?? iic.c.txt
字號:
/*
**********************************************************
s3c2410 gpio linux driver program
**********************************************************
*/
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#ifdef CONFIG_SMP
#define __SMP__
#endif
#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include "iic_drv.h"
#undef DEBUG
//#define DEBUG
// define tracy function
#ifdef DEBUG
#define DPRINTK( x... ) printk("iic_drv:" ##x)
#else
#define DPRINTK( x... )
#endif
#define DEVICE_NAME "iic_drv"
#define EMPLED_MINOR 1
static int iic_drv_major = 0; /* Define major device number -- auto allocate!*/
/*
static ssize_t d11_arm_write(struct file * file, const char * buffer, size_t count, loff_t ppos)
{
copy_from_user(&d11_gpiostatus,buffer,sizeof(d11_gpiostatus));
update_d11_gpio();
DPRINTK("write: d11_gpio=0x%x,count=%d\n",d11_gpiostatus,count);
return sizeof(d11_gpiostatus);
}
*/
#define clrsda GPEDAT &=(~(0x1<<15))
#define setsda GPEDAT |=(0x1<<15)
#define clrscl GPEDAT &= (~(0x1<<14))
#define setscl GPEDAT |= (0x1<<14)
#define setio1 GPECON = (GPECON & (~(0xf<<28))) | (0x1<<28)
#define setio2 GPECON = (GPECON & (~(0xf<<28))) | (0x5<<28)
/*改變sda電平*/
void Change_Sda( int data)
{
if(data==0)
clrsda ; //向sda寄存器寫
else
setsda ; //向sda寄存器寫1
}
/*改變scl電平*/
void Change_Scl( int data)
{
if(data==0)
clrscl ; //向scl寄存器寫0
else
setscl ; //向scl寄存器寫1
}
/*改變數據傳輸方向*/
void Sda_Io( int sda)
{
if(sda==1)
setio1 ; //scl輸出,sda輸入
else
setio2 ; //scl輸出,sda輸出
}
/*延時函數*/
void Delay( long int time)
{
udelay(1 * time);
}
/*讀一個比特數據*/
unsigned int Bit_Read(unsigned int var,int bit)
{
unsigned int value,number;
value=1<<bit; //bit+1位置1
number=(value&var)/value; //number為0/1
return(number);
}
/*寫一個字節數據*/
void Write_Byte(unsigned char data)
{
unsigned int j,k;
Change_Scl(0); //scl為低電平
Sda_Io(0); //sda輸出 scl輸出
for(j=0;j<8;) //寫8位數據
{
Change_Scl(0); //scl為低電平
k=Bit_Read(data,j); //k=0/1=number
Change_Sda(k);
Delay(4);
Change_Scl(1); //scl=1
Delay(2);
j++;
}
}
/*讀一個字節數據*/
unsigned char Read_Byte()
{
unsigned int j;
unsigned char data=0x00,i;
Change_Scl(0); //scl為低電平
Sda_Io(1); //scl輸出 sda輸入
Delay(4);
for(j=0;j<8;)
{
Change_Scl(1); //scl為高電平
i=Bit_Read(GPEDAT,15); //讀sda寄存器的值
data=(data<<1)|i; //左移是因為有八位數據讀入
Delay(2);
Change_Scl(0); //scl為低電平
Delay(4);
j++;
}
return(data); //返回的data為讀入的八位數據
}
/*總線開始信號*/
void Iic_Start()
{
Sda_Io(0); //scl輸出sda 輸入
Change_Sda(1); //sda線為高電平
Change_Scl(1); //scl線為高電平
Delay(4);
Change_Sda(0); //sda線為低電平
Delay(2);
Change_Scl(0); //scl線為低電平
}
/*總線結束信號*/
void Iic_Stop()
{
Sda_Io(0);
Change_Sda(0);
Change_Scl(1);
Delay(4);
Change_Sda(1);
Delay(2);
}
/*接收端返回的確認信號*/
void Ack_In(void)
{
Change_Scl(0); //scl線為低電平
Change_Sda(0);
Delay(4);
Sda_Io(1); //scl輸出 sda輸入
Change_Scl(1); //scl線為高電平
Delay(2);
Change_Scl(0); //線為低電平
}
/*發送端的確認信號*/
void Ack_Out(void)
{
Change_Scl(0); //為低電平
Change_Sda(0); //sda為低電平
Sda_Io(0); //scl輸出sda輸出
Delay(4);
Change_Scl(1);
Delay(2);
Change_Scl(0);
}
/*調用該函數實現向從機寫n字節的數據,slvaddr為從機地址,regaddr為寄存器地址,d為發送的數據數組*/
int Write_Iic(unsigned char slvaddr, unsigned char* pdata, unsigned char size)
{
int i=0;
unsigned char data=0x00,m=0x00,addr=0;
unsigned int j,f,k;
if(size <= 0)
return -1;
addr=((slvaddr<<1) & 0xfe); //將slvaddr的高低位順序換過來
//printk("The slvaddr of Writ_Byte is:%d\n ",addr);
for(i=0;i<8;)
{
j=Bit_Read(addr,i);
data=(data<<1)|j;
i++;
}
addr=data;
//printk("The change slvaddr is :%d\n",addr);
Iic_Start();
Write_Byte(addr);
Ack_In();
for(i = 0; i < size;i++)
{
for(f=0;f<8;) //將pdata[i]的高低位按順序換過來
{
k=Bit_Read(pdata[i],f);
m=(m<<1)|k;
f++ ;
}
pdata[i]=m;
// printk("The pdata[i] is :%d\n",pdata[i]);
m=0;
Write_Byte(pdata[i]);
Ack_In();
}
Iic_Stop();
Delay(100);
return 0;
}
/*調用該函數實現由從機讀n字節的數據(無須提供寄存器地址),slvaddr為從機地址,regaddr為寄存器地址,(*d)為接受數據指針*/
int Read_noaddr_Iic(unsigned char slvaddr, unsigned char* pdata, unsigned char size)
{
int i,l,j;
unsigned char addr=0,data=0x00;
addr=((slvaddr<<1) | 0x01);
for(l=0;l<8;) //將slvaddr的高低位按順序換過來,發送時先發高位
{
j=Bit_Read(addr,l);
data=(data<<1)|j;
l++;
}
addr=data;
//printk("The slvaddr is :%d\n",addr);
Iic_Start();
Write_Byte(addr);
Ack_In();
for(i = 0; i < size; i++)
{
*pdata = Read_Byte();
// printk("read byte is:%d\n",*pdata);
return(*pdata);
pdata++;
if(i == (size - 1))
break;
else
Ack_Out ();
}
Iic_Stop();
Delay(100);
return 0 ;
}
/*調用該函數實現由從機讀n字節的數據(須提供寄存器地址),slvaddr為從機地址*/
int Read_addr_Iic(unsigned char slvaddr, unsigned char* pdata, unsigned char size)
{
int i;
unsigned char addr=0,data=0x00,l,j;
//printk("slvaddr is :0x%x\n",slvaddr);
addr=((slvaddr<<1)&0xfe); //change send order
for(l=0;l<8;)
{
j=Bit_Read(addr,l);
data=(data<<1)|j;
l++;
}
addr=data;
//printk("The first time send slvaddr is :0x%x\n",addr);
Iic_Start();
Write_Byte(addr);
Ack_In();
//printk("The send regaddr is :0x%x\n",pdata[0]);
data=0;
for(l=0;l<8;)
{
j=Bit_Read(pdata[0],l);
data=(data<<1)|j;
l++;
}
pdata[0]=data;
//printk("The send regaddr is:%d\n",pdata[0]);
Write_Byte(pdata[0]);
Ack_In();
Iic_Start();
addr=addr|0x80;
//printk("The slvaddr is :%d\n",slvaddr);
/*addr=((slvaddr<<1)|0x01);
data=0x00; //change send order
for(l=0;l<8;)
{
j=Bit_Read(addr,l);
data=(data<<1)|j;
l++;
}
slvaddr=data;
*/
Write_Byte(addr);
//printk("The second time send slvaddr is:%d\n",addr);
Ack_In();
pdata++;
//printk("*pdata is :%d\n",*pdata);
for(i = 0; i < size; i++)
{
*pdata = Read_Byte();
// printk("The read_byte is:0x%x\n",*pdata);
return(*pdata);
pdata++;
if(i == (size - 1))
break;
else
Ack_Out ();
}
Iic_Stop();
Delay(100);
return 0;
}
/*********************************************************/
static int iic_drv_open(struct inode * inode, struct file * filp)
{
MOD_INC_USE_COUNT;
DPRINTK("open\n");
return 0;
}
static int iic_drv_release(struct inode * inode, struct file * filp)
{
MOD_DEC_USE_COUNT;
DPRINTK("releas\n");
return 0;
}
int iic_drv_ioctl(struct inode * inode, struct file * filp, unsigned int command, unsigned long arg)
{
int err = 0;
struct iic_drv_tag iic_data;
switch(command)
{
case READ_NADD_IIC:
{
copy_from_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(struct iic_drv_tag));
Read_noaddr_Iic(iic_data.addr, iic_data.pdata, iic_data.size);
copy_to_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(iic_data));
copy_to_user(iic_data.pdata, ((struct iic_drv_tag *)(arg))->pdata, iic_data.size);
break;
}
case READ_ADD_IIC:
{
copy_from_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(struct iic_drv_tag));
Read_addr_Iic(iic_data.addr, iic_data.pdata, iic_data.size);
copy_to_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(iic_data));
//copy_to_user(iic_data.pdata, ((struct iic_drv_tag *)(arg))->pdata, iic_data.size);
break;
}
case WRITE_IIC:
{
copy_from_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(struct iic_drv_tag));
copy_from_user(iic_data.pdata, ((struct iic_drv_tag *)(arg))->pdata, iic_data.size);
Write_Iic(iic_data.addr, iic_data.pdata, iic_data.size);
}
default:
return -ENOTTY;
break;
}
return err;
}
static struct file_operations iic_drv_fops = {
owner: THIS_MODULE,
ioctl: iic_drv_ioctl,
open: iic_drv_open,
release: iic_drv_release,
};
#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_iic_drv_dir, devfs_iic_drv;
#endif
static int __init iic_drv_init(void)
{
int ret;
ret = register_chrdev(0, DEVICE_NAME, &iic_drv_fops);
if(ret < 0)
{
printk("iic_drv:Cant't get major number!\n");
return ret;
}
iic_drv_major = ret;
#ifdef CONFIG_DEVFS_FS
devfs_iic_drv_dir = devfs_mk_dir(NULL, "iic_drv", NULL);
if(!devfs_iic_drv_dir) return -EBUSY; /* ERROR */
devfs_iic_drv = devfs_register(devfs_iic_drv_dir, "0",
DEVFS_FL_DEFAULT, iic_drv_major, EMPLED_MINOR,
S_IFCHR | S_IRUSR | S_IWUSR, &iic_drv_fops, NULL);
#endif
printk("iic_drv:Initialized!\n");
printk("iic_drv:Major device no. -> %d\n",iic_drv_major);
return 0;
}
static void __exit iic_drv_exit(void)
{
#ifdef CONFIG_DEVFS_FS
devfs_unregister(devfs_iic_drv);
devfs_unregister(devfs_iic_drv_dir);
#endif
printk("iic_drv:release!\n");
unregister_chrdev(iic_drv_major, DEVICE_NAME);
}
module_init(iic_drv_init);
module_exit(iic_drv_exit);
MODULE_LICENSE("GPL");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -