tiny4412 驱动 (5)Heartbeat

Heartbeat

struct list_head leds_list;           // 资源链表
struct list_head trigger_list;       // 驱动链表

对于链表,总有创建, 添加,遍历这三个要素,下面简单看下这两个链表的三要素

trigger_list

创建

driversleds/led-triggers.c

LIST_HEAD(trigger_list);

添加

driversleds/led-triggers.c

module_init(heartbeat_trig_init);
heartbeat_trig_init    // Ledtrig-heartbeat.c (drivers\leds\trigger)
led_trigger_register
    list_add_tail(&trig->next_trig, &trigger_list);

 

遍历

driversleds/led-triggers.c

led_trigger_store
led_trigger_show
led_trigger_set_default
led_trigger_register
    list_for_each_entry(_trig, &trigger_list, next_trig)

 

leds_list

创建

drivers/leds/led-core.c

LIST_HEAD(leds_list);

添加

drivers/leds/led-class.c

static struct platform_driver gpio_led_driver = {
    .probe      = gpio_led_probe,
    .shutdown   = gpio_led_shutdown,
    .driver     = {
        .name   = "leds-gpio",
        .of_match_table = of_gpio_leds_match,
    },
};
static const struct of_device_id of_gpio_leds_match[] = {
    { .compatible = "gpio-leds", },
    {},
};
module_platform_driver(gpio_led_driver);    // Leds-gpio.c (drivers\leds)
​
    gpio_led_probe
        gpio_leds_create
        create_gpio_led
            devm_of_led_classdev_register
                of_led_classdev_register
                    list_add_tail(&led_cdev->node, &leds_list);

 

遍历

drivers/leds/led-triggers.c

static struct led_trigger heartbeat_led_trigger = {
    .name     = "heartbeat",
    .activate = heartbeat_trig_activate,
    .deactivate = heartbeat_trig_deactivate,
    .groups = heartbeat_trig_groups,
};
​
heartbeat_trig_init       //  driversleds/trigger/Ledtrig-heartbeat.c
    led_trigger_register(&heartbeat_led_trigger);
    led_trigger_unregister
        list_for_each_entry(led_cdev, &leds_list, node) 

先看资源,即设备树

vim arch/arm/boot/dts/exynos4412-tiny4412.dts

leds {
                compatible = "gpio-leds";
​
                led1 {
                        label = "led1";
                        gpios = <&gpm4 0 GPIO_ACTIVE_LOW>;
                        default-state = "off";
                        linux,default-trigger = "heartbeat";
                };
​
                led2 {
                        label = "led2";
                        gpios = <&gpm4 1 GPIO_ACTIVE_LOW>;
                        default-state = "off";
                };
​
                led3 {
                        label = "led3";
                        gpios = <&gpm4 2 GPIO_ACTIVE_LOW>;
                        default-state = "off";
                };
​
                led4 {
                        label = "led4";
                        gpios = <&gpm4 3 GPIO_ACTIVE_LOW>;
                        default-state = "off";
                        linux,default-trigger = "mmc0";
                };
        };

led1是系统heartbeat,这里主要分析它。

其驱动程序在 drivers/leds/leds-gpio.c, 匹配compatible = "gpio-leds"

static const struct of_device_id of_gpio_leds_match[] = {
        { .compatible = "gpio-leds", },
        {},
};

在gpio_led_probe里面会解析设备树

gpio_led_probe
    gpio_leds_create
        fwnode_property_read_string(child, "label", &led.name);   // label
        devm_fwnode_get_gpiod_from_child(dev, NULL, child,
                                 GPIOD_ASIS,
                                 led.name);                     // name
        fwnode_property_read_string(child, "linux,default-trigger",
                        &led.default_trigger);
        fwnode_property_read_string(child, "default-state",
                         &state)
        create_gpio_led(&led, led_dat, dev, np, NULL);
            devm_of_led_classdev_register(parent, np, &led_dat->cdev);
                of_led_classdev_register -->
                    list_add_tail(&led_cdev->node, &leds_list); // leds_list链表产生了节点

驱动

那么trigger驱动在哪里呢

在drivers/leds/led-triggers.c

module_init(heartbeat_trig_init);
heartbeat_trig_init -->
led_trigger_register -->
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, trig->name))
        led_trigger_set(led_cdev, trig);
    up_write(&led_cdev->trigger_lock);
} // 遍历leds_list链

如果要控制LED,需要调用函数:

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

在led_trigger_set函数里面

void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
{
    if (led_cdev->trigger) {
        write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
        list_del(&led_cdev->trig_list);
        write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
            flags);
        cancel_work_sync(&led_cdev->set_brightness_work);
        led_stop_software_blink(led_cdev);
        if (led_cdev->trigger->deactivate)      // deactivate
            led_cdev->trigger->deactivate(led_cdev);
        led_cdev->trigger = NULL;
        led_set_brightness(led_cdev, LED_OFF);
    }
    if (trig) {
        write_lock_irqsave(&trig->leddev_list_lock, flags);
        list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
        write_unlock_irqrestore(&trig->leddev_list_lock, flags);
        led_cdev->trigger = trig;
        if (trig->activate)                     // activate
            trig->activate(led_cdev);
    }
}

而在heartbeat_trig_activate里面

 

timer_setup(&heartbeat_data->timer, led_heartbeat_function, 0);
led_heartbeat_function(&heartbeat_data->timer);

操作

make menuconfig

  Device Drivers  ---> 
	[*] LED Support  --->
		<*>   LED Class Support 
		[*]   LED Trigger support  --->
			<*>   LED Heartbeat Trigger

重新烧录内核并进入文件系统后,在/sys/class/leds里面下有led0这个目录

echo 0 > brightness            #停止闪烁
echo heartbeat > trigger       #继续闪烁 

 

你可能感兴趣的:(tiny4412,tiny4412)