I2C

转自:http://blog.csdn.net/shui1025701856/article/details/7565352


参考Linux设备驱动开发详解第十五章

一、I2C体系结构

 

[csharp]  view plain copy
  1. I2C和SMBus设备使用7位地址,总线上最多支持127个设备,最高100kbit/s的传输率,  
  2. 快速模式下可达400kbit/s,半双工.每个I2C/SMBus客户都分配有一个从地址,作为  
  3. 设备标识,I2C总线被非常广泛地应用在EEPROM、实时钟、小型LCD等设备与CPU的接口中  
  4. 在Linux系统中,I2C驱动由3部分组成,即I2C核心、I2C总线驱动和I2C设备驱动。  
  5. 这3部分相互协作,形成了非常通用、可适应性很强的I2C框架。  
  6.   
  7. I2C核心  
  8. I2C 核心提供了I2C总线驱动和设备驱动的注册、注销方法,  
  9. I2C通信方法(即“algorithm)上层的、与具体适配器无关的代码以及探测设备、  
  10. 检测设备地址的上层代码等  
  11.   
  12. I2C总线驱动  
  13. I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,  
  14. 甚至直接集成在CPU内部。I2C总线驱动主要包含了I2C适配器数据结构  
  15. i2c_adapter、I2C适配器的algorithm数据结构i2c_algorithm  
  16. 和控制I2C适配器产生通信信号的函数。  
  17. 经由I2C总线驱动的代码,我们可以控制I2C适配器以主控方式产生  
  18. 开始位、停止位、读写周期,以及以从设备方式被读写、产生ACK等。  
  19.   
  20. I2C设备驱动  
  21. I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备一般挂接在受  
  22. CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据  
  23. I2C设备驱动主要包含了数据结构i2c_driver和i2c_client,  
  24. 我们需要根据具体设备实现其中的成员函数。  
  25.   
  26. drivers/i2c/i2c-core.c  
  27. 这个文件实现了I2C核心的功能以及/proc/bus/i2c*接口  
  28. drivers/i2c/i2c-dev.c  
  29. 实现了I2C适配器设备文件的功能,每一个I2C适配器都被分配一个设备。  
  30. 通过适配器访问设备时的主设备号都为89,  
  31. 次设备号为0~255。应用程序通过 “i2c-%d” (i2c-0, i2c-1, ..., i2c-10, ...)  
  32. 文件名并使用文件操作接口open() write()、read()、ioctl()和close()等来访问这个设备  
  33. i2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read()、write()和ioctl()等接口  
  34. 用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或  
  35. 寄存器并控制I2C设备的工作方式  
  36.   
  37. busses文件夹  
  38. 这个文件中包含了一些I2C总线的驱动,如S3C2410 S3C6410的I2C控制器驱动为i2c-s3c2410.c。  
  39. algos文件夹  
  40. 实现了一些I2C总线适配器的algorithm。  
  41.   
  42. /include/linux/i2c.h  
  43. /** 
  44. *i2c_adapter 是用于标识物理I2C总线的结构 
  45. *要使用它的算法 
  46. */  
  47.   
  48. struct i2c_adapter {  
  49.     struct module *owner;//所属模块  
  50.     unsigned int id;//algorithm的类型,定义于include/linux/i2c-id.h  
  51.     unsigned int class;       /* 允许探测的*/  
  52.     const struct i2c_algorithm *algo; /* 总线通信方法结构体指针 */  
  53.     void *algo_data;//algorithm数据  
  54.   
  55.     /* 适用于所有设备的数据   */  
  56.     struct rt_mutex bus_lock;  
  57.   
  58.     int timeout;            /* in jiffies */  
  59.     int retries;//重复次数  
  60.     struct device dev;      /* 适配器设备*/  
  61.   
  62.     int nr;  
  63.     char name[48];//适配器名称  
  64.     struct completion dev_released;//用于同步  
  65.   
  66.     struct list_head userspace_clients;  
  67. };  
  68.   
  69. /** 
  70. *下面的结构是为那些想实施新的总线驱动: 
  71. *i2c_algorithm是一类硬件解决方案的接口 
  72. * 
  73. */  
  74.   
  75. struct i2c_algorithm {  
  76. /** 
  77. *如果适配器算法不能访问I2C,设置master_xfer为NULL,如果适配器 
  78. *算法可以做SMBus访问,设置smbus_xfer,如果设置为NULL,SMBus协议 
  79. *是模拟使用普通的I2C消息 
  80. */  
  81.       
  82.     int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,  
  83.                int num);//i2c传输函数指针  
  84.     int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,  
  85.                unsigned short flags, char read_write,  
  86.                u8 command, int size, union i2c_smbus_data *data);  
  87.                 //smbus传输函数指针  
  88.     /* 返回适配器支持的功能 */  
  89.     u32 (*functionality) (struct i2c_adapter *);  
  90. };  
  91.   
  92.   
  93. /** 
  94. *结构体i2c_driver代表一个I2C设备驱动程序 
  95. *@class:什么样的I2C设备,用于检测 
  96. *@attach_adapter:总线添加回调 
  97. *@detach_adapter:总线移除回调(for legacy drivers) 
  98. *@probe:设备绑定回调 
  99. *@remove:设备解脱回调 
  100. *@shutdown:设备关机回调 
  101. *@suspend:设备挂起回调 
  102. *@resume:设备唤醒回调 
  103. *@command:总线信号回调(可选) 
  104. *@driver:设备模型驱动 
  105. *@id_table:这个驱动支持的I2C器件 
  106. *@detect:设备检测回调 
  107. *@address_list:I2C地址探测 
  108. *@clients:我们创建了检测到的客户名单(I2C核心使用) 
  109. *@ 
  110. */  
  111.   
  112. struct i2c_driver {  
  113.     unsigned int class;  
  114.   
  115.     //通知一个新的总线驱动将会出现,你应避免使用这个,它可能  
  116.     //会在将来被删除  
  117.     int (*attach_adapter)(struct i2c_adapter *);//依附i2c_adapter函数指针  
  118.     int (*detach_adapter)(struct i2c_adapter *);//脱离i2c_adapter函数指针  
  119.   
  120.     /* 标准的驱动程序接口 */  
  121.     int (*probe)(struct i2c_client *, const struct i2c_device_id *);  
  122.     int (*remove)(struct i2c_client *);  
  123.   
  124.     /* 驱动模型接口,不涉及到枚举 */  
  125.     void (*shutdown)(struct i2c_client *);  
  126.     int (*suspend)(struct i2c_client *, pm_message_t mesg);  
  127.     int (*resume)(struct i2c_client *);  
  128.   
  129.     //回调警告,例如SMBus报警协议,数据值的格式和意义取决于协议  
  130.     void (*alert)(struct i2c_client *, unsigned int data);  
  131.   
  132.     //像ioctl一样,可用于执行特定功能的命令与设备  
  133.     int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);  
  134.   
  135.     struct device_driver driver;  
  136.     const struct i2c_device_id *id_table;//该驱动所支持的设备ID表  
  137.   
  138.     //设备自动创建设备的检测回调函数  
  139.     int (*detect)(struct i2c_client *, struct i2c_board_info *);  
  140.     const unsigned short *address_list;  
  141.     struct list_head clients;  
  142. };  
  143.   
  144. /** 
  145. *结构体i2c_client:代表一个I2C从设备 
  146. *@flags:I2C_CLIENT_TEN表示该设备采用了10位芯片的地址 
  147. *I2C_CLIENT_PEC:表明它使用的SMBus数据包错误检查 
  148. *@addr:父适配器连接到I2C总线上的地址 
  149. *@name:表示设备的类型,通常这是芯片的名称 
  150. *@adapter:管理I2C总线设备 
  151. *@driver:设备的驱动程序,指针来访问例程 
  152. *@dev:驱动模型从设备的节点 
  153. *@irq:表示此装置所产生的IRQ 
  154. *@detected:i2c_driver.clients或I2C核心成员列表 
  155. *i2c_client标识连接到一个单一的设备(芯片) 
  156. *i2c_bus由驱动定义 
  157. */  
  158. struct i2c_client {  
  159.     unsigned short flags;       /* 标志   */  
  160.     unsigned short addr;        /* 低7位的芯片地址 */  
  161.                       
  162.     char name[I2C_NAME_SIZE]; //设备名称  
  163.     struct i2c_adapter *adapter;    /* 依附的i2c_adapter   */  
  164.     struct i2c_driver *driver;  /* 依附的i2c_driver    */  
  165.     struct device dev;      /* 设备结构体        */  
  166.     int irq;            /* 设备使用的中断号 */  
  167.     struct list_head detected;  
  168. };  
  169.   
  170. i2c_adapter与i2c_algorithm  
  171. i2c_adapter 对应于物理上的一个适配器,而i2c_algorithm对应一套通信方法。  
  172. 一个I2C适配器需要i2c_algorithm中提供的通信函数来控制适配器上产生特定的访问周期。  
  173. 缺少i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含其使用的 i2c_algorithm的指针。  
  174. i2c_algorithm中的关键函数master_xfer()用于产生I2C访问周期需要的信号,以i2c_msg(即I2C消息)为单位  
  175.   
  176. /** 
  177. *i2c_msg:一个I2C传输起始 
  178. *@addr:从地址,七,或十位,当是十位的时候I2C_M_TEN必须被设置,必须支持I2C_FUNC_10BIT_ADDR 
  179. *@flags:I2C_M_RD适合所有适配器处理 
  180. *@len:消息长度 
  181. *@buf:消息数据 
  182. */  
  183.   
  184. struct i2c_msg {  
  185.     __u16 addr; /* slave address            */  
  186.     __u16 flags;  
  187. #define I2C_M_TEN       0x0010  /* this is a ten bit chip address */  
  188. #define I2C_M_RD        0x0001  /* read data, from slave to master */  
  189. #define I2C_M_NOSTART       0x4000  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  190. #define I2C_M_REV_DIR_ADDR  0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  191. #define I2C_M_IGNORE_NAK    0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  192. #define I2C_M_NO_RD_ACK     0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  193. #define I2C_M_RECV_LEN      0x0400  /* length will be first received byte */  
  194.     __u16 len;      /* msg length               */  
  195.     __u8 *buf;      /* pointer to msg data          */  
  196. };  
  197.   
  198. i2c_driver与i2c_client  
  199. i2c_driver对应一套驱动方法,是纯粹的用于辅助作用的数据结构,它不对应于任何的物理实体。i2c_client对应  
  200. 于真实的物理设备,每个I2C设备都需要一个i2c_client来描述。i2c_client一般被包含在i2c字符设备的私有信息结  
  201. 构体中  
  202. i2c_driver 与i2c_client发生关联的时刻在i2c_driver的attach_adapter()函数被运行时。attach_adapter()会探测物  
  203. 理设备,当确定一个client存在时,把该client使用的i2c_client数据结构的adapter指针指向对应的i2c_adapter  
  204. driver指针指向该i2c_driver,并会调用i2c_adapter的client_register()函数  
  205. 相反的过程发生在 i2c_driver 的detach_client()函数被调用的时候。  
  206.   
  207.  i2c_adpater与i2c_client  
  208.  i2c_adpater 与i2c_client的关系与I2C硬件体系中适配器和设备的关系一致,即i2c_client依附于i2c_adpater。由  
  209.  于一个适配器上可以连接多个I2C设备,所以一个i2c_adpater也可以被多个i2c_client依附,  
  210.  i2c_adpater中包括依附于它的i2c_client的链表。  
  211.   
  212.    
  213.  工程师要实现的主要工作如下  
  214.  提供I2C适配器的硬件驱动,探测、初始化I2C适配器(如申请I2C的I/O地址和中断号)、驱动CPU控制的I2C适  
  215.  配器从硬件上产生各种信号以及处理I2C中断等  
  216.  提供I2C适配器的algorithm,用具体适配器的xxx_xfer()函数填充i2c_algorithm的master_xfer指针,  
  217.  并把i2c_algorithm指针赋值给i2c_adapter的algo指针。  
  218. 实现I2C设备驱动与i2c_driver接口,用具体设备yyy的yyy_attach_adapter()函数指针、 yyy_detach_client()函  
  219. 数指针和yyy_command()函数指针的赋值给i2c_driver的attach_adapter、 detach_adapter和detach_client指针。  
  220. 实现I2C设备驱动的文件操作接口,即实现具体设备yyy的yyy_read()、yyy_write()和yyy_ioctl()函数等。  

二、I2C核心

[csharp]  view plain copy
  1. drivers/i2c/i2c-core.c  
  2. I2C核心(drivers/i2c/i2c-core.c)中提供了一组不依赖于硬件平台的接口函数,  
  3. 这个文件一般不需要被工程师修改,但是理解其中的主要函数非常关键,  
  4. 因为I2C总线驱动和设备驱动之间依赖于I2C核心作为纽带。I2C核心中的主要函数包括:  
  5. 增加删除i2c_adapter  
  6. int i2c_add_adapter(struct i2c_adapter *adapter)  
  7. int i2c_del_adapter(struct i2c_adapter *adap)  
  8. 增加删除i2c_driver  
  9. int i2c_register_driver(struct module *owner, struct i2c_driver *driver)  
  10. void i2c_del_driver(struct i2c_driver *driver)  
  11. 当一个具体的client被侦测到并被关联的时候,设备和sysfs文件将被注册  
  12. 相反地,在client被取消关联的时候,sysfs文件和设备也被注销  
  13.   
  14. I2C传输,发送和接收  
  15. //执行单一或联合的I2C消息  
  16. int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)  
  17. //主传输模式发送一个单一的I2C消息  
  18. int i2c_master_send(struct i2c_client *client, const char *buf, int count)  
  19. //主控I2C消息接收模式  
  20. int i2c_master_recv(struct i2c_client *client, char *buf, int count)  
  21. i2c_transfer ()函数用于进行I2C适配器和I2C设备之间的一组消息交互,i2c_master_send()函数和  
  22. i2c_master_recv()函数内部会调用i2c_transfer()函数分别完成一条写消息和一条读消息  
  23.   
  24. i2c_transfer()函数本身不具备驱动适配器物理硬件完成消息交互的能力,它只是需找到  
  25. i2c_adapter对应的i2c_algorithm,并使用i2c_algorithm的master_xfer()函数真正驱动硬件流程  


三、I2C总线驱动

[csharp]  view plain copy
  1. I2C适配器驱动加载与卸载  
  2. I2C总线驱动模块的加载函数要完成两个工作:  
  3. 初始化I2C适配器所使用的硬件资源,申请I/O地址、中断号等。  
  4. 通过i2c_add_adapter()添加i2c_adapter的数据结构,当然这个i2c_adapter数据结构的成员  
  5. 已经被xxx适配器的相应函数指针所初始化。  
  6. I2C总线驱动模块的卸载函数要完成的工作与加载函数的相反:  
  7. 释放I2C适配器所使用的硬件资源,释放I/O地址、中断号等  
  8. 通过i2c_del_adapter()删除i2c_adapter的数据结构  
  9.    
  10.  I2C总线通信方法  
  11. 我们需要为特定的I2C适配器实现其通信方法,主要实现i2c_algorithm的master_xfer()函数  
  12. 和functionality()函数  
  13. functionality ()函数非常简单,用于返回algorithm所支持的通信协议,如I2C_FUNC_I2C、  
  14. I2C_FUNC_10BIT_ADDR、 I2C_FUNC_SMBUS_READ_BYTE、I2C_FUNC_SMBUS_WRITE_BYTE等  
  15. master_xfer()函数在I2C适配器上完成传递给它的i2c_msg数组中的每个I2C消息  
  16. 总线驱动master_xfer函数模板  


 

四、I2C设备驱动

[csharp]  view plain copy
  1. I2C 设备驱动要使用i2c_driver和i2c_client数据结构并填充其中的成员函数。  
  2. i2c_client一般被包含在设备的私有信息结构体 yyy_data中,  
  3. 而i2c_driver则适宜被定义为全局变量并初始化  
  4. 被初始化的i2c_driver  
  5. static struct i2c_driver ov9640_i2c_driver = {  
  6.     .driver = {  
  7.         .name = "ov9640",  
  8.     },  
  9.     .probe    = ov9640_probe,  
  10.     .remove   = ov9640_remove,  
  11.     .id_table = ov9640_id,  
  12. };  
  13.   
  14.  Linux I2C设备驱动模块加载与卸载  
  15. I2C设备驱动模块加载函数通用的方法是在I2C设备驱动模块加载函数中完成两件事:  
  16. 通过register_chrdev()函数将I2C设备注册为一个字符设备。  
  17. 通过I2C核心的i2c_add_driver()函数添加i2c_driver  
  18. 在模块卸载函数中需要做相反的两件事:  
  19.  通过I2C核心的i2c_del_driver()函数删除i2c_driver  
  20.  通过unregister_chrdev()函数注销字符设备  
  21.    
  22.  static int __init ov9640_module_init(void)  
  23. {  
  24.     return i2c_add_driver(&ov9640_i2c_driver);  
  25. }  
  26.   
  27. static void __exit ov9640_module_exit(void)  
  28. {  
  29.     i2c_del_driver(&ov9640_i2c_driver);  
  30. }  
  31.   
  32. Linux I2C设备驱动的数据传输  


五、S3C6410 I2C总线驱动实例

[csharp]  view plain copy
  1. S3C6410 处理器内部集成了一个I2C控制器,通过4个寄存器就可以方便地对其进行控制  
  2. 这四个寄存器如下  
  3. IICCON:I2C控制寄存器  
  4. IICSTAT:I2C状态寄存器  
  5. IICDS:I2C收发数据移位寄存器  
  6. IICADD:I2C 地址寄存器  
  7. 通过对IICCON,IICDS和IICADD的操作,可在I2C总线上产生开始位,停止位,数据和地址  
  8. 而传输状态则通过IICSTAT寄存器获取  
  9. S3C6410 I2C的总线驱动drivers/i2c/busses/i2c-s3c2410.c  
  10. I2C总线驱动设计主要要实现的工作包括:  
  11. 设计对应于i2c_adapter_xxx_init()模板的S3C2410的模块加载函数和对应于  
  12. i2c_adapter_xxx_exit()函数模板的模块卸载函数。  
  13. 设计对应于i2c_adapter_xxx_xfer()模板的S3C6410适配器的通信方法函数  
  14. functionality()函数只需简单的返回  
  15. I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING  
  16. 表明其支持的功能  
  17.   
  18. static int __init i2c_adap_s3c_init(void)  
  19. {  
  20.     return platform_driver_register(&s3c24xx_i2c_driver);  
  21. }  
  22. subsys_initcall(i2c_adap_s3c_init);  
  23.   
  24. static void __exit i2c_adap_s3c_exit(void)  
  25. {  
  26.     platform_driver_unregister(&s3c24xx_i2c_driver);  
  27. }  
  28.   
  29.   
  30.   
  31. /* s3c24xx_i2c_probe 
  32.  * 
  33.  * called by the bus driver when a suitable device is found 
  34. */  
  35.   
  36. static int s3c24xx_i2c_probe(struct platform_device *pdev)  
  37. {  
  38.     struct s3c24xx_i2c *i2c;  
  39.     struct s3c2410_platform_i2c *pdata;  
  40.     struct resource *res;  
  41.     int ret;  
  42.   
  43.     pdata = pdev->dev.platform_data;  
  44.     if (!pdata) {  
  45.         dev_err(&pdev->dev, "no platform data\n");  
  46.         return -EINVAL;  
  47.     }  
  48.   
  49.     i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);  
  50.     if (!i2c) {  
  51.         dev_err(&pdev->dev, "no memory for state\n");  
  52.         return -ENOMEM;  
  53.     }  
  54.   
  55.     strlcpy(i2c->adap.name, "s3c2410-i2c"sizeof(i2c->adap.name));  
  56.     i2c->adap.owner   = THIS_MODULE;  
  57.     i2c->adap.algo    = &s3c24xx_i2c_algorithm;  
  58.     i2c->adap.retries = 2;  
  59.     i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;  
  60.     i2c->tx_setup     = 50;  
  61.   
  62.     spin_lock_init(&i2c->lock);  
  63.     init_waitqueue_head(&i2c->wait);  
  64.   
  65.     /* 发现时钟并使能它 */  
  66.   
  67.     i2c->dev = &pdev->dev;  
  68.     i2c->clk = clk_get(&pdev->dev, "i2c");  
  69.   
  70.     if (IS_ERR(i2c->clk)) {  
  71.         dev_err(&pdev->dev, "cannot get clock\n");  
  72.         ret = -ENOENT;  
  73.         goto err_noclk;  
  74.     }  
  75.   
  76.     dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);  
  77.   
  78.     clk_enable(i2c->clk);  
  79.   
  80.     /* 映射寄存器 */  
  81.   
  82.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  83.     if (res == NULL) {  
  84.         dev_err(&pdev->dev, "cannot find IO resource\n");  
  85.         ret = -ENOENT;  
  86.         goto err_clk;  
  87.     }  
  88.   
  89.     i2c->ioarea = request_mem_region(res->start, resource_size(res),  
  90.                      pdev->name);  
  91.   
  92.     if (i2c->ioarea == NULL) {  
  93.         dev_err(&pdev->dev, "cannot request IO\n");  
  94.         ret = -ENXIO;  
  95.         goto err_clk;  
  96.     }  
  97.   
  98.     i2c->regs = ioremap(res->start, resource_size(res));  
  99.   
  100.     if (i2c->regs == NULL) {  
  101.         dev_err(&pdev->dev, "cannot map IO\n");  
  102.         ret = -ENXIO;  
  103.         goto err_ioarea;  
  104.     }  
  105.   
  106.     dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",  
  107.         i2c->regs, i2c->ioarea, res);  
  108.   
  109.     /* 设置i2c核心需要的信息*/  
  110.   
  111.     i2c->adap.algo_data = i2c;  
  112.     i2c->adap.dev.parent = &pdev->dev;  
  113.   
  114.     /* initialise the i2c controller */  
  115.   
  116.     ret = s3c24xx_i2c_init(i2c);  
  117.     if (ret != 0)  
  118.         goto err_iomap;  
  119.   
  120.     /*  
  121.      *申请中断 
  122.      */  
  123.   
  124.     i2c->irq = ret = platform_get_irq(pdev, 0);  
  125.     if (ret <= 0) {  
  126.         dev_err(&pdev->dev, "cannot find IRQ\n");  
  127.         goto err_iomap;  
  128.     }  
  129.   
  130.     ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,  
  131.               dev_name(&pdev->dev), i2c);  
  132.   
  133.     if (ret != 0) {  
  134.         dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);  
  135.         goto err_iomap;  
  136.     }  
  137.   
  138.     ret = s3c24xx_i2c_register_cpufreq(i2c);  
  139.     if (ret < 0) {  
  140.         dev_err(&pdev->dev, "failed to register cpufreq notifier\n");  
  141.         goto err_irq;  
  142.     }  
  143.   
  144.     //bus_num是platform数据  
  145.     i2c->adap.nr = pdata->bus_num;  
  146.   
  147.     ret = i2c_add_numbered_adapter(&i2c->adap);  
  148.     if (ret < 0) {  
  149.         dev_err(&pdev->dev, "failed to add bus to i2c core\n");  
  150.         goto err_cpufreq;  
  151.     }  
  152.   
  153.     platform_set_drvdata(pdev, i2c);  
  154.   
  155.     clk_disable(i2c->clk);  
  156.   
  157.     dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));  
  158.     return 0;  
  159.   
  160. }  
  161.   
  162.   
  163. S3C6410 I2C总线通信方法  
  164. static const struct i2c_algorithm s3c24xx_i2c_algorithm = {  
  165.     .master_xfer        = s3c24xx_i2c_xfer,  
  166.     .functionality      = s3c24xx_i2c_func,  
  167. };  
  168.   
  169.   
  170. /drivers/misc/eeprom/at24.c不依赖于具体的CPU和I2C控制器硬件特性  
  171. 如果电路板包含该外设,只需要在板文件中添加对应的i2c_board_info  
  172. arch/arm/mach-s3c64xx/mach-smdk6410.c  
  173. static struct i2c_board_info i2c_devs0[] __initdata = {  
  174.     { I2C_BOARD_INFO("24c08", 0x50), },  
  175.     { I2C_BOARD_INFO("wm8580", 0x1b), },  
  176. }  


六、I2C读写函数的封装

[csharp]  view plain copy
  1. static int ov9650_reg_read(struct i2c_client *client, u8 reg, u8 *val)  
  2. {  
  3.     char buf[1];  
  4.     int retval = 0;  
  5.   
  6.     buf[0] = reg;  
  7.   
  8.     retval = i2c_master_send(client, buf, 1);  
  9.     if (retval != 1) {  
  10.         dev_err(&client->dev, "%s read reg:%x error\n", __func__, reg);  
  11.         return retval;  
  12.     }  
  13.   
  14.     retval = i2c_master_recv(client, buf, 1);  
  15.     if (retval != 1) {  
  16.         dev_err(&client->dev, "%s read reg:%x error\n", __func__, reg);  
  17.         return retval;  
  18.     }  
  19.   
  20.     *val = buf[0];  
  21.   
  22.     return retval;  
  23. }  
  24.   
  25. static int ov9650_reg_write(struct i2c_client *client, u8 reg, u8 val)  
  26. {  
  27.     int retval = 0;  
  28.   
  29.     if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))  
  30.         retval = i2c_smbus_write_byte_data(client, reg, val);  
  31.     else  
  32.         dev_err(&client->dev, "%s write reg:%x error\n", __func__, reg);  
  33.   
  34.     return retval;  
  35. }  
  36.   
  37. if (1) {  
  38.         u8 pid, ver;  
  39.         ov9650_reg_read(client, 0x0A, &pid);  
  40.         ov9650_reg_read(client, 0x0B, &ver);  
  41.         dev_info(&client->dev, "%s:PID=%x, VER=%x\n", client->name, pid, ver);  
  42.     }  
  43.       
  44. --------------------------------------------------------------------------------------  
  45. u8 s3c_fimc_i2c_read(struct i2c_client *client, u8 subaddr)  
  46. {  
  47.     u8 buf[1];  
  48.     struct i2c_msg msg = {client->addr, 0, 1, buf};  
  49.     int ret;  
  50.       
  51.     buf[0] = subaddr;  
  52.   
  53.     ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;  
  54.     if (ret == -EIO) {  
  55.         err("i2c transfer error\n");  
  56.         return -EIO;  
  57.     }  
  58.   
  59.     msg.flags = I2C_M_RD;  
  60.     ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;  
  61.   
  62.     return buf[0];  
  63. }  
  64.   
  65. int s3c_fimc_i2c_write(struct i2c_client *client, u8 subaddr, u8 val)  
  66. {  
  67.     u8 buf[2];  
  68.     struct i2c_msg msg = {client->addr, 0, 2, buf};  
  69.   
  70.     buf[0] = subaddr;  
  71.     buf[1] = val;  
  72.   
  73.     return i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;  
  74. }  
  75. ----------------------------------------------------  
  76. I2C发送和接收  
  77. drivers/i2c/i2c-core.c里实现  
  78. int i2c_master_send(struct i2c_client *client, const char *buf, int count)  
  79. int i2c_master_recv(struct i2c_client *client, char *buf, int count)  
  80. 第一个参数是i2c_client对象指针,第二个参数是要传输的数据buffer指针,第三个参数为ubffer  
  81. 的大小  
  82. 对于写I2C寄存器,给i2c_master_send函数传入两个字节的数据即可,第一个字节  
  83. 为寄存器地址,第二个字节为要写入寄存器的数据  
  84. static int ov9650_reg_write(struct i2c_client* client, u8 reg, u8 data)  
  85. {  
  86.     unsigned char buffer[2];  
  87.       
  88.     buffer[0] = reg;  
  89.     buffer[1] = data;  
  90.       
  91.     if ( 2 != i2c_master_send(client, buffer, 2)){  
  92.         printk(KERN_ERR "ov9650_i2c_reg_write fail!\n");  
  93.         return -1;  
  94.     }  
  95.       
  96.     return 0;  
  97. }  
  98.   
  99. 读I2C时序要做的操作是,先向I2C总线上写入需要读的寄存器地址,然后读I2C总线上的值  
  100. u8 ov9650_reg_read(struct i2c_client* client, u8 reg, u8 *data)  
  101. {  
  102.     //write reg addr  
  103.     if ( 1 != i2c_master_send(client, ®, 1)) {  
  104.         printk(KERN_ERR "ov9650_i2c_reg_read fail!\n");  
  105.         return -1;  
  106.     }  
  107.     //wait  
  108.     msleep(10);  //#include <linux/delay.h>  
  109.     //read  
  110.     if ( 1 != i2c_master_recv(client, data, 1)) {  
  111.         printk(KERN_ERR "ov9650_i2c_reg_read fail!\n");  
  112.         return -1;  
  113.     }  
  114.     return 0;  
  115. }  
  116. 测试  
  117. ---------------------------------------------------------  
  118.     u8 pid;  
  119.     ov9650_reg_read(client, 0x0A, &pid);读寄存器ID PID=96  
  120.     printk("PID=%x\n", pid);  
  121. ---------------------------------------------------------  
  122.     u8 pid;  
  123.     ov9650_reg_write(client, 0x0C, 0xCD);  
  124.     ov9650_reg_read(client, 0x0C, &pid);  
  125.     printk("PID=%x\n", pid);//PID=cd  
  126.       

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值