of中设备树生成方法
kerne\drivers\misc\mediatek\i2c\mt6580\i2c.c
设备驱动节点compatible = "mediatek,mt6580-i2c"
static const struct of_device_id mt_i2c_of_match[] = {
{.compatible = "mediatek,mt6580-i2c",},
{},
};
MODULE_DEVICE_TABLE(of, mt_i2c_of_match);
static struct platform_driver mt_i2c_driver = {
.probe = mt_i2c_probe,
.remove = mt_i2c_remove,
.suspend = mt_i2c_suspend,
.resume = mt_i2c_resume,
.driver = {
.name = I2C_DRV_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = mt_i2c_of_match,
#endif
},
};
设备(这里叫设备树)
compatible = “mediatek,mt6580-i2c”, compatible后面的字符串中只需要有一个符合就匹配成功,匹配函数逻辑在__of_device_is_compatible中
./kernel/arch/arm/boot/dts/mt6580.dts-760- i2c0: i2c@11009000 {
./kernel/arch/arm/boot/dts/mt6580.dts:761: compatible = "mediatek,mt6580-i2c", "mediatek,i2c0";
./kernel/arch/arm/boot/dts/mt6580.dts-762- cell-index = <0>;
./kernel/arch/arm/boot/dts/mt6580.dts-763- reg = <0x11009000 0x1000>;
./kernel/arch/arm/boot/dts/mt6580.dts-764- interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_LOW>,
./kernel/arch/arm/boot/dts/mt6580.dts-765- <GIC_SPI 50 IRQ_TYPE_LEVEL_LOW>;
./kernel/arch/arm/boot/dts/mt6580.dts-766- clock-div = <10>;
./kernel/arch/arm/boot/dts/mt6580.dts-767- #address-cells = <1>;
./kernel/arch/arm/boot/dts/mt6580.dts-768- #size-cells = <0>;
./kernel/arch/arm/boot/dts/mt6580.dts-769- };
./kernel/arch/arm/boot/dts/mt6580.dts-770-
./kernel/arch/arm/boot/dts/mt6580.dts-771- i2c1: i2c@1100a000 {
./kernel/arch/arm/boot/dts/mt6580.dts:772: compatible = "mediatek,mt6580-i2c", "mediatek,i2c1";
./kernel/arch/arm/boot/dts/mt6580.dts-773- cell-index = <1>;
./kernel/arch/arm/boot/dts/mt6580.dts-774- reg = <0x1100a000 0x1000>;
./kernel/arch/arm/boot/dts/mt6580.dts-775- interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_LOW>,
./kernel/arch/arm/boot/dts/mt6580.dts-776- <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
./kernel/arch/arm/boot/dts/mt6580.dts-777- clock-div = <10>;
./kernel/arch/arm/boot/dts/mt6580.dts-778- #address-cells = <1>;
./kernel/arch/arm/boot/dts/mt6580.dts-779- #size-cells = <0>;
./kernel/arch/arm/boot/dts/mt6580.dts-780- };
./kernel/arch/arm/boot/dts/mt6580.dts-781-
./kernel/arch/arm/boot/dts/mt6580.dts-782- i2c2: i2c@1100b000 {
./kernel/arch/arm/boot/dts/mt6580.dts:783: compatible = "mediatek,mt6580-i2c", "mediatek,i2c2";
./kernel/arch/arm/boot/dts/mt6580.dts-784- cell-index = <2>;
./kernel/arch/arm/boot/dts/mt6580.dts-785- reg = <0x1100b000 0x1000>;
./kernel/arch/arm/boot/dts/mt6580.dts-786- interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_LOW>,
./kernel/arch/arm/boot/dts/mt6580.dts-787- <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
./kernel/arch/arm/boot/dts/mt6580.dts-788- clock-div = <10>;
./kernel/arch/arm/boot/dts/mt6580.dts-789- #address-cells = <1>;
./kernel/arch/arm/boot/dts/mt6580.dts-790- #size-cells = <0>;
./kernel/arch/arm/boot/dts/mt6580.dts-791- };
匹配成功后等执行probe函数
mt_i2c_probe-》
i2c_add_numbered_adapter (可以用i2c_add_adapter,i2c_add_adapter会调用_i2c_add_numbered_adapter )->
i2c_register_adapter)-》
of_i2c_register_devices(下面还有i2c_scan_static_board_info)-》
of_i2c_register_device-》
&i2c1 {
#address-cells = <1>;
#size-cells = <0>;
cap_touch_mtk:cap_touch@5d {
compatible = "mediatek,cap_touch";
reg = <0x5d>;
status = "okay";
};
};
最终调用i2c_new_device
其中i2c_dev_set_name
生成的名字在
/sys/bus/i2c/devices 下面
/sys/bus/i2c/devices/1-005d/name 为cap_touch是怎样来的呢?
实现代码在:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/198e61b4983e7a602bf7300161c78b1b.png)
查一下i2c_client->name在哪里赋值,发现是在i2c_new_device中
strlcpy(client->name, info->type, sizeof(client->name));
查info->type找到在
of_i2c_register_device
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/67480ab4e755fbfda9640c38d79e9646.png)
of_modalias_node
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4f651ae67b6c990d8e10dee7dab9d986.png)
即将compatible 的值取逗号后面的字符串而得到
&i2c1 {
#address-cells = <1>;
#size-cells = <0>;
cap_touch_mtk:cap_touch@5d {
compatible = "mediatek,cap_touch";
reg = <0x5d>;
status = "okay";
};
};
#define i2c_add_driver(driver)
i2c_register_driver(THIS_MODULE, driver)
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p)))
return -EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver);
if (res)
return res;
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);
return 0;
}
其中driver->driver.bus = &i2c_bus_type;为bus操作函数
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
};
i2c_register_driver -> driver_register(&driver->driver);->bus_add_driver
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
if (driver_allows_async_probing(drv)) {
pr_debug("bus: '%s': probing driver %s asynchronously\n",
drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
}
module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_groups(drv, bus->drv_groups);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
__func__, drv->name);
}
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
return 0;
out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
driver_attach->__driver_attach
driver_match_device
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
i2c bus的match函数,match不成功,也无法进入probe探测函数
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;
}
带of匹配的在of_driver_match_device配对
of_driver_match_device-》of_driver_match_device-》of_match_node-》__of_match_node-》__of_device_is_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]) {
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) {
printk("zyk zyk cp of_driver_match_device %s compat %s\n",cp,compat);
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;
}
如mtk tp配对的有如下打印:
[ 1.839785] <1>-(0)[135:kworker/u8:4]zyk zyk cp of_driver_match_device mediatek,mt6580-touch compat mediatek,mt6580-touch
[ 1.840484] <1>-(2)[135:kworker/u8:4]zyk zyk cp of_driver_match_device mediatek,cap_touch compat mediatek,cap_touch
匹配节点 .compatible = “mediatek,cap_touch”
设备驱动:
static const struct i2c_device_id tpd_i2c_id[] = {{"gt9xx", 0}, {} };
static unsigned short force[] = {0, 0x5D, I2C_CLIENT_END, I2C_CLIENT_END};
static const unsigned short *const forces[] = { force, NULL };
#ifdef CONFIG_OF
//static const struct of_device_id gt9xx_dt_match[] = { {.compatible = "mediatek,goodix_touch"}, {},};
//fangjie modify: "mediatek,cap_touch"
static const struct of_device_id gt9xx_dt_match[] = { {.compatible = "mediatek,cap_touch"}, {},};
#endif
MODULE_DEVICE_TABLE(of, gt9xx_dt_match);
static struct i2c_driver tpd_i2c_driver = {
.driver = {
.name = "gt9xx",
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(gt9xx_dt_match),
#endif
},
.probe = tpd_i2c_probe,
.remove = tpd_i2c_remove,
.detect = tpd_i2c_detect,
.id_table = tpd_i2c_id,
.address_list = (const unsigned short *) forces,
};
设备(这里叫设备树)
匹配代码会在设备树中字符串中找,直到匹配成功就结束,没有匹配成功就返回,因此只需要有一个匹配设备驱动中的
compatible = “mediatek,cap_touch”;就可以匹配成功
&i2c1 {
#address-cells = <1>;
#size-cells = <0>;
cap_touch_mtk:cap_touch@5d {
compatible = "mediatek,cap_touch";
reg = <0x5d>;
status = "okay";
};
};
然后直接返回1:接下来进入probe函数
__driver_attach -》driver_probe_device -》really_probe
优先采用bus的probe,没有就调用i2c设备驱动的probe,二者选 一,一般bus中的probe会调用驱动的probe
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/157f89214a0c45b4cfe2fb0aab75a707.png)
先看bus的probe
i2c_device_probe
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3ee65778cbd767f6eccd33ebed843eed.png)
bus中调用设备驱动的probe
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/625e651cdb79b388fc3fe6973306ca17.png)
就算probe不成功,但match成功了,仍会在文件系统/sys/bus/i2c/drivers中留下device_driver节点信息:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5c0ecc8a51686585ec7eba44ee17f87c.png)
那这个节点gt9xx是怎样生成的?
目前分析是在
i2c_register_driver-》driver_register-》bus_add_driver-》kobject_init_and_add中生成的,函数用的参数中的fmt是device_driver->name,刚好是gt9xx
static struct i2c_driver tpd_i2c_driver = {
.driver = {
.name = "gt9xx",
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(gt9xx_dt_match),
#endif
},
.probe = tpd_i2c_probe,
.remove = tpd_i2c_remove,
.detect = tpd_i2c_detect,
.id_table = tpd_i2c_id,
.address_list = (const unsigned short *) forces,
};
做了实验修改后
static const struct i2c_device_id tpd_i2c_id[] = {{"gt9xx12312", 0}, {} };
static unsigned short force[] = {0, 0x5D, I2C_CLIENT_END, I2C_CLIENT_END};
static const unsigned short *const forces[] = { force, NULL };
#ifdef CONFIG_OF
//static const struct of_device_id gt9xx_dt_match[] = { {.compatible = "mediatek,goodix_touch"}, {},};
//fangjie modify: "mediatek,cap_touch"
static const struct of_device_id gt9xx_dt_match[] = { {.compatible = "mediatek,cap_touch"}, {},};
#endif
MODULE_DEVICE_TABLE(of, gt9xx_dt_match);
static struct i2c_driver tpd_i2c_driver = {
.driver = {
.name = "gt9xx53443",
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(gt9xx_dt_match),
#endif
},
.probe = tpd_i2c_probe,
.remove = tpd_i2c_remove,
.detect = tpd_i2c_detect,
.id_table = tpd_i2c_id,
.address_list = (const unsigned short *) forces,
};
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/1492c9c429408a50c0d4a2323572d901.png)
生成的仍是device_driver->name
利用这个可以查看对应的bus上devices drivers 注册了哪些设备与驱动
如mmc下有一个mmcblk的驱动
$:/sys/bus/mmc/drivers $ ls
mmcblk
如usb下的所有驱动
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6784c360c69f0f8c91f0098d1f6446e2.png)
综上所述:i2c设备要probe成功的条件:
1.需要的设备驱动与设备(这里叫设备树)的compatible属性相同
2.设备驱动的id_table不为空,至少有一个成员
如下例子
static const struct i2c_device_id tpd_i2c_id[] = {{“gt9xx”, 0}, {} };
3.probe函数返回成功,必须保证,其中的i2c 通讯成功
(上电时序,通讯格式,设备i2c地址,要与设备规格书一致)