linux I2C体系结构的三大部分
-
I2C核心(由内核中i2c-core.c实现)
-
提供了i2c总线驱动和设备驱动的注册、注销方法。
- I2C通信上层的与具体的适配器无关的代码。
- 探测设备、检测设备地址的上层代码。
-
I2C总线驱动(由内核中i2c-dev.c实现,是对i2c硬件体系结构中适配器端的实现)
- 包含I2C适配器数据结构i2c_adapter。
- I2C适配器的Algorithm数据结构i2c_algorithm
- 控制I2C适配器产生通信信号的函数 主要是master_xfer()函数,它在I2C适配器上完成传递给它的i2c_msg数组中的每个i2c消息
经由I2C总线驱动的代码,可以控制I2C适配器
- 主控方式产生开始位、停止位、读写周期
- 从设备方式被读写、产生ACK
-
I2C设备驱动(客户驱动)是对硬件结构的设备端的实现
设备一般连接在受cpu控制的I2C适配器上,通过设配器与cpu交换数据
- 数据结构i2c_driver
- 数据结构i2c_client
linux I2C体系中四个重要的数据结构和它们之间的联系
-
i2c_adapter
-
i2c_algorithm
-
i2c_driver
-
i2c_client
前两个是总线驱动中所涉及的数据结构,后两个是设备驱动中涉及的数据结构,它们都在内核的i2c.h中进行了定义,接着就来说一下它们之间的关系
-
i2c_adapter和i2c_algorithm
i2c_adapter对应一个物理的适配器,i2c_algorithm对应一套通信方法。
一个i2c适配器需要i2c_algorithm提供的函数来产生特定的周期信号,所以如果没有i2c_algorithm所提供的函数,那么i2c适配器什么也做不成。
i2c_algorithm中的关键函数是master/-xfer()用来产生周期信号,以i2c_msg为单位。在函数master_xfer()中就完成了I2C协议中的启始信号、发地址、等待的ACK、读写字节底层硬件的操作i,需要工程师根据芯片的数据手册来完成。i2c_msg相当于一个数据包,里面包含了传输数据的三要素:源、目的、长度;还有一个是flag读写标志,0代表写,I2C_M_RD代表读。
-
i2c_driver和i2c_client
i2c_driver对应一套驱动方法,i2c_client对应一个物理设备
struct i2c_driver_id形式的i2c_table 是该驱动所支持的所有i2c设备ID
每个设备都需要用i2c_client结构体来进行硬件描述 描述一般包括:设备的地址,所链接的适配器,所用到的驱动方法还有标志flag。
i2c_driver和i2c_client是一对多的关系,也就是多个i2c设备可以共用一套驱动方法。
i2c通常在BSP的板文件中通过i2c_board_info填充。
i2c总线驱动i2c_bus_type的match()函数i2c_drivers_match()中,会调用i2c_match_id()函数来匹配板文件中定义的ID表和i2c_driver所支持的ID表。
-
i2c_adapter和i2c_client
i2c_adapter相当于物理的适配器,i2c_client相当于物理的设备
i2c_adapter和i2c_client是一对多的关系。一个适配器可以连多个i2c设备
工程师在整个I2C驱动中要做哪些东西?
总线驱动
- 提供I2C适配器的硬件驱动,探测、初始化I2C适配器(如申请I2C的I/O地址和中断号)、驱动CPU控制的I2C适配器从硬件上产生各种信号以及处理I2C中断等。
- 提供I2C适配器的algorithm 具体的就是master_xfer
设备驱动
- 实现I2C设备驱动中的i2c_driver
- 实现I2C设备所对应的具体驱动 i2c_driver只是设备与总线驱动的接口,所以还需要具体的驱动 例如:字符驱动 对存储设备进行读写。
用I2C对AT24CXX进行读写操作,完成设备驱动
- 入口函数at24cxx_init(),在入口函数中对i2c_driver进行注册,用函数i2c_add_driver()
- 在入口函数中对i2c_driver进行注册之前,我们需要定义并实例化i2c_driver结构体 在实例化结构体的过程中会涉及到attach_adapter和detach_client这两个函数指针,需要我们写这两个函数。at24cxx_attach()和at24cxx_detach()。前者在装载驱动后,会调用i2c_probe()函数,对设备的探测。这里可以参考http://blog.csdn.net/qq_33160790/article/details/68244202?locationNum=2有详细的介绍。在调用i2c_probe成功后会调用另一个函数at24cxx_detect()
- 在at24cxx_detect()中我们可以做一些自己的操作。到这里我们已经检测到这个I2C设备,然后我们需要将这个设备构造出来包括:设备地址,所用的适配器,用的驱动方法也就是i2c_driver等等.
- i2c_attach_client(at24cxx_client); /*附上这个设备到适配器上,通俗的说就是将设备和适配器连起来 不过2.6以后的内核已经没有这个了*/这个函数是将设备和适配器连起来。2.6以后的驱动中没有这个函数了,暂时还没研究。
- at24cxx_detect()中我们可以写具体的驱动,比如字符驱动,完成对AT24cxx的读写 字符驱动我们要用到file_operations结构体,注册字符设备一系列,在读的过程我们首先要发出读的地址,也就是写地址,然后才能读出内容。写需要注意的是先写地址再写数据。
- 读写数据也就是传输数据,确定数据的源、目的、长度,这里还有读写标志。构造i2c_msg结构体。然后用i2c_transfer(at24cxx_client->adapter,msgs,1)进行传输。
- 最后就是利用at24cxx_detach()函数,在函数中对申请的内存和注册的设备进行释放和注销。