Linux I2C驱动分析与实现

来源:互联网 发布:淘宝卡密提取网址 编辑:程序博客网 时间:2024/05/16 15:30

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

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

Linux中i2c子系统框图如下:

•客户驱动

即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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  1. i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));  

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

[cpp] view plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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为什么不可以上传附件?


代码测试结果:

[cpp] view plaincopy
  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<itspy.wei@gmail.com>");  
  219. MODULE_DESCRIPTION("i2c client driver demo");  
  220. MODULE_LICENSE("GPL");  
  221. module_init(my_i2c_init);  
  222. module_exit(my_i2c_exit);  

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手动档汽车离合抱死怎么办 别克gl8后轮吃胎怎么办 扭力梁后轮吃胎怎么办 非独立悬挂吃胎怎么办 货车半轴法兰盘裂纹怎么办 小天才平板裂屏了怎么办 新车撞了个坑怎么办 新车碰了个坑怎么办 汽车顶被砸了个坑怎么办 途观l前减震异响怎么办 锦明8代声音太大怎么办 手机网页无法加载插件怎么办 微信公众号被投诉怎么办 住了酒店的尾房怎么办 喜欢前任的闺蜜怎么办 闺蜜给介绍对象怎么办 喜欢对象的发小怎么办 山东省直医保卡丢失怎么办 高铁票如果错过了怎么办 动车错过了时间怎么办 长途动车错过了怎么办 动车如果错过了怎么办 没有取票错过了怎么办 动车出站没检票怎么办 火车晚点耽误了下班车怎么办 动车票中途丢了怎么办 购买二手房异地铁路公积金怎么办 沈阳公积金卡丢了怎么办 住宅专项维修资金用完了怎么办 广州出租车丢了东西怎么办 广州的士丢了东西怎么办 网上找兼职被骗了怎么办 海信空调开不了机怎么办 海信空调遥控器开不了怎么办 学生遭套路贷反被仲裁怎么办 赏脸打错字尝脸怎么办 红掌的花变黑了怎么办 红掌花苞发黑了怎么办 水培植物腐根了怎么办 水培绿萝水发臭怎么办 水里养花根烂掉怎么办