i2c匹配过程 分析

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是怎样来的呢?
在这里插入图片描述

实现代码在:
在这里插入图片描述
查一下i2c_client->name在哪里赋值,发现是在i2c_new_device
strlcpy(client->name, info->type, sizeof(client->name));
查info->type找到在
of_i2c_register_device
在这里插入图片描述
of_modalias_node

在这里插入图片描述
即将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

在这里插入图片描述
先看bus的probe
i2c_device_probe

在这里插入图片描述
bus中调用设备驱动的probe
在这里插入图片描述
就算probe不成功,但match成功了,仍会在文件系统/sys/bus/i2c/drivers中留下device_driver节点信息:
在这里插入图片描述

那这个节点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,
};

在这里插入图片描述
生成的仍是device_driver->name
利用这个可以查看对应的bus上devices drivers 注册了哪些设备与驱动

如mmc下有一个mmcblk的驱动
$:/sys/bus/mmc/drivers $ ls
mmcblk
如usb下的所有驱动
在这里插入图片描述
综上所述:i2c设备要probe成功的条件:

1.需要的设备驱动与设备(这里叫设备树)的compatible属性相同

2.设备驱动的id_table不为空,至少有一个成员

如下例子
static const struct i2c_device_id tpd_i2c_id[] = {{“gt9xx”, 0}, {} };

3.probe函数返回成功,必须保证,其中的i2c 通讯成功

(上电时序,通讯格式,设备i2c地址,要与设备规格书一致)

发布了168 篇原创文章 · 获赞 39 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/u010481276/article/details/104652126