Linux i2c子系统驱动probe
Posted mb60ffdbe016b5d
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux i2c子系统驱动probe相关的知识,希望对你有一定的参考价值。
I2C 子系统
I2C 子系统使用的概率非常大,我之前有做过手机的经验, 手机跑的安卓系统,内核是Linux,手机的很多器件都是用I2C通信的,我经历过从板级设备到dts设备树的阶段,知道I2C在整个系统的举足轻重,正常的TP,Camera,sonser等等都是使用I2C进行控制的。
吹牛逼这么多,就是让大家知道理解I2C子系统的重要性,不过这篇文章就写一个小细节,I2C驱动的probe是如何被触发的,如果你不知道其中的原理,可能在写驱动的时候不能成功执行probe也是有可能的。
static const struct i2c_device_id goodix_ts_id[] =
GTP_I2C_NAME, 0 ,
;
static struct of_device_id goodix_ts_dt_ids[] =
.compatible = "goodix,gt9xx" ,
;
static struct i2c_driver goodix_ts_driver =
.probe = goodix_ts_probe,
.remove = goodix_ts_remove,
.id_table = goodix_ts_id,
.driver =
.name = GTP_I2C_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(goodix_ts_dt_ids),
,
;
/*******************************************************
Function:
Driver Install function.
Input:
None.
Output:
Executive Outcomes. 0---succeed.
********************************************************/
static int goodix_ts_init(void)
s32 ret;
/*
......
*/
ret = i2c_add_driver(&goodix_ts_driver);
return ret;
i2c_add_driver 驱动和设备匹配
i2c_add_driver()
i2c_register_driver
driver_register
driver_find
bus_add_driver
driver_attach
bus_for_each_dev
next_device
__driver_attach
driver_match_device
i2c_device_match
acpi_driver_match_device
i2c_match_id
of_driver_match_device
of_match_device of_match_node
__of_match_node
__of_device_is_compatible
这个要说明的一个点是,我提出来一下,可能大家看代码的时候就不会那么困惑了,Linux 下的指针那么多,你每次如果调用都要追根溯源,那可能需要花费非常多的时间。
总线上的device和driver进行匹配的时候会调用 bus 对应的 match函数,对于i2c bus而言就是i2c_match,如果是platform_bus 那么就会回调到platform_match里面去执行。
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
const struct i2c_client *client)
while (id->name[0])
if (strcmp(client->name, id->name) == 0)
return id;
id++;
return NULL;
static int i2c_device_match(struct device *dev, struct device_driver *drv)
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
if (!client)
return 0;
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;
/* Then ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
driver = to_i2c_driver(drv);
/* match on an id table if there is one */
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
return 0;
里面有三种 match 的函数,最后才会调用 i2c_match_id 这个函数,这个也是低版本内核还没有使用dts的时候使用的方式,也就是匹配dev和driver的name。
看下面新的 compatible 匹配方式
/**
* __of_device_is_compatible() - Check if the node matches given constraints
* @device: pointer to node
* @compat: required compatible string, NULL or "" for any match
* @type: required device_type value, NULL or "" for any match
* @name: required node name, NULL or "" for any match
*
* Checks if the given @compat, @type and @name strings match the
* properties of the given @device. A constraints can be skipped by
* passing NULL or an empty string as the constraint.
*
* Returns 0 for no match, and a positive integer on match. The return
* value is a relative score with larger values indicating better
* matches. The score is weighted for the most specific compatible value
* to get the highest score. Matching type is next, followed by matching
* name. Practically speaking, this results in the following priority
* order for matches:
*
* 1. specific compatible && type && name
* 2. specific compatible && type
* 3. specific compatible && name
* 4. specific compatible
* 5. general compatible && type && name
* 6. general compatible && type
* 7. general compatible && name
* 8. general compatible
* 9. type && name
* 10. type
* 11. name
*/
static int __of_device_is_compatible(const struct device_node *device,
const char *compat, const char *type, const char *name)
struct property *prop;
const char *cp;
int index = 0, score = 0;
/* Compatible match has highest priority */
if (compat && compat[0])
/*获取dts里面该节点的值*/
prop = __of_find_property(device, "compatible", NULL);
for (cp = of_prop_next_string(prop, NULL); cp;
cp = of_prop_next_string(prop, cp), index++)
/*字符串比较*/
if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
score = INT_MAX/2 - (index << 2);
break;
/*返回成功*/
if (!score)
return 0;
/* Matching type is better than matching name */
if (type && type[0])
if (!device->type || of_node_cmp(type, device->type))
return 0;
score += 2;
/* Matching name is a bit better than not */
if (name && name[0])
if (!device->name || of_node_cmp(name, device->name))
return 0;
score++;
return score;
代码里面我们看到是同时比较 name ,type,compatible 这三个属性的,但是我们使用dts进行设置的时候,name和type的属性很多时候都是空的。
&i2c1
status = "okay";
/*
......
*/
gt9xx: gt9xx@14
compatible = "goodix,gt9xx";
reg = <0x14>;
touch-gpio = <&gpio1 0 IRQ_TYPE_EDGE_RISING>;
reset-gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
max-x = <800>;
max-y = <1280>;
tp-size = <89>;
configfile-num = <1>;
status = "okay";
tp-supply = <&vcc3v0_tp>;
;
;
i2c probe被探测 执行的流程
i2c_add_driver()
i2c_register_driver
driver_register driver_find
kset_find_obj
kobject_put
to_driver
bus_add_driver
driver_attach
bus_for_each_dev
next_device
__driver_attach
driver_match_device
driver_probe_device
really_probe
i2c_device_probe
i2c_match_id
你以为上面设置就好了吗?我们看到
static struct i2c_driver goodix_ts_driver =
.probe = goodix_ts_probe,
.remove = goodix_ts_remove,
.id_table = goodix_ts_id,
.driver =
.name = GTP_I2C_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(goodix_ts_dt_ids),
,
;
里面有一个 id_tabel和一个 of_match_table 两个东西,既然probe探测只需要 of_match_tabel就可以了,是不是可以去掉id_tabel了呢?
这感觉是一个遗留问题,在i2c_probe函数里面有一个判断,不知道历史原因还是为何,不能做到完全兼容,看代码如下
static int i2c_device_probe(struct device *dev)
/* ...... */
driver = to_i2c_driver(dev->driver);
/* 判断id_table为空就退出 */
if (!driver->probe || !driver->id_table)
return -ENODEV;
/* ...... */
扫码或长按关注
回复「 加群 」进入技术群聊
以上是关于Linux i2c子系统驱动probe的主要内容,如果未能解决你的问题,请参考以下文章