- 编写I2C slave device驱动程序
1.i2c slave device形态
嵌入式系统I2C总线上连接的slave device,有两种形态,如下:

-
CPU和设备之间的所有数据交互,都是通过I2C总线进行,没有其它方式,如PMIC、Audio codec等。
-
I2C只是CPU和设备之间进行数据交互的一种,例如HDMI,图像以及音频数据通过TDMS接口传输,EDID等信息的交互通过I2C总线(在HDMI协议中称作DDC接口)。
设备形态决定设备在设备模型中的位置:
- 形态1,以PMIC为例,可以把它看作I2C bus上的一个设备;
- 形态2,以TV为例,它一部分功能可看作I2C bus上的一个设备,另一部分是却是platform bus(HDMI Controller)上的一个设备,它的设备驱动要怎么写?一般是以其主要功能为准,TV的主要功能明显是音视频传输,因此应该当做一个platform设备。
2.DTSI settings
在设备模型中的位置不同,最终体现在DTS的描述方式不同。
- 形态1,pmic的DTS node是i2c1的一个child node,I2C core负责该设备的创建和注册,以及和其driver的probe等操作:
/* arch/arm/boot/dts/imx6dl-riotboard.dts */
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
…
pmic: pf0100@08 {
compatible = "fsl,pfuze100";
…
};
...
};
- 形态2,hdmi的DTS node位于根目录,作为platform device存在,它的DDC功能所使用的i2c2,是以一个变量的形式引用的:
/* arch/arm/boot/dts/imx6dl-riotboard.dts */
&hdmi {
ddc-i2c-bus = <&i2c2>;
status = "okay";
};
3.编写步骤(形态1)
-
根据硬件的连接方式,确定该设备所从属的I2C controller(即I2C adapter)。
-
在I2C adapter的DTS node中,添加该设备的DTS描述,其格式和正常的platform device一致。
-
DTS描述中的compatible关键字用于设备和驱动的probe,如“compatible = “fsl,pfuze100”;”,其它字段根据实际情况自行添加。
-
编写该设备的驱动程序,完成如下内容(如drivers/regulator/pfuze100-regulator.c):
-
定义一个struct i2c_driver类型的变量,并调用module_i2c_driver接口将其注册到I2C core中。
-
该变量包含应包含一个DTS中的“compatible ”字段相同的of_match_table,以及一个probe接口。
-
-
由“Linux I2C framework(2)- I2C provider”的描述可知,I2C framework core会在每一个I2C adapter注册时,为它下面所有的slave device创建struct i2c_client结构,并匹配对应的struct i2c_driver变量,调用driver的probe接口。
-
i2c_driver的probe接口的输入参数是struct i2c_client类型的指针(代表I2C slave device),以struct i2c_client指针为参数,可以调用i2c_master_send/i2c_master_recv接口进行简单的I2C传输,同时,也可以通过该指针获得所属的I2C adapter指针,然后通过i2c_transfer接口,进行更为复杂的read、write操作(可参考“drivers/base/regmap/regmap-i2c.c”中的regmap_i2c_read接口)。
4.相关APIs
- i2c_register_driver
- i2c_del_driver
4.1.i2c_register_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type; // 设置驱动的注册总线 i2c_bus_type
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver); // 注册进kernel设备驱动框架
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
i2c_for_each_dev(driver, __process_new_driver); // 轮询 i2c_bus_type 下的所有设备,并匹配驱动
return 0;
}
分析 __process_new_driver:
static int __process_new_driver(struct device *dev, void *data)
{
if (dev->type != &i2c_adapter_type) // 非 i2c_adapter 不能进一步处理
return 0;
return i2c_do_add_adapter(data, to_i2c_adapter(dev)); // 根据该驱动支持的address list,探测,创建并注册相应的i2c_client
}
参考代码:
- drivers/mfd/rk808.c
本文详细介绍了在嵌入式系统中I2C总线的两种设备形态及其DTS描述方法,重点讲解了如何根据设备形态编写I2C slave设备驱动程序,包括设备在DTS中的描述规范、驱动程序的编写步骤以及核心APIs的使用。
1698

被折叠的 条评论
为什么被折叠?



