#include <linux/mm.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/rtc.h> /* get the user-level API */
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <mach/at91_pio.h>
#include <mach/gpio.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/version.h>
/*通过测试也是可以的*/
#define DEV_NAME "iic" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
//#define DEV_MAJOR 231 /* 主设备号 */
#define DEV_MAJOR 0
#define DEV_MINOR 0
///////
#define I2C_SCL_H (at91_set_gpio_value(AT91_PIN_PA24, 1))
#define I2C_SCL_Low (at91_set_gpio_value(AT91_PIN_PA24, 0))
#define I2C_SDA_OUT (at91_set_gpio_output(AT91_PIN_PA23,1)) /* SDA OUT*/
#define I2C_SDA_IN (at91_set_gpio_input(AT91_PIN_PA23, 1)) /* SDA IN*/
#define I2C_SDA_Low (at91_set_gpio_value(AT91_PIN_PA23, 0)) /* SDA Low*/
#define I2C_SDA_H (at91_set_gpio_value(AT91_PIN_PA23, 1)) /* SDA H*/
#define I2C_SDA_Value (at91_get_gpio_value(AT91_PIN_PA23)) /* SDA H*/
//if(at91_get_gpio_value(AT91_PIN_PA0)==1)//读I/O就可以了 真他妈的搞不懂
///////
//#define SPI_READ_MODE _IOR('D', 1, long)
//#define SPI_WRITE_MODE _IOW('D', 1, long)
#define TWD_CLOCK_H _IOW('D', 2, int)
#define TWD_CLOCK_L _IOW('D', 3, int)
//#define SPI_READ_DATA _IOR('D', 4, long)
//#define SPI_WRITE_DATA _IOW('D', 4, long)
////////
struct i2c_dev
{
dev_t devno; //变量是设备号
int major;
int minor;
struct class_device *class_dev;
struct class *class;
struct cdev cdev;
};
struct i2c_dev *at91_i2c;
static void __iomem *pio_base;
/* 应用程序对设备文件/dev/led执行open(...)时, * 就会调用led_open函数 */
////////delay()
/**********************************************************************
**函数原型: i2c_delay(int num)
**入口参数: num
**出口参数: 无
**返 回 值: 无
**说 明: I2C的延迟函数
************************************************************************/
void i2c_delay(int num)
{
int i;
while(num--)
{
for(i = 0;i<100;i++);
}
}
///*********************************************************************
///**函数原型: void I2CStart()
///**入口参数: 无
///**出口参数: 无
///**返 回 值: 无
///**说 明: 启动I2C总线
///**********************************************************************
void I2cStart()
{
I2C_SDA_OUT; //SDA输出
I2C_SDA_H; //SDA=1;
i2c_delay(50); //延时>1us
I2C_SCL_H; //SCL=1;
i2c_delay(250); //延时>4.7us
I2C_SDA_Low; //SDA=0
i2c_delay(250); //延时>4us
I2C_SCL_Low ; //SCL=0;
i2c_delay(50); //延时>1us
}
///**********************************************************************
///**函数原型: void I2cSendByte(int data)
///**入口参数: data
///**出口参数: 无
///**返 回 值: 无
///**说 明: 向I2C写入数据
///************************************************************************
void I2cSendByte(unsigned char data)
{
unsigned char flag, sz; //定义局部寄存器
I2C_SDA_OUT; //SDA输出
for(flag=0x0080; flag!=0x00;flag=flag/2)
{
sz=data&flag;
if(sz==0)
{
I2C_SDA_Low; //SDA=0
i2c_delay(50); //1us
I2C_SCL_H; //SCL=1;
i2c_delay(250); //5us
I2C_SCL_Low ; //SCL=0;
}
else
{
I2C_SDA_H; //SDA=1
i2c_delay(50); //1us
I2C_SCL_H; //SCL=1;
i2c_delay(250); //5us
I2C_SCL_Low ; //SCL=0;
}
}
}
/**********************************************************************
**函数原型: I2cRecak()
**入口参数: 无
**出口参数: 无
**返 回 值: 应答值
**说 明: 检查应答位子程序(返回0表示有应答)
************************************************************************/
int I2cRecak()
{
unsigned char Ack=1;
unsigned char m=1;
I2C_SDA_OUT; //SDA输出
I2C_SDA_H; //SDA=1
i2c_delay(50); //2us
I2C_SDA_IN; //SDA输入
I2C_SCL_H; //SCL=1;
i2c_delay(50); //3us
if(I2C_SDA_Value == 1) //表示无应答
{
i2c_delay(50);
I2C_SCL_Low ; //SCL=0;
i2c_delay(50); //1us......
}
else
{
Ack=0;
i2c_delay(50);
I2C_SCL_Low ; //SCL=0;
i2c_delay(50); //1us......
}
return(Ack);
}
///**********************************************************************
///**函数原型: void I2cRecByte()
///**入口参数: 无
///**出口参数: 无
///**返 回 值: 数据
///**说 明: 从I2C中读取数据
///************************************************************************/
int I2cReadByte()
{
unsigned char M=0;
int flag;
I2C_SDA_OUT; //SDA输出
I2C_SDA_H; //SDA=1
I2C_SDA_IN; //SDA输入
for(flag=7;flag>=0;flag--)
{
I2C_SCL_H; //SCL=1
i2c_delay(100); //2us...
M=M|(I2C_SDA_Value << flag); //保留读取的那位
i2c_delay(250); //5us...
I2C_SCL_Low ; //SCL=0
i2c_delay(100); //3us
}
return(M);
}
///**********************************************************************
///**函数原型: void I2cAck()
///**入口参数: 无
///**出口参数: 无
///**返 回 值: 无
///**说 明: 对I2C总线中产生应答
///***********************************************************************
void I2cAck( )
{
I2C_SDA_OUT; //SDA输出
I2C_SDA_Low; //SDA=0
i2c_delay(50); //2us.....
I2C_SCL_H; //SCL=1
i2c_delay(250); //5us......
I2C_SCL_Low ; //SCL=0
i2c_delay(50); //2us......
}
/**********************************************************************
**函数原型: void I2cNoAck()
**入口参数: 无
**出口参数: 无
**返 回 值: 无
**说 明:不对I2C总线中产生应答
************************************************************************/
void I2cNoAck()
{
I2C_SDA_OUT; //SDA输出
I2C_SDA_H; //SDA=1
i2c_delay(50); //2us.....
I2C_SCL_H; //SCL=1;
i2c_delay(250); //5us....
I2C_SCL_Low ; //SCL=0;
i2c_delay(50); //2us......
}
/**********************************************************************
**函数原型: void I2CStop()
**入口参数: 无
**出口参数: 无
**返 回 值: 无
**说 明: 停止IC总线
************************************************************************/
void I2cStop()
{
I2C_SDA_OUT; //SDA输出
I2C_SDA_Low; //SDA=0
i2c_delay(50); //2us........
I2C_SCL_H; //SCL=1;
i2c_delay(250); //5us........//延时
I2C_SDA_H; //SDA=1
i2c_delay(250); //5us......
}
static int i2c_open(struct inode *inode,
struct file *file)
{
/*pio_base = ioremap(0xFFFFF400,512); //PIOA开始的地址 以及空间512字节
writel(0x01800000, pio_base + PIO_PER); //PIO的使能寄存器 表示向该寄存器写入0x00000040的数据
writel(0x01800000, pio_base + PIO_PUER); //pull—up 使能寄存器 表示向该寄存器写入0x00000040的数据
writel(0x01000000, pio_base + PIO_ODSR); //输出数据状态寄存器 表示向该寄存器写入0x00000040的数据
writel(0x01000000, pio_base + PIO_OER); //输出使能寄存器 表示向该寄存器写入0x00000040的数据
*/
at91_set_A_periph(AT91_PIN_PA23, 1); //TWD
at91_set_A_periph(AT91_PIN_PA24, 1); //TWD CLOCK
at91_set_gpio_output(AT91_PIN_PA24, 1); //I/O 口设置 clock
at91_set_deglitch(AT91_PIN_PA24, 1);
printk(KERN_INFO "::open_iic\n");
return 0;
}
static int i2c_ioctl( struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
{
//long mode=0x01000000;
switch(cmd){
case TWD_CLOCK_H:
I2C_SCL_H;
printk(KERN_INFO "::I2C_CLK_H\n");
break;
case TWD_CLOCK_L:
I2C_SCL_Low;
printk(KERN_INFO "::I2C_CLK_L\n");
break;
default: return -EINVAL;
break;
}
return 0;
}
/**********************************************************************
**函数原型: i2c_read(struct file *file, const char __user *buf, size_t count)
**入口参数:
**出口参数: 无
**返 回 值: 无
**说 明: 通用的读24LC256的子程序((指针是8字节的读操作已经成功)
************************************************************************/
static int i2c_read(struct file *file, const char __user *buf, size_t count)
{
unsigned char dat,i;
unsigned char *buffer;
unsigned char missing;
unsigned char counter=count;
ssize_t status = 0;
buffer=kmalloc(count * sizeof(char),GFP_KERNEL);
LABLE: I2cStart();
dat=0xA2; //设置I2c的开始状态
I2cSendByte(dat); //送出器件地址字0xA3
printk("read_dat0=0x%02X\n",dat);
dat=I2cRecak(); //检查应答位
if(dat==0)
{
dat=0x00; //dat=24LC256的块内地址的高字节 (因为每次只能送8位)
printk("read_dat1=0x%02X\n",dat);
I2cSendByte(dat); //送出24LC256的块内地址的高字节
dat=I2cRecak(); //检查应答位
if(dat==0)
{
I2cStart();
dat=0xA3;
I2cSendByte(dat); //送出24LC256的读指令
//printk("read_dat2=0x%02X\n",dat);
dat=I2cRecak(); //检查应答位
if(dat==1)
{
goto LABLE;//无则重新开始
printk("read FUCK\n");
}
else
{
//printk("read FUCK_in\n");
//printk("read_count2=0x%02X\n",counter);
for(;counter!=1;counter--)
{
dat=I2cReadByte(); //读取一个字节的数据
*(buffer++)=dat; //把读取的数据存入数组
printk("read_dat3=0x%02X\n",*(buffer-1));
I2cAck(); //产生应答信号
}
//printk("read_count4=0x%02X\n",counter);
dat=I2cReadByte(); //接收最后一个数据
I2cNoAck(); //发出应答
*buffer=dat; //把读取的数据放入数组
//printk("read_dat5=0x%02X\n",*(buffer));
}
}
}
// printk("read_count=0x%02X\n",count);
buffer=buffer-(count-1);
missing=copy_to_user(buf,buffer, count);//boy
if(missing != 0)
{
kfree(buffer);
status = -EFAULT;
}
for(i=0;i<4;i++)printk("read_dat6=0x%02X\n",*(buf+i));
printk("read FUCK_out\n");
I2cStop();
return 0;
}
/********************************************************
**函数原型: void Write(uint8 * array, uint16 address,uint16 control,uint16 n)
**入参数: array addres control n
**出口参数: 无
**返 回 值: 无
**说 明? 通用的写24LC256的子程序(指针是8字节的写操作已经成功)
************************************************************************/
/////通用的读写24LC256的程序,ARRAY=缓冲区首地址 address=块内地址,
/////control=控制字节
/////n=读写的字节数adders=N*64+M
/////N=第几页,
/////M=第几个字节
static int i2c_write(struct file *file, const char __user *buf, size_t count)
{
unsigned char dat,i;
unsigned char missing;
unsigned char *buff;
unsigned char counter=count-2;
ssize_t status = 0;
printk(KERN_INFO "i2c_write\n");
buff = kmalloc(count*sizeof(char), GFP_KERNEL);
missing=copy_from_user(buff,buf, count);
if(missing != 0)
{
kfree(buff);
status = -EFAULT;
}
//LCM_SPA_Low; //WP=0;设置写允许
LOOP: I2cStart(); //设置I2c的开始状态
I2cSendByte(*buff); //送出器件地址字0xA2
printk("buff=0x%02X\n",*buff);
dat=I2cRecak(); //检查应答位
if(dat==0)
{
dat=*(buff+1); //0x00;
printk("write_dat=0x%02X\n",dat);
I2cSendByte(dat); //送出24LC256的块内地址的高字节
dat=I2cRecak(); //检查应答位
if(dat==0)
{
// dat=*(buff+2); //送出24LC256的低地址
//I2cSendByte(dat); //送出24LC256的低地址
// dat=I2cRecak(); //检查应答位
// if(dat==0) //如果有应答位
// {
for(i=0;i<counter;i++)
{
//buff++;
I2cSendByte(*(buff+2+i)); //写出一个字节的数据0x23
printk("write_dat1=0x%02X\n",*(buff+2+i));
dat=I2cRecak(); //检查应答位 dat==0,表明写成功
if(dat==1) goto LOOP; //如果无应答位,写操作失败,重新开始
}
// }
}
}
I2cStop(); //返回一个状态字,以确操作是否成功
//LCM_SPA_H; //WP=1;写操作完成,设置写保护
return 0;
}
static int i2c_close(
struct inode *inode,
struct file *file)
{
/*
int i;
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
{
free_irq(button_irqs[i].irq, NULL);
}
*/
return 0;
}
static struct file_operations i2c_fops =
{
.owner = THIS_MODULE,
.open = i2c_open,
.ioctl = i2c_ioctl,
.read = i2c_read,
.write = i2c_write,
.release = i2c_close,
};
static int i2c_init(void)
{
int result,err;
printk(DEV_NAME "::i2c_init\n");
at91_i2c = kmalloc(sizeof(struct i2c_dev), GFP_KERNEL);
if( DEV_MAJOR != 0){ /*静态申请设置号*/
at91_i2c->devno = MKDEV(DEV_MAJOR,DEV_MINOR);
result = register_chrdev_region(at91_i2c->devno,1,DEV_NAME);
at91_i2c->major = DEV_MAJOR;
at91_i2c->minor = DEV_MINOR;
}else {
result = alloc_chrdev_region(&at91_i2c->devno,DEV_MINOR,1,DEV_NAME); /*动态申请设置号*/
at91_i2c->major = MAJOR(at91_i2c->devno);
at91_i2c->minor = DEV_MINOR;
}
if(result < 0){
printk(KERN_ERR"i2c::can't get major\n");
kfree(at91_i2c);
return result;
}
cdev_init(&at91_i2c->cdev,&i2c_fops); /*设置注册 初始化设备*/
at91_i2c->cdev.owner = THIS_MODULE;
at91_i2c->cdev.ops = &i2c_fops;
err = cdev_add(&at91_i2c->cdev,at91_i2c->devno,1);
if(err){
printk(KERN_INFO"::error %d adding led\n",err);
}
at91_i2c->class = class_create(THIS_MODULE, DEV_NAME); /*创建一个类*/
if( IS_ERR(at91_i2c->class) ){ /*IS_ERR() PTR_ERR()等函数是专门用来处理CLASS之类的返回错误代码 */
return PTR_ERR(at91_i2c->class);
}
at91_i2c->class_dev = device_create(at91_i2c->class, NULL,/*创建在/dev目录下创建相应的设备节点。这样,加载模块的时候,*/
/* 用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。*/
// 第一个参数指定所要创建的设备所从属的类,第二个参数是这个设备的父设备,如果没有就指定为NULL,第三个参数是设备号,第四个参数是设备名称,第五个参数是从设备号
at91_i2c->devno,
NULL,DEV_NAME);
if( IS_ERR(at91_i2c->class_dev) ){
return PTR_ERR(at91_i2c->class_dev);
}
return 0;
}
static void __exit i2c_exit(void)
{
device_destroy(at91_i2c->class, at91_i2c->devno);
class_destroy(at91_i2c->class); ////还定义了class_destroy(…)函数,用于在模块卸载时删除类。
cdev_del(&at91_i2c->cdev);
unregister_chrdev_region(at91_i2c->devno,1);
kfree(at91_i2c);
printk(DEV_NAME ":: led_exit\n");
}
module_init(i2c_init);
module_exit(i2c_exit);
MODULE_AUTHOR("zhd wangyulu");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("at91sam9g20 led");
/*****Kconfig*******************************
config baite_LED
tristate "baite_led"
default m
******************************************/
/****Makeflie********************************
obj-$(CONFIG_baite_LED) +=baite_led.o
******************************************/
以上是我的AT91的iic的软件驱动,其实只要稍加改动就可以应用在其他的上面。
下面是我的应用代码,就是用来测试该驱动的,以上都是通过我的测试,可以用的
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
//IIC Define the command constant
//#define SPI_READ_MODE _IOR('D', 1, long)
//#define SPI_WRITE_MODE _IOW('D', 1, long)
#define TWD_CLOCK_H _IOW('D', 2, int)
#define TWD_CLOCK_L _IOW('D', 3, int)
//#define SPI_READ_DATA _IOR('D', 4, long)
//#define SPI_WRITE_DATA _IOW('D', 4, long)
unsigned char Tx_buffer[6]={0xA2,0x00,0x89,0x12,0x23,0x34};
unsigned char Rx_buffer[4]={0};
/***********主程序***********/
int main(int argc, char **argv)
{
int fd,ret,i;
fd=open("/dev/iic",O_RDWR);
if(fd<0)
{
perror("open error");
}
else printf("open iic success\n");
//while(1)
//{
if(write(fd,Tx_buffer,sizeof(Tx_buffer)/sizeof(Tx_buffer[0]))<0) //注意fd?
{
perror("read wrong::");
exit(1);
}
if(read(fd,Rx_buffer,sizeof(Rx_buffer)/sizeof(Rx_buffer[0]))<0) //注意fd?
{
perror("read wrong::");
exit(1);
}
printf("Rx_buffer=::0x%02X\n",Rx_buffer[0]);
printf("Rx_buffer=::0x%02X\n",Rx_buffer[1]);
printf("Rx_buffer=::0x%02X\n",Rx_buffer[2]);
printf("Rx_buffer=::0x%02X\n",Rx_buffer[3]);
//}
//sleep(1);
close(fd);
return 0;
}
希望有帮助!