一. 简介
前面一篇文章分析了 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
,设置为输出等。