linux下IIC驱动程序

IIC总线驱动共3个部分 :IIC核心,IIC总线驱动,IIC设备驱动。
1> IIC核心:提供总线驱动和设备驱动的注册和注销方法 
2> IIC总线驱动:是对适配器端的实现 
3> IIC设备驱动:是对设备端的实现
框架图:
IIC总线驱动用于识别IIC设备,提供读写函数,提供如何收发数据,但是不知道数据的具体含义。在内核源代码的drivers/i2c/busses/目录中有很多IIC总线驱动,例如S3C2440,对应i2c-s3c2410.c。
i2c_add_adapter 作用
<a> 将adapter放入链表
<b>调用driver中的attach_adapter函数
<c>在attach_adapte函数中调用i2c_probe函数
<d>用adapter的master_xfer函数发信号,确定有没有该设备,如果有,调用i2c_probe中的定义的发现这个设备后要调用的函数。
i2c设备驱动程序功能(以drivers/i2c/chip/eeprom.c为例)。
<a>分配构造一个i2c_driver
static struct i2c_driver eeprom_driver = {
     .driver = {
          .name = "eeprom",
     },  
     .id  = I2C_DRIVERID_EEPROM,  
     .attach_adapter = eeprom_attach_adapter,  
     .detach_client = eeprom_detach_client, 
};
<b>使用i2c_add_driver函数将i2c_driver放入链表
<c>从adapter链表取出适配器调用driver的attach_adapter函数, 在attach_adapter中调用i2c_probe函数,用adapter的master_xfer发信号,确定有没有该设备,如果有,调用i2c_probe中定义的发现这个设备后要调用的函数。
代码清单如下:
1.定义变量并设置地址
static unsigned short ignore[] = {I2C_CLIENT_END};
static unsigned short normal_addr = {0x50, I2C_CLIENT_END};
static unsigned short force_addr[] = {ANY_I2C_BUS, 0x60, I2C_CLIENT_END};
static unsigned short *forces[] = {force_addr, NULL};
 
static struct i2c_client_address_data addr_data = {
     .normal_i2c = normal_addr,
     .probe = ignore,
     .ignore = ignore,
     //.forces = forces,
};
static struct i2c_driver at24cxx_driver;
static int major;
static struct class *cls;
struct i2c_client *at24cxx_client;
2.入口函数和出口函数
static int at24cxx_init(void)
{
    i2c_add_driver(&at24cxx_driver);
    return 0;
}
 
static void at24cxx_exit(void)
{
    i2c_del_driver(&at24cxx_driver);
}
3.分配构造i2c_driver结构体
static struct i2c_driver at24cxx_driver = {
    .driver = {
         .name = "at24cxx",
     },
    .attach_adapter = at24cxx_attach,
    .detach_adapter = at24cxx_detach,
};
static int at24cxx_attach(struct i2c_adapter *adapter)
{
    return i2c_probe(adapter, &addr_data, at24cxx_detect);
}
static int at24cxx_detect(struct i2c_adapter *adapter, int address, int kind)
{
    at24cxx_client = kzmalloc(sizeof(struct i2c_client), GFP_KERNEL);
    at24cxx_client->addr = address;
    at24cxx_client->adapter = adapter;
    at24cxx_client->driver = &at24cxx_driver;
    strcpy(at24cxx_driver->name, "at24cxx");
    i2c_attach_client(at24cxx_client);
    major = register_chrdev(0, "at24cxx", &at24cxx_fops);
    cls = class_create(THIS_MODULE, "at24cxx");
    device_create(cls, NULL, MKDEV(major, 0), NULL, "at24cxx");
    return 0;
}
static int at24cxx_detach(struct i2c_client *client)
{
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    unregister_chrdev(major, "at24cxx");
    i2c_detach_client(client);
    kfree(i2c_get_clientdata(client));
}
4.构造并初始化file_operations结构体
static struct file_operations at24cxx_fops = {
    .owner = THIS_MODULE,
    .read = at24cxx_read,
    .write = at24cxx_write,
};
static ssize_t at24cxx_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    unsigned char address;
    unsigned char data;
    struct i2c_msg msg[2];
    int ret;
 
    if (size != 1)
         return -EINVAL;
    copy_from_user(&address, buf, 1);
    msg[0].addr = at24cxx_client->addr;
    msg[0].buf = &address;
    msg[0].len = 1;
    msg[0].flags = 0;
    
    msg[1].addr = at24cxx_client->addr;
    msg[1].buf = &data;
    msg[1].len = 1;
    msg[1].flags = I2C_M_RD;
 
    ret = i2c_transfer(at24cxx_client->adapter, msg, 2);
    if (ret == 2) {
         copy_to_user(buf, &data, 1);
         return 1;
     } else {
         return -EIO;
     }
}
static ssize_t at24cxx_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    unsigned char val[2];
    struct i2c_msg msg[1];
    int ret;
 
    if (size != 2) {
         return -EINVAL;
     }
    copy_from_user(val, buf, 2);
    msg[0].addr = at24cxx_client->addr;
    msg[0].buf = val;
    msg[0].len = 2;
    msg[0].flags = 0;
    
    ret = i2c_transfer(at24cxx_client->adapter, msg, 1);
    if (ret == 1) {
        return 2;
     } else {
         return -EIO;
     }
}
posted @ 2014-07-03 12:45  zpehome  阅读(627)  评论(0编辑  收藏  举报