Linux内核自带的LED灯驱动:gpio_led_probe函数简析(probe函数)

本文详细解析了Linux内核中LED灯驱动的platform_driver,重点剖析了gpio_led_probe函数的工作原理,包括devicetree下的设备匹配与GPIO信息获取过程。
摘要由CSDN通过智能技术生成

一. 简介

前面一篇文章分析了 Linux内核自带的LED灯驱动框架中:驱动与设备匹配的关键。文章如下:

Linux内核自带的LED灯驱动框架:驱动与设备匹配分析-CSDN博客

本文继续简单分析Linux内核自带的LED灯驱动框架,主要分析一下 platform_driver的 probe函数,这里probe函数: gpio_led_probe函数。

二.  Linux内核自带的LED灯驱动:gpio_led_probe函数简析(probe函数)

1.   led灯的 platform_driver结构体

LED 灯驱动文件为 /drivers/leds/leds-gpio.c,打开 leds-gpio.c文件,找到Led灯的 platform_driver结构体,如下:
static const struct of_device_id of_gpio_leds_match[] = {
	{ .compatible = "gpio-leds", },
	{},
};

static struct platform_driver gpio_led_driver = {
	.probe		= gpio_led_probe,
	.remove		= gpio_led_remove,
	.driver		= {
		.name	= "leds-gpio",
		.of_match_table = of_gpio_leds_match,
	},
};

上面结构体中,驱动与设备匹配的两种方法:

.name  的匹配方法:驱动与设备传统的匹配方法(在不支持设备树的情况下)

.of_match_table的匹配方法:在支持设备树的情况下,of_match_table中 compatile值与 设备树中的设备节点的 compatile的匹配方法。

2.  gpio_led_probe 函数(platform_driver的probe函数)

当驱动和设备匹配以后 , gpio_led_probe 函数就会执行,此函数主要是从设备树中获取 LED灯的 GPIO 信息,缩减后的函数内容如下所示:
static int gpio_led_probe(struct platform_device *pdev)
{
	struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
	struct gpio_leds_priv *priv;
	int i, ret = 0;

	if (pdata && pdata->num_leds) {   /*非设备树方式 */
    /* 获取 platform_device 信息 */
    ....................
		}
	} else {                     /* 采用设备树 */
		priv = gpio_leds_create(pdev);
		if (IS_ERR(priv))
			return PTR_ERR(priv);
	}

	platform_set_drvdata(pdev, priv);

	return 0;
}

12~13 行,如果使用设备树的话,使用 gpio_leds_create 函数从设备树中提取设备信 息,获取到的 LED GPIO 信息保存在返回值中。
gpio_leds_create 函数内容如下:
static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct fwnode_handle *child;
	struct gpio_leds_priv *priv;
	int count, ret;
	struct device_node *np;

	count = device_get_child_node_count(dev);
	if (!count)
		return ERR_PTR(-ENODEV);

	priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
	if (!priv)
		return ERR_PTR(-ENOMEM);

	device_for_each_child_node(dev, child) {
		struct gpio_led led = {};
		const char *state = NULL;

		led.gpiod = devm_get_gpiod_from_child(dev, NULL, child);
		if (IS_ERR(led.gpiod)) {
			fwnode_handle_put(child);
			ret = PTR_ERR(led.gpiod);
			goto err;
		}

		np = of_node(child);

		if (fwnode_property_present(child, "label")) {
			fwnode_property_read_string(child, "label", &led.name);
		} else {
			if (IS_ENABLED(CONFIG_OF) && !led.name && np)
				led.name = np->name;
			if (!led.name)
				return ERR_PTR(-EINVAL);
		}
		fwnode_property_read_string(child, "linux,default-trigger",
					    &led.default_trigger);

		if (!fwnode_property_read_string(child, "default-state",
						 &state)) {
			if (!strcmp(state, "keep"))
				led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
			else if (!strcmp(state, "on"))
				led.default_state = LEDS_GPIO_DEFSTATE_ON;
			else
				led.default_state = LEDS_GPIO_DEFSTATE_OFF;
		}

		if (fwnode_property_present(child, "retain-state-suspended"))
			led.retain_state_suspended = 1;

		ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
				      dev, NULL);
		if (ret < 0) {
			fwnode_handle_put(child);
			goto err;
		}
	}

	return priv;

err:
	for (count = priv->num_leds - 2; count >= 0; count--)
		delete_gpio_led(&priv->leds[count]);
	return ERR_PTR(ret);
}

第 9 行,调用 device_get_child_node_count 函数统计子节点数量,一般在在设备树中创建一个节点表示 LED 灯,然后在这个节点下面为每个 LED 灯创建一个子节点。因此子节点数量 也是 LED 灯的数量。

17 行,遍历每个子节点,获取每个子节点的信息。
21 行,获取 LED 灯所使用的 GPIO 信息。
30~31 行,读取子节点 label 属性值,因为使用 label 属性作为 LED 的名字。
38~39 行,获取 “ linux,default-trigger ” 属性值,可以通过此属性设置某个 LED 灯在Linux 系统中的默认功能,比如,作为系统心跳指示灯等等。
41~49 行,获取 “ default-state ” 属性值,也就是 LED 灯的默认状态属性。
54 行,调用 create_gpio_led 函数创建 LED 相关的 io 其实就是设置 LED 所使用的 io为输出之类的。
create_gpio_led 函数主要是初始化 led_dat 这个 gpio_led_data 结构体类型变量, led_dat 保存了 LED 的操作函数等内容。

关于 gpio_led_probe 函数就分析到这里, gpio_led_probe 函数主要功能就是获取 LED 灯的设备信息,然后根据这些信息来初始化对应的 IO ,设置为输出等。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值