1c72a1d60SRichard Purdie /* 2c72a1d60SRichard Purdie * LED Class Core 3c72a1d60SRichard Purdie * 4c72a1d60SRichard Purdie * Copyright 2005-2006 Openedhand Ltd. 5c72a1d60SRichard Purdie * 6c72a1d60SRichard Purdie * Author: Richard Purdie <rpurdie@openedhand.com> 7c72a1d60SRichard Purdie * 8c72a1d60SRichard Purdie * This program is free software; you can redistribute it and/or modify 9c72a1d60SRichard Purdie * it under the terms of the GNU General Public License version 2 as 10c72a1d60SRichard Purdie * published by the Free Software Foundation. 11c72a1d60SRichard Purdie * 12c72a1d60SRichard Purdie */ 13c72a1d60SRichard Purdie 14c72a1d60SRichard Purdie #include <linux/kernel.h> 15c72a1d60SRichard Purdie #include <linux/list.h> 16c72a1d60SRichard Purdie #include <linux/module.h> 1772f8da32SRichard Purdie #include <linux/rwsem.h> 18c72a1d60SRichard Purdie #include <linux/leds.h> 19c72a1d60SRichard Purdie #include "leds.h" 20c72a1d60SRichard Purdie 2172f8da32SRichard Purdie DECLARE_RWSEM(leds_list_lock); 22c72a1d60SRichard Purdie EXPORT_SYMBOL_GPL(leds_list_lock); 234d404fd5SNémeth Márton 244d404fd5SNémeth Márton LIST_HEAD(leds_list); 254d404fd5SNémeth Márton EXPORT_SYMBOL_GPL(leds_list); 26a403d930SBryan Wu 27a403d930SBryan Wu static void led_set_software_blink(struct led_classdev *led_cdev, 28a403d930SBryan Wu unsigned long delay_on, 29a403d930SBryan Wu unsigned long delay_off) 30a403d930SBryan Wu { 31a403d930SBryan Wu int current_brightness; 32a403d930SBryan Wu 33a403d930SBryan Wu current_brightness = led_get_brightness(led_cdev); 34a403d930SBryan Wu if (current_brightness) 35a403d930SBryan Wu led_cdev->blink_brightness = current_brightness; 36a403d930SBryan Wu if (!led_cdev->blink_brightness) 37a403d930SBryan Wu led_cdev->blink_brightness = led_cdev->max_brightness; 38a403d930SBryan Wu 39a403d930SBryan Wu led_cdev->blink_delay_on = delay_on; 40a403d930SBryan Wu led_cdev->blink_delay_off = delay_off; 41a403d930SBryan Wu 42a403d930SBryan Wu /* never on - don't blink */ 43a403d930SBryan Wu if (!delay_on) 44a403d930SBryan Wu return; 45a403d930SBryan Wu 46a403d930SBryan Wu /* never off - just set to brightness */ 47a403d930SBryan Wu if (!delay_off) { 480da3e65bSShuah Khan __led_set_brightness(led_cdev, led_cdev->blink_brightness); 49a403d930SBryan Wu return; 50a403d930SBryan Wu } 51a403d930SBryan Wu 52a403d930SBryan Wu mod_timer(&led_cdev->blink_timer, jiffies + 1); 53a403d930SBryan Wu } 54a403d930SBryan Wu 55a403d930SBryan Wu 5620c0e6b8SBryan Wu static void led_blink_setup(struct led_classdev *led_cdev, 57a403d930SBryan Wu unsigned long *delay_on, 58a403d930SBryan Wu unsigned long *delay_off) 59a403d930SBryan Wu { 605bb629c5SFabio Baltieri if (!(led_cdev->flags & LED_BLINK_ONESHOT) && 615bb629c5SFabio Baltieri led_cdev->blink_set && 62a403d930SBryan Wu !led_cdev->blink_set(led_cdev, delay_on, delay_off)) 63a403d930SBryan Wu return; 64a403d930SBryan Wu 65a403d930SBryan Wu /* blink with 1 Hz as default if nothing specified */ 66a403d930SBryan Wu if (!*delay_on && !*delay_off) 67a403d930SBryan Wu *delay_on = *delay_off = 500; 68a403d930SBryan Wu 69a403d930SBryan Wu led_set_software_blink(led_cdev, *delay_on, *delay_off); 70a403d930SBryan Wu } 715bb629c5SFabio Baltieri 725bb629c5SFabio Baltieri void led_blink_set(struct led_classdev *led_cdev, 735bb629c5SFabio Baltieri unsigned long *delay_on, 745bb629c5SFabio Baltieri unsigned long *delay_off) 755bb629c5SFabio Baltieri { 765bb629c5SFabio Baltieri del_timer_sync(&led_cdev->blink_timer); 775bb629c5SFabio Baltieri 785bb629c5SFabio Baltieri led_cdev->flags &= ~LED_BLINK_ONESHOT; 795bb629c5SFabio Baltieri led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; 805bb629c5SFabio Baltieri 815bb629c5SFabio Baltieri led_blink_setup(led_cdev, delay_on, delay_off); 825bb629c5SFabio Baltieri } 83a403d930SBryan Wu EXPORT_SYMBOL(led_blink_set); 84a403d930SBryan Wu 855bb629c5SFabio Baltieri void led_blink_set_oneshot(struct led_classdev *led_cdev, 865bb629c5SFabio Baltieri unsigned long *delay_on, 875bb629c5SFabio Baltieri unsigned long *delay_off, 885bb629c5SFabio Baltieri int invert) 895bb629c5SFabio Baltieri { 905bb629c5SFabio Baltieri if ((led_cdev->flags & LED_BLINK_ONESHOT) && 915bb629c5SFabio Baltieri timer_pending(&led_cdev->blink_timer)) 925bb629c5SFabio Baltieri return; 935bb629c5SFabio Baltieri 945bb629c5SFabio Baltieri led_cdev->flags |= LED_BLINK_ONESHOT; 955bb629c5SFabio Baltieri led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; 965bb629c5SFabio Baltieri 975bb629c5SFabio Baltieri if (invert) 985bb629c5SFabio Baltieri led_cdev->flags |= LED_BLINK_INVERT; 995bb629c5SFabio Baltieri else 1005bb629c5SFabio Baltieri led_cdev->flags &= ~LED_BLINK_INVERT; 1015bb629c5SFabio Baltieri 1025bb629c5SFabio Baltieri led_blink_setup(led_cdev, delay_on, delay_off); 1035bb629c5SFabio Baltieri } 1045bb629c5SFabio Baltieri EXPORT_SYMBOL(led_blink_set_oneshot); 1055bb629c5SFabio Baltieri 106*d23a22a7SFabio Baltieri void led_stop_software_blink(struct led_classdev *led_cdev) 107a403d930SBryan Wu { 10843786482SFabio Baltieri del_timer_sync(&led_cdev->blink_timer); 10943786482SFabio Baltieri led_cdev->blink_delay_on = 0; 11043786482SFabio Baltieri led_cdev->blink_delay_off = 0; 111*d23a22a7SFabio Baltieri } 112*d23a22a7SFabio Baltieri EXPORT_SYMBOL_GPL(led_stop_software_blink); 113*d23a22a7SFabio Baltieri 114*d23a22a7SFabio Baltieri void led_set_brightness(struct led_classdev *led_cdev, 115*d23a22a7SFabio Baltieri enum led_brightness brightness) 116*d23a22a7SFabio Baltieri { 117*d23a22a7SFabio Baltieri /* delay brightness setting if need to stop soft-blink timer */ 118*d23a22a7SFabio Baltieri if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) { 119*d23a22a7SFabio Baltieri led_cdev->delayed_set_value = brightness; 120*d23a22a7SFabio Baltieri schedule_work(&led_cdev->set_brightness_work); 121*d23a22a7SFabio Baltieri return; 122*d23a22a7SFabio Baltieri } 12343786482SFabio Baltieri 1240da3e65bSShuah Khan __led_set_brightness(led_cdev, brightness); 125a403d930SBryan Wu } 12619cd67e2SShuah Khan EXPORT_SYMBOL(led_set_brightness); 127