Linux I2C驱动分析与实现

====本文系本站原创,欢迎转载! 转载请注明出处:http://blog.csdn.net/yyplc====

本文基于内核版本linux-2.6.30.4分析.

Linux中i2c子系统框图如下:

Linux I2C驱动分析与实现_第1张图片

•客户驱动

即I2C设备驱动,每个客户驱动可以为一个或多个I2C设备服务,并向用户空间提供相应的访问接口函数。

客户驱动需要向总线注册并通过i2c-core提供的接口与I2C设备通信。与客户程序相关的数据结构主要有struct i2c_driver和struct i2c_client

添加客户驱动:static inline int i2c_add_driver(struct i2c_driver *driver)

删除客户驱动:extern void i2c_del_driver(struct i2c_driver *);   

I2C-core核心

I2c-core核心是I2C总线的核心,承上启下,其实现与平台无关。I2C总线的初始化、注册和适配器添加和注销等相关工作均在I2C核心代码中完成,

除此之外,还向上层客户驱动提供相应的API接口函数,使得客户驱动独立于适配器驱动而工作。

• 适配器驱动

负责对I2C控制器的驱动实现,一个总线对应一个适配器。I2C总线上对I2C slave设备的具体

操作是在适配器驱动中完成的。适配器驱动作为platform_driver而注册,在probe()到驱动设

备后,向总线声明并被添加:i2c_add_numbered_adapter(&i2c->adap);

I2c-dev驱动是系统自带的一个通用客户驱动,它不是针对某一个I2C设备(即没有自己驱动设备id-table),它可以使得用户空间的程序通过i2c-tools访问总线上的i2c/SMBUS设备。

I2C子系统主要数据结构

[cpp]  view plain copy
  1. struct i2c_msg;             //I2C消息数据结构  
  2.   
  3. struct i2c_algorithm;       //算法驱动数据结构  
  4.   
  5. struct i2c_adapter;         //I2C适配器数据结构  
  6.   
  7. struct i2c_client;          //I2C客户数据结构  
  8.   
  9. struct i2c_driver;          //I2C设备驱动数据结构  
  10.   
  11. struct i2c_board_info;      //描述板载I2C设备的信息    
  12.    

以上数据结构在include/linux/i2c.h中定义,下面我们结合源码分析一下这些数据结构

I2C算法结构:

[cpp]  view plain copy
  1. struct i2c_algorithm {  
  2.   
  3.    /* If an adapter algorithm can't do I2C-level access, set master_xfer 
  4.  
  5.       to NULL. If an adapter algorithm can do SMBus access, set 
  6.  
  7.       smbus_xfer. If set to NULL, the SMBus protocol is simulated 
  8.  
  9.       using common I2C messages */  
  10.   
  11.    /* master_xfer should return the number of messages successfully 
  12.  
  13.       processed, or a negative value on error */  
  14.   
  15.    int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,  
  16.   
  17.             int num);  
  18.   
  19.    int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,  
  20.   
  21.             unsigned short flags, char read_write,  
  22.   
  23.             u8 command, int size, union i2c_smbus_data *data);  
  24.   
  25.    
  26.   
  27.    /* To determine what the adapter supports */  
  28.   
  29.    u32 (*functionality) (struct i2c_adapter *);  
  30.   
  31. };  

例如:

s3c2440 i2c 适配器驱动是这样实现这个算法结构体:

[cpp]  view plain copy
  1. static const struct i2c_algorithm s3c24xx_i2c_algorithm = {  
  2.   
  3.      .master_xfer            = s3c24xx_i2c_xfer,  
  4.   
  5.      .functionality          = s3c24xx_i2c_func,  
  6.   
  7. };  

s3c24xx_i2c_xfer 是适配器的对I2C设备的读写操作函数

s3c24xx_i2c_func函数决定了该适配器向i2c-core核心支持哪些API函数

I2c_adapter结构标识一个物理I2C总线(适配器),总线通过

算法结构访问到适配器。

[cpp]  view plain copy
  1. struct i2c_adapter {  
  2.   
  3.     struct module *owner;  
  4.   
  5.     unsigned int id;  
  6.   
  7.     unsigned int class;             /* classes to allow probing for */  
  8.   
  9.     const struct i2c_algorithm *algo; /* the algorithm to access the bus */  
  10.   
  11.     void *algo_data;  
  12.   
  13.    
  14.   
  15.     /* --- administration stuff. */  
  16.   
  17.     int (*client_register)(struct i2c_client *) __deprecated;  
  18.   
  19.     int (*client_unregister)(struct i2c_client *) __deprecated;  
  20.   
  21.    
  22.   
  23.     /* data fields that are valid for all devices  */  
  24.   
  25.     u8 level;                /* nesting level for lockdep */  
  26.   
  27.     struct mutex bus_lock;  
  28.   
  29.     struct mutex clist_lock;  
  30.   
  31.    
  32.   
  33.     int timeout;            /* in jiffies */  
  34.   
  35.     int retries;  
  36.   
  37.     struct device dev;      /* the adapter device */  
  38.   
  39.    
  40.   
  41.     int nr;  
  42.   
  43.     struct list_head clients;     /* DEPRECATED */  
  44.   
  45.     char name[48];  
  46.   
  47.     struct completion dev_released;  
  48.   
  49. };  

I2c_msg是I2C消息,I2C通信是以i2c_msg为单位的。

[cpp]  view plain copy
  1. struct i2c_msg {  
  2.   
  3.    __u16 addr;     /* slave address            */  
  4.   
  5.    __u16 flags;  
  6.   
  7. #define I2C_M_TEN      0x0010   /* this is a ten bit chip address */  
  8.   
  9. #define I2C_M_RD       0x0001   /* read data, from slave to master */  
  10.   
  11. #define I2C_M_NOSTART       0x4000   /* if I2C_FUNC_PROTOCOL_MANGLING */  
  12.   
  13. #define I2C_M_REV_DIR_ADDR  0x2000   /* if I2C_FUNC_PROTOCOL_MANGLING */  
  14.   
  15. #define I2C_M_IGNORE_NAK    0x1000   /* if I2C_FUNC_PROTOCOL_MANGLING */  
  16.   
  17. #define I2C_M_NO_RD_ACK 0x0800   /* if I2C_FUNC_PROTOCOL_MANGLING */  
  18.   
  19. #define I2C_M_RECV_LEN 0x0400   /* length will be first received byte */  
  20.   
  21.    __u16 len;      /* msg length               */  
  22.   
  23.    __u8 *buf;      /* pointer to msg data           */  
  24.   
  25. };  

I2c_client描述了一个i2c设备。

[cpp]  view plain copy
  1. struct i2c_client {  
  2.   
  3.      unsigned short flags;        /* div., see below         */  
  4.   
  5.      unsigned short addr;        /* chip address - NOTE: 7bit */  
  6.   
  7.                             /* addresses are stored in the      */  
  8.   
  9.                             /* _LOWER_ 7 bits        */  
  10.   
  11.      char name[I2C_NAME_SIZE];  
  12.   
  13.      struct i2c_adapter *adapter;    /* the adapter we sit on       */  
  14.   
  15.      struct i2c_driver *driver;  /* and our access routines    */  
  16.   
  17.      struct device dev;            /* the device structure          */  
  18.   
  19.      int irq;                     /* irq issued by device          */  
  20.   
  21.      struct list_head list;          /* DEPRECATED */  
  22.   
  23.      struct list_head detected;  
  24.   
  25.      struct completion released;  
  26.   
  27. };  

I2c_driver描述了I2C设备的驱动。

[cpp]  view plain copy
  1. struct i2c_driver {  
  2.   
  3.       int id;  
  4.   
  5.       unsigned int class;  
  6.   
  7.    
  8.   
  9.       /* Notifies the driver that a new bus has appeared. This routine 
  10.  
  11.        * can be used by the driver to test if the bus meets its conditions 
  12.  
  13.        * & seek for the presence of the chip(s) it supports. If found, it 
  14.  
  15.        * registers the client(s) that are on the bus to the i2c admin. via 
  16.  
  17.        * i2c_attach_client.  (LEGACY I2C DRIVERS ONLY) 
  18.  
  19.        */  
  20.   
  21.       int (*attach_adapter)(struct i2c_adapter *);  
  22.   
  23.       int (*detach_adapter)(struct i2c_adapter *);  
  24.   
  25.    
  26.   
  27.       /* tells the driver that a client is about to be deleted & gives it 
  28.  
  29.        * the chance to remove its private data. Also, if the client struct 
  30.  
  31.        * has been dynamically allocated by the driver in the function above, 
  32.  
  33.        * it must be freed here.  (LEGACY I2C DRIVERS ONLY) 
  34.  
  35.        */  
  36.   
  37.       int (*detach_client)(struct i2c_client *) __deprecated;  
  38.   
  39.       。。。  
  40.   
  41. }  

I2C核心提供的API函数

[cpp]  view plain copy
  1. •      extern int i2c_master_send(struct i2c_client *client, const char *buf,  
  2.   
  3. •                    int count);  
  4.   
  5. •      extern int i2c_master_recv(struct i2c_client *client, char *buf, int count);  
  6.   
  7.    
  8.   
  9. <span style="color:#ff6666;">•      extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,  
  10.   
  11. •                 int num);  
  12. </span>  
  13. •      extern s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,  
  14.   
  15. •                   unsigned short flags, char read_write, u8 command,  
  16.   
  17. •                   int size, union i2c_smbus_data *data);  
  18.   
  19. •      extern s32 i2c_smbus_read_byte(struct i2c_client *client);  
  20.   
  21. •      extern s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value);  
  22.   
  23. •      extern s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command);  
  24.   
  25. •      extern s32 i2c_smbus_write_byte_data(struct i2c_client *client,  
  26.   
  27. •                           u8 command, u8 value);  
  28.   
  29. •      extern s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command);  
  30.   
  31. •      extern s32 i2c_smbus_write_word_data(struct i2c_client *client,  
  32.   
  33. •                           u8 command, u16 value);  

其中: i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 是实现其他函数的基础,换句话说,其它函数均是通过调用该函数来实现的


编写客户驱动的方法

在内核中有两种方式的i2c客户驱动的编写方法,一种叫legacy传统方式,另一种是newstyle方式. 前

一种legacy是一种旧式的方法,在2.6内核以后的标准驱动模型编写中逐渐被newstyle方式取代。本文编程实例是基于newstyle方式的来实现at24c02的驱

动。

客户驱动程序开发的一般步骤

(1)注册板载i2c设备信息

 

(2)定义i2c驱动设备id

 

(3)定义i2c_driver结构并完成其相应函数

 

(4)模块初始化时添加/撤销时删除i2c_driver

 

(5)/dev  entry 访问方法 /sysfs访问方法

 

客户设备驱动开发实例

内核为linux-2.6.30.4

基于arm9 S3c2440平台

开发一个at24c02 eeprom的客户驱动

开发一个应用程序访问I2C设备

-----------------------------------------------------------------

根据开发客户驱动程序步骤实现对i2c设备at24c02的读写操作。

(分析at24c02 datasheet)

(1)注册板载信息

mach-smdk2440.c文件中静态声明一个I2C设备

[cpp]  view plain copy
  1. static struct i2c_board_info i2c_devices[] __initdata = {  
  2.   
  3.     {I2C_BOARD_INFO("24c02", 0x50), },  
  4.   
  5.      {}  
  6.   
  7. };  

smdk2440_machine_init()函数中,向总线注册I2C设备信息:

[cpp]  view plain copy
  1. i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));  

(2)定义i2c驱动设备id:

[cpp]  view plain copy
  1. static struct i2c_device_id foo_idtable[] = {  
  2.   
  3.     { “24c01", 0x51 },  
  4.   
  5.     {“20402”,0x50 },  
  6.   
  7.     {}  
  8.   
  9. };  

(3)定义i2c_driver结构并完成其相应函数:

[cpp]  view plain copy
  1. static struct i2c_driver my_i2c_driver = {  
  2.   
  3.     .driver = {  
  4.   
  5.       .name = "i2c_demo",  
  6.   
  7.       .owner = THIS_MODULE,  
  8.   
  9.     },  
  10.   
  11.     .probe = my_i2c_probe,  
  12.   
  13.     .remove = my_i2c_remove,  
  14.   
  15.     .id_table = my_ids,  
  16.   
  17. };  

(4)模块初始化时添加/撤销时删除i2c_driver

[cpp]  view plain copy
  1. static int __init  my_i2c_client(void)  
  2.   
  3. {  
  4.   
  5.    return i2c_add_driver(&my_i2c_driver);  
  6.   
  7. }  
  8.   
  9. static void __exit my_i2c_exit(void)  
  10.   
  11. {  
  12.   
  13.    i2c_del_driver(&my_i2c_driver);  
  14.   
  15. }  

(5)使用/dev entry 访问方法

注册字符设备

[cpp]  view plain copy
  1. register_chrdev(I2C_MAJOR,DEVICE_NAME,&i2c_fops);  
  2.   
  3. 创建类class_create(THIS_MODULE, DEVICE_NAME);  
  4.   
  5. 在/dev下创建设备节点  
  6.   
  7. device_create(my_dev_class, &client->dev,MKDEV(I2C_MAJOR, 0), NULL, DEVICE_NAME);  


"实现代码附件下载",有需要请留言,邮件发~

谁能告诉我csdn为什么不可以上传附件?


代码测试结果:

Linux I2C驱动分析与实现_第2张图片

[cpp]  view plain copy
  1. #include <linux/kernel.h>  
  2. #include <linux/module.h>  
  3. #include <linux/fs.h>  
  4. #include <linux/slab.h>  
  5. #include <linux/init.h>  
  6. #include <linux/list.h>  
  7. #include <linux/i2c.h>  
  8. #include <linux/i2c-dev.h>  
  9. #include <linux/smp_lock.h>  
  10. #include <linux/jiffies.h>  
  11. #include <asm/uaccess.h>  
  12. #include <linux/delay.h>  
  13.   
  14.   
  15. #define DEBUG 1  
  16. #ifdef DEBUG  
  17. #define dbg(x...) printk(x)  
  18. #else   
  19. #define dbg(x...) (void)(0)  
  20. #endif  
  21.   
  22. #define I2C_MAJOR 89  
  23. #define DEVICE_NAME "at24c02"  
  24. static struct class *my_dev_class;  
  25. static struct i2c_client *my_client;  
  26. static struct i2c_driver my_i2c_driver;  
  27.   
  28.   
  29. static struct i2c_device_id my_ids[] = {  
  30.     {"24c01",0x50},  
  31.     {"24c02",0x50},  
  32.     {"24c08",0x50},  
  33.     {}  
  34. };  
  35.   
  36. MODULE_DEVICE_TABLE(i2c,my_ids);  
  37.   
  38. static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)  
  39. {  
  40.     int res;  
  41.     struct device *dev;  
  42.   
  43.     dbg("probe:name = %s,flag =%d,addr = %d,adapter = %d,driver = %s\n",client->name,  
  44.          client->flags,client->addr,client->adapter->nr,client->driver->driver.name );  
  45.   
  46.     dev = device_create(my_dev_class, &client->dev,  
  47.                      MKDEV(I2C_MAJOR, 0), NULL,  
  48.                      DEVICE_NAME);  
  49.     if (IS_ERR(dev))  
  50.     {  
  51.         dbg("device create error\n");  
  52.         goto out;  
  53.     }  
  54.     my_client = client;  
  55.       
  56.     return 0;  
  57. out:  
  58.     return -1;  
  59. }  
  60. static int  my_i2c_remove(struct i2c_client *client)  
  61. {  
  62.   
  63.     dbg("remove\n");  
  64.     return 0;  
  65. }  
  66.   
  67. static ssize_t at24c02_read(struct file *fd, char *buf, ssize_t count, loff_t *offset)  
  68. {  
  69.     char *tmp;  
  70.     int ret;  
  71.     char data_byte;  
  72.     char reg_addr = 0,i;  
  73.     struct i2c_client *client = (struct i2c_client*) fd->private_data;  
  74.     struct i2c_msg msgs[2];  
  75.   
  76.     dbg("read:count = %d,offset = %ld\n",count,*offset);  
  77.     tmp = kmalloc(count,GFP_KERNEL);  
  78.   
  79.     if (!tmp)  
  80.     {  
  81.         dbg("malloc error in read function\n");  
  82.         goto out;  
  83.     }  
  84.   
  85.     reg_addr = *offset;  
  86.     msgs[0].addr = client->addr;  
  87.     msgs[0].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC) ;  
  88.     msgs[0].len = 1;  
  89.     msgs[0].buf = (char *)®_addr;  
  90.       
  91.     msgs[1].addr= client->addr;  
  92.     msgs[1].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC);  
  93.     msgs[1].flags |= I2C_M_RD;  
  94.     msgs[1].len = count;  
  95.     msgs[1].buf = (char*)tmp;  
  96.   
  97.     ret = i2c_transfer(client->adapter,&msgs,2);  
  98.     if (ret != 2)  
  99.         goto out;  
  100.     if (copy_to_user(buf, tmp, count))  
  101.         goto out;  
  102.       
  103.     kfree(tmp);  
  104.     return count;  
  105. out:  
  106.     kfree(tmp);  
  107.     return -1;    
  108.       
  109. }  
  110.   
  111.   
  112. static int at24c02_ioctl(struct file *fd, unsigned int cmd, unsigned long arg)  
  113. {  
  114.     dbg("ioctl code ...\n");  
  115.     return 0;  
  116. }  
  117.   
  118. static ssize_t at24c02_write(struct file *fd, char *buf, ssize_t count, loff_t *offset)  
  119. {  
  120.     int ret,i;  
  121.     char *tmp;  
  122.     int errflg;  
  123.     struct i2c_msg msg;  
  124.     struct i2c_client *client = (struct i2c_client*) fd->private_data;  
  125.     char tmp_data[2];  
  126.   
  127.     dbg("write:count = %d,offset = %ld\n",count,*offset);  
  128.     tmp = kmalloc(count, GFP_KERNEL);  
  129.     if (!tmp)  
  130.         goto out;  
  131.     if (copy_from_user(tmp, buf, count))  
  132.         goto out;  
  133.     msg.addr = client->addr;  
  134.     msg.flags = client->flags & (I2C_M_TEN | I2C_CLIENT_PEC);  
  135.     for (i = 0; i < count; i++) {  
  136.         msg.len = 2;  
  137.         tmp_data[0] = *offset + i;  
  138.         tmp_data[1] = tmp[i];  
  139.         msg.buf = tmp_data;  
  140.         ret = i2c_transfer(client->adapter,&msg,1);  
  141.         if (ret != 1)  
  142.             goto out;  
  143.         msleep(1);  
  144.     }   
  145.     kfree(tmp);  
  146.   
  147.     return ((ret == 1) ? count:ret);  
  148. out:  
  149.     kfree(tmp);  
  150.     return -1;  
  151.       
  152. }  
  153. static int at24c02_open(struct inode *inode, struct file *fd)  
  154. {  
  155.   
  156.     fd->private_data =(void*)my_client;  
  157.     return 0;  
  158.   
  159. }  
  160.   
  161. static int at24c02_release(struct inode *inode, struct file *fd)  
  162. {  
  163.     dbg("release\n");  
  164.     fd->private_data = NULL;  
  165.       
  166.     return 0;     
  167.   
  168. }  
  169.   
  170. static const struct file_operations i2c_fops = {  
  171.     .owner = THIS_MODULE,  
  172.     .open   = at24c02_open,  
  173.     .read  = at24c02_read,  
  174.     .write = at24c02_write,  
  175.     .unlocked_ioctl = at24c02_ioctl,  
  176.     .release = at24c02_release,  
  177. };  
  178.   
  179. static struct i2c_driver my_i2c_driver = {  
  180.     .driver = {  
  181.         .name = "i2c_demo",  
  182.         .owner = THIS_MODULE,  
  183.     },  
  184.     .probe = my_i2c_probe,  
  185.     .remove = my_i2c_remove,  
  186.     .id_table = my_ids,  
  187. };  
  188.   
  189. static int __init my_i2c_init(void)  
  190. {  
  191.     int res;  
  192.       
  193.       
  194.     res = register_chrdev(I2C_MAJOR,DEVICE_NAME,&i2c_fops);  
  195.     if (res)  
  196.     {  
  197.         dbg("register_chrdev error\n");  
  198.         return -1;  
  199.     }  
  200.     my_dev_class = class_create(THIS_MODULE, DEVICE_NAME);  
  201.     if (IS_ERR(my_dev_class))  
  202.     {  
  203.         dbg("create class error\n");  
  204.         unregister_chrdev(I2C_MAJOR, DEVICE_NAME);  
  205.         return -1;  
  206.     }  
  207.     return i2c_add_driver(&my_i2c_driver);  
  208. }  
  209.   
  210. static void __exit my_i2c_exit(void)  
  211. {  
  212.     unregister_chrdev(I2C_MAJOR, DEVICE_NAME);  
  213.     class_destroy(my_dev_class);  
  214.     i2c_del_driver(&my_i2c_driver);  
  215.       
  216. }  
  217.   
  218. MODULE_AUTHOR("itspy<[email protected]>");  
  219. MODULE_DESCRIPTION("i2c client driver demo");  
  220. MODULE_LICENSE("GPL");  
  221. module_init(my_i2c_init);  
  222. module_exit(my_i2c_exit);  

你可能感兴趣的:(Linux I2C驱动分析与实现)