diff options
Diffstat (limited to 'drivers/leds/led-core.c')
| -rw-r--r-- | drivers/leds/led-core.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 016d19f5486..71b40d3bf77 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -23,3 +23,106 @@ EXPORT_SYMBOL_GPL(leds_list_lock); LIST_HEAD(leds_list); EXPORT_SYMBOL_GPL(leds_list); + +static void led_set_software_blink(struct led_classdev *led_cdev, + unsigned long delay_on, + unsigned long delay_off) +{ + int current_brightness; + + current_brightness = led_get_brightness(led_cdev); + if (current_brightness) + led_cdev->blink_brightness = current_brightness; + if (!led_cdev->blink_brightness) + led_cdev->blink_brightness = led_cdev->max_brightness; + + led_cdev->blink_delay_on = delay_on; + led_cdev->blink_delay_off = delay_off; + + /* never on - just set to off */ + if (!delay_on) { + __led_set_brightness(led_cdev, LED_OFF); + return; + } + + /* never off - just set to brightness */ + if (!delay_off) { + __led_set_brightness(led_cdev, led_cdev->blink_brightness); + return; + } + + mod_timer(&led_cdev->blink_timer, jiffies + 1); +} + + +static void led_blink_setup(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + if (!(led_cdev->flags & LED_BLINK_ONESHOT) && + led_cdev->blink_set && + !led_cdev->blink_set(led_cdev, delay_on, delay_off)) + return; + + /* blink with 1 Hz as default if nothing specified */ + if (!*delay_on && !*delay_off) + *delay_on = *delay_off = 500; + + led_set_software_blink(led_cdev, *delay_on, *delay_off); +} + +void led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + del_timer_sync(&led_cdev->blink_timer); + + led_cdev->flags &= ~LED_BLINK_ONESHOT; + led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; + + led_blink_setup(led_cdev, delay_on, delay_off); +} +EXPORT_SYMBOL(led_blink_set); + +void led_blink_set_oneshot(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off, + int invert) +{ + if ((led_cdev->flags & LED_BLINK_ONESHOT) && + timer_pending(&led_cdev->blink_timer)) + return; + + led_cdev->flags |= LED_BLINK_ONESHOT; + led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; + + if (invert) + led_cdev->flags |= LED_BLINK_INVERT; + else + led_cdev->flags &= ~LED_BLINK_INVERT; + + led_blink_setup(led_cdev, delay_on, delay_off); +} +EXPORT_SYMBOL(led_blink_set_oneshot); + +void led_stop_software_blink(struct led_classdev *led_cdev) +{ + del_timer_sync(&led_cdev->blink_timer); + led_cdev->blink_delay_on = 0; + led_cdev->blink_delay_off = 0; +} +EXPORT_SYMBOL_GPL(led_stop_software_blink); + +void led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + /* delay brightness setting if need to stop soft-blink timer */ + if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) { + led_cdev->delayed_set_value = brightness; + schedule_work(&led_cdev->set_brightness_work); + return; + } + + __led_set_brightness(led_cdev, brightness); +} +EXPORT_SYMBOL(led_set_brightness); |
