📄 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 + -