I2C子系统驱动框架:
应用程序层(app层)
——————————————————————————————————–
i2c driver层: 从设备驱动层(TS Sensor等)
1. 需要和应用层交互(fops cdev)
2. 封装数据,但是不知道数据如何写入到硬件,需要调用adapter层的相关函数去写
——————————————————————————————————–
i2c core:维护i2c bus, 包括i2c driver和i2c client链表
1. 实现i2c client和i2c driver的匹配
——————————————————————————————————–
i2c adapter层: i2c控制器层,初始化i2c控制器,实现i2c时序
1. 将数据写入或读取从设备
2. 不知道具体数据(i2c driver提供的数据)是什么,但知道具体如何操作(读/写)从设备
这一层是具体的厂商实现的,比如三星:driver/i2c/busser/i2c-s3c2410.c
框架中,i2c core是由Linux内核实现的(i2c-core.c),i2c adapter是由具体的芯片厂商实现的,比如三星的芯片adapter实现都在driver/i2c/busser/i2c-s3c2410.c。所以这连个部分需要编译到uImage中(make menuconfig -> device driver -> <*> i2c support -> i2c hardware Bus support -> S3C2410 I2C driver)。
如果在/sys/bus/i2c/devices/i2c-0/1/2 表示有i2c-adapter 存在
在总结的时候看到有其他博友整理的框图非常好,我就借过来给大家分享!
从i2c驱动架构图中可以看出,linux内核对i2c架构抽象了一个叫核心层core的中间件,它分离了设备驱动device driver和硬件控制的实现细节(如操作i2c的寄存器),core层不但为上面的设备驱动提供封装后的内核注册函数,而且还为下面的硬件事件提供注册接口(也就是i2c总线注册接口i2c_add_register),可以说core层起到了承上启下的作用。
相关的重要结构体和函数:
1. i2c_client
每一个i2c从设备都需要用一个i2c_client结构体来描述,i2c_client对应真实的i2c物理设备device,但是i2c_client不是我们自己写程序去创建的,而是通过以下常用的方式自动创建的(这个地方不做详细说明,以介绍总体框架为主):
platform创建:
1. 注册i2c_board_info
2. 获取对应的adapter,然后i2c_new_device
devicetree创建:
3. 通过设备树的一个节点去描述一个从设备,设备树在解析的时候会自动创建client
struct i2c_client {
unsigned short flags; //标志位 (读写)
unsigned short addr; //7位的设备地址(低7位)
char name[I2C_NAME_SIZE]; //设备的名字,用来和i2c_driver匹配
struct i2c_adapter *adapter; //依附的适配器(adapter),适配器指明所属的总线(i2c0/1/2_bus)
struct device dev; //继承的设备结构体
int irq; //设备申请的中断号
struct list_head detected; //已经被发现的设备链表
};
2. i2c_driver
driver是指向从设备的驱动程序,由我们自己去实现并通过i2c_add_register注册到i2c的bus中,和i2c clinet进行匹配,匹配成功则调用probe函数。
struct i2c_driver {
int (*probe)(struct i2c_client *, const struct i2c_device_id *); //设备匹配成功调用的函数
int (*remove)(struct i2c_client *); //设备移除之后调用的函数
struct device_driver driver;