leds-gpio driver 续1

本文详细解析了Linux内核中GPIO LED模块的工作原理,特别是如何通过设备树配置实现LED设备的初始化与控制。文章深入分析了gpio-ledplatform_device与gpio-ledplatform_driver的匹配过程,以及关键函数gpio_led_probe和gpio_leds_create的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上文中分析了gpio-led platform_device是如何定义并注册的。
那么gpio-led platform_device 和 gpio-led platform_driver是如何匹配的呢

我们还是先分析probe函数
drivers\leds\leds-gpio.c

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) {
        priv = devm_kzalloc(&pdev->dev,
                sizeof_gpio_leds_priv(pdata->num_leds),
                    GFP_KERNEL);
        if (!priv)
            return -ENOMEM;

        priv->num_leds = pdata->num_leds;
        for (i = 0; i < priv->num_leds; i++) {
            ret = create_gpio_led(&pdata->leds[i], &priv->leds[i],
                          &pdev->dev, NULL,
                          pdata->gpio_blink_set);
            if (ret < 0)
                return ret;
        }
    } else {
        priv = gpio_leds_create(pdev);
        if (IS_ERR(priv))
            return PTR_ERR(priv);
    }

    platform_set_drvdata(pdev, priv);

    return 0;
}

接着看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;
    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_data *led_dat = &priv->leds[priv->num_leds];
        struct gpio_led led = {};
        const char *state = NULL;
        struct device_node *np = to_of_node(child);
        ret = fwnode_property_read_string(child, "label", &led.name);
        if (ret && IS_ENABLED(CONFIG_OF) && np)
            led.name = np->name;
        if (!led.name) {
            fwnode_handle_put(child);
            return ERR_PTR(-EINVAL);
        }
        led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child,
                                 GPIOD_ASIS,
                                 led.name);
        if (IS_ERR(led.gpiod)) {
            fwnode_handle_put(child);
            return ERR_CAST(led.gpiod);
        }
        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;
        if (fwnode_property_present(child, "retain-state-shutdown"))
            led.retain_state_shutdown = 1;
        if (fwnode_property_present(child, "panic-indicator"))
            led.panic_indicator = 1;
        ret = create_gpio_led(&led, led_dat, dev, np, NULL);
        if (ret < 0) {
            fwnode_handle_put(child);
            return ERR_PTR(ret);
        }
        led_dat->cdev.dev->of_node = np;
        priv->num_leds++;
    }
    return priv;
}

其中,

ret = fwnode_property_read_string(child, "label", &led.name);
led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child,
                                 GPIOD_ASIS,
                                 led.name);
fwnode_property_read_string(child, "linux,default-trigger",
                        &led.default_trigger);  

最后调用create_gpio_led()函数创建led

ret = create_gpio_led(&led, led_dat, dev, np, NULL);

那么设备树中的gpio定义是如何传递到设备中的呢
接着分析gpio_leds_create中调用的devm_fwnode_get_gpiod_from_child()函数
先看一段定义
drivers/gpio/gpiolib.h

/* gpio suffixes used for ACPI and device tree lookup */
static const char * const gpio_suffixes[] = { "gpios", "gpio" };

devm_fwnode_get_gpiod_from_child调用一系列函数, 创建gpio_desc

fwnode_get_named_gpiod
gpiod_get_from_of_node

最后调用devres_add将gpio_desc作为device resource 注册给leds-gpio platfor_device

devres_add(dev, dr);
``` /include/ "system-conf.dtsi" #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/media/xilinx-vip.h> #include <dt-bindings/phy/phy.h> / { model = "Alientek Navigator Zynq Development Board"; compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000"; leds { compatible = "gpio-leds"; gpio-led1 { label = "led2"; gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; default-state = "on"; }; gpio-led2 { label = "led1"; gpios = <&gpio0 54 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; gpio-led3 { label = "pl_led0"; gpios = <&axi_gpio_0 0 0 GPIO_ACTIVE_HIGH>; default-state = "on"; }; gpio-led4 { label = "pl_led1"; gpios = <&axi_gpio_0 1 0 GPIO_ACTIVE_HIGH>; linux,default-trigger = "timer"; }; gpio-led5 { label = "ps_led0"; gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; default-state = "on"; }; gpio-led6 { label = "ps_led1"; gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; linux,default-trigger = "timer"; }; }; keys { compatible = "gpio-keys"; autorepeat; gpio-key1 { label = "pl_key0"; gpios = <&gpio0 55 GPIO_ACTIVE_LOW>; linux,code = <KEY_LEFT>; gpio-key,wakeup; autorepeat; }; gpio-key2 { label = "pl_key1"; gpios = <&gpio0 56 GPIO_ACTIVE_LOW>; linux,code = <KEY_RIGHT>; gpio-key,wakeup; autorepeat; }; gpio-key3 { label = "ps_key1"; gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; linux,code = <KEY_UP>; gpio-key,wakeup; autorepeat; }; gpio-key4 { label = "ps_key2"; gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; linux,code = <KEY_DOWN>; gpio-key,wakeup; autorepeat; }; touch-key { label = "touch_key"; gpios = <&gpio0 57 GPIO_ACTIVE_HIGH>; linux,code = <KEY_ENTER>; gpio-key,wakeup; autorepeat; }; }; beep { compatible = "gpio-beeper"; gpios = <&gpio0 58 GPIO_ACTIVE_HIGH>; }; usb_phy0: phy0@e0002000 { compatible = "ulpi-phy"; #phy-cells = <0>; reg = <0xe0002000 0x1000>; view-port = <0x0170>; drv-vbus; }; }; &uart0 { u-boot,dm-pre-reloc; status = "okay"; }; &sdhci0 { u-boot,dm-pre-reloc; status = "okay"; }; &usb0 { dr_mode = "otg"; usb-phy = <&usb_phy0>; }; &qspi { u-boot,dm-pre-reloc; flash@0 { /* 16 MB */ compatible = "w25q256", "jedec,spi-nor"; reg = <0x0>; spi-max-frequency = <50000000>; #address-cells = <1>; #size-cells = <1>; partition@0x00000000 { label = "boot"; reg = <0x00000000 0x00100000>; }; partition@0x00100000 { label = "bootenv"; reg = <0x00100000 0x00020000>; }; partition@0x00120000 { label = "bitstream"; reg = <0x00120000 0x00400000>; }; partition@0x00520000 { label = "device-tree"; reg = <0x00520000 0x00020000>; }; partition@0x00540000 { label = "kernel"; reg = <0x00540000 0x00500000>; }; partition@0x00A40000 { label = "space"; reg = <0x00A40000 0x00000000>; }; }; }; &gem0 { local-mac-address = [00 0a 35 00 8b 87]; phy-handle = <&ethernet_phy>; ethernet_phy: ethernet-phy@7 { /* yt8521 */ reg = <0x7>; device_type = "ethernet-phy"; }; }; &gem1 { local-mac-address = [00 0a 35 00 11 55]; phy-reset-gpio = <&gpio0 63 GPIO_ACTIVE_LOW>; phy-reset-active-low; phy-handle = <&pl_phy>; pl_phy: pl_phy@4 { reg = <0x4>; device_type = "ethernet-phy"; }; }; &watchdog0 { status = "okay"; reset-on-timeout; // Enable watchdog reset function }; &adc { status = "okay"; xlnx,channels { #address-cells = <1>; #size-cells = <0>; channel@0 { reg = <0>; }; }; }; &i2c0 { clock-frequency = <100000>; eeprom@50 { compatible = "atmel,24c64"; reg = <0x50>; pagesize = <32>; }; rtc@51 { compatible = "nxp,pcf8563"; reg = <0x51>; }; };```如何查看linux内核支持哪些驱动
03-14
<think>好的,我需要帮助用户了解如何查看Linux内核支持的驱动。首先,用户提供的代码片段看起来是一个设备树(Device Tree)文件,用于配置硬件设备。这可能与内核驱动相关,所以需要结合设备树来分析。 用户的问题是“如何查看Linux内核支持哪些驱动”,我需要分步骤解释方法。首先想到的是内核配置,因为配置选项中包含了所有支持的驱动。通常通过make menuconfig或查看.config文件来查看已配置的驱动。另外,已编译的模块存放在/lib/modules目录下,可以用lsmod命令查看已加载的模块。 接下来,设备树中的compatible属性对应内核中的驱动匹配,可以查找源代码中的of_device_id结构体。用户提供的设备树里有很多compatible字段,比如gpio-leds、ulpi-phy等,这些可能对应内核中的具体驱动。 还需要提到内核文档,比如Documentation/devicetree/bindings/目录,这里会说明支持的驱动和绑定信息。另外,dmesg日志和/sys文件系统也能提供已加载驱动的信息。 可能需要解释用户提供的设备树中的部分内容,比如leds、keys、usb_phy等,说明它们是如何与内核驱动关联的。例如,gpio-leds兼容的驱动会处理LED设备,而gpio-keys对应按键驱动。 需要注意用户可能对内核编译和配置不太熟悉,所以步骤要详细,但不过于技术化。最后,确保回答结构清晰,分点说明各种方法,并结合用户提供的代码示例,说明如何通过设备树查找对应驱动。</think>以下是查看Linux内核支持哪些驱动的分步说明: ### 一、通过内核配置查看驱动支持 1. **内核配置文件**: - 查看路径:`/boot/config-$(uname -r)` 或 `/proc/config.gz` - 使用命令: ```bash zcat /proc/config.gz | grep CONFIG_GPIO_LEDS ``` - 示例结果:`CONFIG_GPIO_LEDS=y` 表示GPIO LED驱动已内置 2. **菜单配置工具**: ```bash make menuconfig # 在内核源码目录执行 ``` - 导航路径:`Device Drivers -> GPIO Support -> LED Support` ### 二、通过系统运行时信息 1. **已加载模块**: ```bash lsmod | grep gpio ``` 示例输出: ``` gpio_led 16384 0 ``` 2. **设备树绑定关系**(对应您提供的代码): ```dts leds { compatible = "gpio-leds"; // 对应内核的drivers/leds/leds-gpio.c驱动 ``` ### 三、通过内核源码分析 1. **驱动匹配规则**: ```c // 内核源码中的驱动声明示例(drivers/leds/leds-gpio.c) static const struct of_device_id of_gpio_leds_match[] = { { .compatible = "gpio-leds", }, {}, }; ``` 2. **驱动文档**: 查看内核文档: ```bash less Documentation/devicetree/bindings/leds/leds-gpio.txt ``` ### 四、针对您提供的设备树分析 1. **LED驱动**: ```dts gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; // 使用GPIO控制器0的第0号引脚 ``` 对应驱动: - 通用GPIO LED:`drivers/leds/leds-gpio.c` - AXI GPIO:`drivers/gpio/gpio-xilinx.c` 2. **按键驱动**: ```dts compatible = "gpio-keys"; // 对应drivers/input/keyboard/gpio_keys.c ``` 3. **USB PHY驱动**: ```dts compatible = "ulpi-phy"; // 对应drivers/usb/phy/phy-ulpi.c ``` ### 五、实用工具 1. **设备树反编译**: ```bash dtc -I fs /sys/firmware/devicetree/base ``` 2. **sysfs接口查询**: ```bash ls /sys/bus/platform/drivers # 查看所有平台驱动 ``` ### 六、特殊驱动验证(以watchdog为例) ```dts &watchdog0 { status = "okay"; // 需要CONFIG_XILINX_WATCHDOG驱动支持 } ``` 验证命令: ```bash dmesg | grep watchdog ``` ### 总结方法: | 方法 | 适用场景 | 示例命令 | |-------------------|---------------------------|-----------------------------------| | 内核配置文件 | 查看编译时配置选项 | `grep CONFIG_DRIVER_NAME /boot/config-*` | | 设备树兼容属性 | 验证硬件驱动绑定关系 | `dmesg | grep "compatible"` | | sys文件系统 | 查看运行时设备信息 | `ls /sys/class/leds/` | | 内核文档 | 查询驱动绑定规范 | `find Documentation/ -name "*gpio*"` | 注:您提供的设备树中: - `w25q256` SPI Flash需要`CONFIG_MTD_SPI_NOR`驱动 - `pcf8563` RTC需要`CONFIG_RTC_DRV_PCF8563`驱动 - `atmel,24c64` EEPROM需要`CONFIG_EEPROM_AT24`驱动
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值