LINUX内核中的gpio-led子系统

我们可以在板子初始化时将GPIO-LED注册为platform_device,并指定该led的触发器,比如内核定义的heartbeat触发器,在系统运行期间会一直闪。

arch/arm/mach-davinci/board-da850-evm.c

#define DA850_HEARTBEAT_LED        GPIO_TO_PIN(6, 12)
static
const short da850_evm_tl_user_led_pins[] = {          // 这是引脚复用的列表 DA850_GPIO6_12, -1 }; static struct gpio_led da850_evm_tl_leds[] = { [0] = { .active_low = 0, .gpio = DA850_HEARTBEAT_LED,                    // GPIO引脚定义 .name = "heartbeat",                        // GPIO的名字,传递给gpio_request() .default_trigger = "heartbeat",                  // 触发器的名字 }, }; static struct gpio_led_platform_data da850_evm_tl_leds_pdata = { .leds = da850_evm_tl_leds, .num_leds = ARRAY_SIZE(da850_evm_tl_leds), }; static struct platform_device da850_evm_tl_leds_device = { .name = "leds-gpio",                      // platform_driver类型 .id = -1, .dev = { .platform_data = &da850_evm_tl_leds_pdata } }; static void da850_evm_tl_leds_init(void) { int ret; ret = davinci_cfg_reg_list(da850_evm_tl_user_led_pins);      // 设置引脚复用,该函数是davinci系列处理器自有的 if (ret) pr_warning("da850_evm_tl_leds_init : User LED mux failed :" "%d\n", ret); ret = platform_device_register(&da850_evm_tl_leds_device); if (ret) { pr_warning("Could not register som GPIO expander LEDS"); } }

/drivers/leds/leds-gpio.c文件中,如下定义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        = __devexit_p(gpio_led_remove),
    .driver        = {
        .name    = "leds-gpio",
        .owner    = THIS_MODULE,
        .of_match_table = of_gpio_leds_match,
    },
};
module_platform_driver(gpio_led_driver);

linux内核在初始化时,会根据platform_driver中定义的兼容名称列表,找到所有使用该platform_driverplatform_device,并逐个调用gpio_led_probe
gpio_led_probe会申请每个GPIO,并调用led_classdev_register函数。
led_classdev_register()函数在led-calss.c文件中定义,该函数会将GPIO-LED加入名为leds_list的列表中。leds_listled-core.c文件中定义
//////////////////////////////////////////////////////////////////////////////////////////////////
触发器列表trigger_listled-triggers.c中定义,该文件中同时定义了加入新触发器到该列表的函数led_trigger_register
heartbeat触发器的定义在ledtrig-heartbeat.c文件中,核心是一个定时器

static void heartbeat_trig_activate(struct led_classdev *led_cdev)
{
    struct heartbeat_trig_data *heartbeat_data;

    heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
    if (!heartbeat_data)
        return;

    led_cdev->trigger_data = heartbeat_data;
    setup_timer(&heartbeat_data->timer,
            led_heartbeat_function, (unsigned long) led_cdev);
    heartbeat_data->phase = 0;
    led_heartbeat_function(heartbeat_data->timer.data);
}

static struct led_trigger heartbeat_led_trigger = {
    .name     = "heartbeat",
    .activate = heartbeat_trig_activate,
    .deactivate = heartbeat_trig_deactivate,
};

static int __init heartbeat_trig_init(void)
{
    return led_trigger_register(&heartbeat_led_trigger);
}

static void __exit heartbeat_trig_exit(void)
{
    led_trigger_unregister(&heartbeat_led_trigger);
}

heartbeat触发器在初始化中,调用led_trigger_register注册触发器,并与使用该触发器的gpio-led绑定。
led_trigger_register函数的一部分:

/* Register with any LEDs that have this as a default trigger */
    down_read(&leds_list_lock);
    list_for_each_entry(led_cdev, &leds_list, node) {
        down_write(&led_cdev->trigger_lock);
        if (!led_cdev->trigger && led_cdev->default_trigger &&
                !strcmp(led_cdev->default_trigger, trigger->name))
            led_trigger_set(led_cdev, trigger);
        up_write(&led_cdev->trigger_lock);
    }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

其实本来是想在自己的驱动中定义一个led-trigger的,弄明白了之后,我放弃了——对于我正在编写的专用驱动,还不如直接操作GPIO省事。

posted on 2015-11-03 15:30  jacob1934  阅读(1058)  评论(0)    收藏  举报

导航