编译官方例程源码中的I2C驱动例程,发现i2c的probe函数始终无法执行,没有在dev下面生成设备节点。
多方求助,原来是i2c需要传统匹配方式,设备树匹配方式要同时匹配,ap3216c中的probe函数才能执行。
例程如下:
【正点原子】阿尔法Linux开发板(A盘)-基础资料\01、例程源码\02、Linux驱动例程\21_iic\ap3216c.c中
/* 传统匹配方式ID列表 */
static const struct i2c_device_id ap3216c_id[] = {
**{"alientek,ap3216c", 0},**
{}
};
/* 设备树匹配列表 */
static const struct of_device_id ap3216c_of_match[] = {
{ .compatible = "Liteon,ap3216c" },
{ /* Sentinel */ }
};
修改为:
/* 传统匹配方式ID列表 */
static const struct i2c_device_id ap3216c_id[] = {
**{"ap3216c", 0},**
{}
};
/* 设备树匹配列表 */
static const struct of_device_id ap3216c_of_match[] = {
{ .compatible = "Liteon,ap3216c" },
{ /* Sentinel */ }
};
修改后从新编译,/dev的设备节点终于生成了:
root@ATK-IMX6U:/mnt# ls /dev
ap3216c
root@ATK-IMX6U:/mnt# ./ap3216cApp /dev/ap3216c
ir = 0, als = 0, ps = 0
ir = 0, als = 265, ps = 3
ir = 0, als = 265, ps = 3
我使用的设备树定义如下
F:\【正点原子】阿尔法Linux开发板(A盘)-基础资料\01、例程源码\03、正点原子Uboot和Linux出厂源码\linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7\arch\arm\boot\dts\imx6ull-alientek-emmc.dts
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
mag3110@0e {
compatible = "fsl,mag3110";
reg = <0x0e>;
position = <2>;
};
ap3216c@1e {
compatible = "ap3216c";
reg = <0x1e>;
};
};
内核中的匹配代码分析:
内核代码中 i2c_device_probe 函数中存在
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
int status;
if (!client)
return 0;
... ...
driver = to_i2c_driver(dev->driver);
if (!driver->probe || !driver->id_table)
return -ENODEV;
... ...
status = driver->probe(client, i2c_match_id(driver->id_table, client));
... ...
}
if (!driver->probe || !driver->id_table)
return -ENODEV
其中|| 逻辑或 判断规则:一真则真,两假才假,即
如果driver->id_table为空或者driver->probe为空则无法实现probe函数
所以,在新内核的dts设备树表述设备时,注册i2c_driver时,一定要将i2c_driver中的id_table实现!!!
其实也是根据设备树匹配成功的,只不过传统匹配表(i2c_device_id)也必须实现。如果只使用传统匹配表匹配应该是不需要设备树匹配表的。