I2C总线经常挂载eeprom、温度传感器、湿度传感器等设备。I2C总线下可以挂载多个设备,识别设备采用一个地址,这个地址在一条i2c总线是独一无二的。I2C总线驱动与spi总线驱动框架是一致的,都是采用控制器、core、设备三层驱动。
内核中I2C 的处理已经做好了,我们只需要做设备驱动程序相关的内容。总线处理好了I2C 协议,即总线知道如何收发数据,而不知道数据的含义,我们要做的只是设备相关层的代码。
I2C 协议中,先发出7bit“设备地址”,然后是1 位“写”或“读”的标志位。然后接着是每发出8 位数据有一个ACK 位。
一般I2C 驱动分为两层:
总线层:知道设备如何读写。芯片厂家会帮我们做好,操作寄存器。
设备驱动层:知道数据的含义。
一、4个数据结构的作用及区别
1、i2c_adapter和i2c_algorithm
i2c_adapter:对应于物理上的适配器
i2c_algorithm:对应于一套通信方法
缺少了i2c_algorithm的i2c_adapter什么也做不了。
i2c_algorithm中的关键函数master_xfer用于产生i2c访问周期所需要的信号,以i2c_msg为单位,i2c_msg非常重要,它包含了i2c的传输地址、方向、缓冲区、缓冲区长度。
2、i2c_driver和i2c_client
i2c_driver:对应一套驱动方法
i2c_client:对应于真实的物理设备
每个i2c设备都需要一个i2c_client来描述。i2c_driver和i2c_client是一对多的关系,一个i2c_driver可以支持多个同类型的i2c_client。
3、i2c_client和i2c_adapter
i2c_client依赖于i2c_adapter,i2c_adapter可以被多个i2c_client依赖。
二、总线驱动
I2C总线控制器通常是在内存上,所以它本身是在platform总线上。使用总线驱动模型,通过platform_driver和platform_device的匹配来执行。
(1)适配器驱动的初始化
在platform_driver的probe函数中完成两个工作:
1、初始化I2C适配器的硬件资源,申请IO、中断号、时钟等;
2、使用i2c_add_adapter()添加i2c_adapter数据结构,并且在此之前i2c_adapter已经被初始化。
static int xxx_i2c_probe(struct platform_device *pdev) { struct i2c_adapter *adap; ... xxx_adapter_hw_init(); ,,, i2c_add_adapter(adap); }
在platform_driver的remove函数中完成相反的两个工作。
(2)i2c总线的通信方法
主要是实现i2c_algorithm的functionality和master_xfer函数。
三、设备驱动
1、初始化i2c_driver 和模块的加载和卸载
(同大部分总线驱动一样,不再赘述)
2、数据传输
在i2c设备上读写数据的时序且数据常通过i2c_msg组织,最后由i2c_transfer()发送
struct i2c_msg msg[2]; //第一条是写消息 msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = &offs; //第二条是读消息 msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; msg[1].len = sizeof(buf); msg[1].buf = &buf[0]; i2c_transfer(client->adapter, msg, 2);
更详细示例的参考drivers/i2c/busses/i2c-tegra.c