I2C子系统分析
firefly-3399
linux内核版本:4.4
参考博客:
https://www.cnblogs.com/deng-tao/p/6130080.html
http://blog.youkuaiyun.com/w89436838/article/details/38660631
http://blog.youkuaiyun.com/wangpengqi/article/details/17711165
I2C硬件
一个I2C总线上挂载了多个I2C接口器件,但是这些I2C从设备的地址可能会重突,大部分以0xA开头的,所以在ARM的SOC上会有多个I2C适配器,每个I2C适配器上挂在1到2个从设备
I2C 总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来 产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。
I2C子系统驱动
首先,I2C的架构和SPI的很相似,有适配器,设备,通过核心来进行连接,这样的分离架构可以使得Adapter和Device几乎没有耦合性,m+n个驱动可以形成m*n个搭配方式
- I2C核心层:代码位于i2c-core.c ,注册了i2c总线,实现了i2c_adapter的注册函数,i2c_driver和i2c_device的注册函数
- I2C适配器层:代码位于i2c-rk3x.c,提供i2c adapter的algorithm
- I2C驱动层:代码位于i2c-dev.c(通用的驱动),注册了设备节点,提供了file_operations
I2C核心层
/**
* i2c-core.c
* 注册了i2c总线,实现了i2c_adapter的注册函数,i2c_driver和i2c_device的注册函数
* 起到了连接上下层的作用,上层指的是i2c-dev.c中的通用用户层接口驱动程序,下层是i2c-rk3x.c中的soc内部适配器(bus)驱动程序
**/
struct bus_type i2c_bus_type = {
.name = "i2c", // 总线的名字
.match = i2c_device_match, // 总线下设备与设备驱动的匹配函数
.probe = i2c_device_probe, // 总线层的probr函数
.remove = i2c_device_remove, // 总线卸载时执行的函数
.shutdown = i2c_device_shutdown, // 电源管理
};
static struct i2c_driver dummy_driver = {
.driver.name = "dummy",
.probe = dummy_probe, //null实现
.remove = dummy_remove, //null实现
.id_table = dummy_id,
};
postcore_initcall(i2c_init)
i2c_init
bus_register(&i2c_bus_type) //注册i2c总线 /sys/bus/i2c
class_compat_register("i2c-adapter") //创建一个class /sys/class/i2c-adapter
i2c_add_driver(&dummy_driver) //注册一个i2c_driver,null驱动
i2c_device_probe(struct device *dev)//当i2c总线下的i2c_device和i2c_driver匹配后执行
i2c_client *client = i2c_verify_client(dev) // 通过device指针获取到对应的i2c_client指针
i2c_driver *driver =