- 了解linux i2c framework. 源自蜗蜗科技
1.I2C Bus Topology
硬件拓扑如下图所示:
软件拓扑如下图所示:
- platform bus(/sys/bus/platform)用于挂载和CPU通过系统总线连接的各类外设。在I2C framework中,I2C控制器直接从属于platform bus,linux kernel中所说的I2C driver,都是指I2C controller driver,都是以platform driver的形式存在,当然,对应的控制器是platform device。查看如下:
[root@]# cd /sys/bus/platform/devices/
[root@]# ls -l
total 0
lrwxrwxrwx 1 0 0 0 Jan 1 00:05 d4010c00.i2c ->../../../devices/platform/d4010c00.i2c
- 与此同时,kernel抽象出I2C bus(/sys/bus/i2c),用于挂载和I2C controller通过I2C总线连接的各个I2C slave device。
[root@]# cd /sys/bus/i2c/
[root@]# ls
devices drivers_autoprobe uevent
drivers drivers_probe
[root@]# cd /sys/bus/i2c/devices
i2c-1
-
I2C core抽象一个虚拟实体I2C adapter,提供I2C controller相关的功能(主要是数据的收发),I2C adapter也挂载在I2C bus上。
-
I2C adapter和I2C slave device都挂载在I2C bus上,就可以方便的进行Master(I2C adapter)和Slave之间的匹配操作,并通过I2C core提供的统一接口,访问I2C salve device,进行数据的收发。
2.软件框架
Linux kernel抽象出如下的软件框架:
-
I2C framework最终目标是提供一种“访问I2C slave devices”的方法。由于这些slave devices由I2C controller控制,因而主要由I2C controller驱动实现这一目标。
-
经过I2C framework的抽象,consumer只需要通过简单的API,就可以与slave devices进行数据交互。正常情况下,consumer是位于内核态的其它driver(如HDMI driver、touch screen driver等等)。与此同时,I2C framework也通过字符设备向用户空间提供类似的接口,用户空间程序可以通过该接口访问slave devices。
-
在I2C framework内部,有I2C core、I2C busses、I2C algos和I2C muxes四个模块。
-
I2C core使用I2C adapter和I2C algorithm两个子模块抽象I2C controller的功能,使用I2C client和I2C driver抽象I2C slave device的功能(对应设备模型中的device和device driver)。另外,基于I2C协议,通过smbus模块实现SMBus(System Management Bus,系统管理总线)的功能。
-
I2C busses是各个I2C controller drivers的集合,位于drivers/i2c/busses/目录下,驱动工程师常说的“I2C driver”就是指它们。
-
I2C algos包含了一些通用的I2C algorithm,所谓的algorithm,是指I2C协议包的生成方法,进而组合成I2C的read/write指令,一般情况下,都是由硬件实现,不需要特别关注该目录。
-
I2C muxes用于实现I2C bus的多路复用功能。
3.Linux I2C Framework
I2C驱动框架主要由3部分组成,即I2C总线驱动、I2C核心层和I2C设备驱动。I2C核心层是I2C驱动和I2C设备驱动的中间枢纽,它以通用的、与平台无关的接口实现了I2C驱动中设备与适配器的沟通。
3.1.i2c core
I2C core提供I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法funcs上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。
1>.注册i2c bus(/sys/bus/i2c/)
1804 static int __init i2c_init(void)
1805 {
1814 ...
1815 retval = bus_register(&i2c_bus_type);
1818 ...
1820 retval = i2c_add_driver(&dummy_driver);
1837 return 0;
1838 }
2>.通用接口函数:
- 注册(销)IIC适配器:
i2c_add_adapter(struct i2c_adapter *adap);
i2c_add_numbered_adapter(struct i2c_adapter *adap);
i2c_del_adapter(struct i2c_adapter *adap); - 注册(销)IIC设备驱动:
i2c_register_driver(struct module *owner ,struct i2c_driver *driver);
i2c_del_driver(struct i2c_driver *driver); - IIC数据传输、发送和接收函数:
i2c_transfer(struct i2c_adapter *adapter,struct i2c_msg *msg,int num);
i2c_master_send(struct i2c_client *client,const char *buf,int count);
i2c_master_recv(struct i2c_client *client , char * buf , int count);
3.2.i2c总线驱动
I2C总线驱动即实现I2C适配器驱动,提供I2C适配器与slave device之间数据通信的能力。目前i2c控制器大多集中在soc芯片中,所以大多由soc厂商提供。内核中定义i2c_adapter结构体描述IIC适配器。
编写i2c总线驱动步骤:
- 1.编写与i2c控制器相关的平台驱动(struct platform_driver);
- 2.在平台驱动的probe()函数中构建struct i2c_adapter结构,可以直接创建这个结构,也可以将这个结构内嵌到一个表示某个平台的i2c控制器的一个结构体中。
- 3.实现struct i2c_algorithm中的传输数据的函数master_xfer和functionality;
- 4.设置struct i2c_adapter结构的一些信息,包括.algo、.retries、.class等;
- 5.注册struct i2c_adapter结构到i2c子系统中;
- 6.如果要支持device tree,那么就要调用of_i2c_register_devices()注册连接在该总线上的i2c设备。
3.3.i2c设备驱动
I2C设备驱动即实现I2Cslave device驱动,一个具体的I2C设备驱动包括两个部分:
- 一部分是i2c_device,用于将设备挂接于i2c总线;
- 另一部分是设备本身的驱动i2c_driver。
I2C设备驱动程序由i2c_device和i2c_driver来描述。
4.内核源码目录结构
drivers/i2c/
├── algos
│ ├── i2c-algo-bit.c
│ ├── i2c-algo-pca.c
│ ├── i2c-algo-pcf.c
│ ├── i2c-algo-pcf.h
│ ├── Kconfig
│ └── Makefile
├── busses
│ ├── i2c-gpio.c
│ ├── i2c-vendor.c
│ ├── Kconfig
│ ├── Makefile
├── i2c-boardinfo.c
├── i2c-core.c
├── i2c-core.h
├── i2c-dev.c
├── i2c-mux.c
├── i2c-slave-eeprom.c
├── i2c-smbus.c
├── i2c-stub.c
├── Kconfig
├── Makefile
└── muxes
├── Kconfig
└── Makefile