Linux platform总线

总线是Linux内核用来匹配设备与驱动的内核对象。Linux内核遵循设备与驱动分开的原则,驱动可以通过一些规则来获取对应的设备数据,这样就可以实现一个驱动对应该多个设备的情况。
在这里插入图片描述
Linux的总线下面分了platform总线、IIC总线、SPI总线等。总线下面又分了设备与驱动。驱动和设备通过总线的一些规则来进行匹配。下面就来讲解一下platform总线的工作原理。
platform总线是Linux内核的一种虚拟总线,是用来匹配那些没有明确框架的设备,比如Linux早期内核的PWM,ADC等设备。

int __init platform_bus_init(void)
{
	int error;

	early_platform_cleanup();

	error = device_register(&platform_bus);  // 注册platform设备
	if (error)
		return error;
	error =  bus_register(&platform_bus_type); // 注册platform总线
	if (error)
		device_unregister(&platform_bus);
	of_platform_register_reconfig_notifier();
	return error;
}

platform_bus_init是platform总线的初始化函数,device_register用来注册platform设备,bus_register用来注册platform总线的一些规则。
在Linux中内核的sys文件系统中可以查看对应的设备和总线
在这里插入图片描述

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.pm		= &platform_dev_pm_ops,
};

在platform_bus_type结构体中,重点关注platform_match函数,此函数是用来进行设备与驱动的匹配。

static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

	/* Attempt an OF style match first */
	if (of_driver_match_device(dev, drv))  // 设备树的匹配方式
		return 1;

	/* Then try ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
	return (strcmp(pdev->name, drv->name) == 0); // 利用名字进行匹配
}

platform_match函数内有5中匹配方式,常用的有设备树匹配方式和名字匹配方式。
设备树的匹配方式主要是匹配设备中的compatible值是否与驱动中的compatible值相同,相同就执行驱动程序。

  • 有设备树下的platform驱动匹配
mytestled: atkled{
	compatible = "fsl,imx6ull atkled";
	#address-cells = <1>;
	#size-cells = <1>;
	reg = < 0x20E02F4 0x04  // SW_PAD_CTL_PAD_GPIO1_IO03
			0x20E0068 0x04  // SW_MUX_CTL_PAD_GPIO1_IO03
			0x209C000 0x4000  // GPIO1
		>;
	status = "okay";
};

驱动

static const struct of_device_id led_of_match[] = {
	{.compatible = "fsl,imx6ull atkled",},
	{},
};
static struct platform_driver led_driver = {
	.probe = led_probe,
	.remove = led_remove,
	.driver = {
		.name = "led_dtb",
		.of_match_table = led_of_match,
		
	},
};

上面的例子中,在设备树的文件中有一个compatible属性,属性名为"fsl,imx6ull atkled"。在驱动中也有一个compatible属性,属性名也为"fsl,imx6ull atkled"。当着两个属性名相同时,就会触发platform_match函数的匹配规则,从而驱动程序就会被执行。

static const struct of_device_id *__of_match_node(const struct of_device_id *matches,
					   const struct device_node *node)
{
	const struct of_device_id *best_match = NULL;
	int score, best_score = 0;

	if (!matches)
		return NULL;

	for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
		score = __of_device_is_compatible(node, matches->compatible,
						  matches->type, matches->name);
		if (score > best_score) {
			best_match = matches;
			best_score = score;
		}
	}

	return best_match;
}

通过内核源代码可以看到,设备树的匹配方式不仅有compatible属性,name和type属性也可以进行匹配,但是很多内核驱动程序都习惯用compatible属性进行匹配。

  • 无设备树下的platform驱动匹配

在没有设备树的情况下也是一样的,只不过变成了设备与驱动的名字是否相同

static struct platform_device led_device = {
	.name = "led_nodtb",
	.id = -1,
	.num_resources = ARRAY_SIZE(led_resources),
	.resource = led_resources,
};
static struct platform_driver serial8250_isa_driver = {
	.probe		= led_probe,
	.remove		= led_remove,

	.driver		= {
		.name	= "led_nodtb",
	},
};

在上面程序中设备和驱动的名字都为led_nodtb,当两个名字相同时也会触发platform总线的匹配规则。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值