aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabio Baltieri <fabio.baltieri@gmail.com>2012-05-26 19:19:22 -0400
committerBryan Wu <bryan.wu@canonical.com>2012-07-23 19:52:34 -0400
commit5bb629c504394f4d42c53a25d75ccb02a393f92f (patch)
treec504fb776de83b95045d3274cd7bc82cee0bc983
parenteb202621f8c0fb264a35e1b35fc00bdb3114a897 (diff)
leds: add oneshot blink functions
Add two new functions, led_blink_set_oneshot and led_trigger_blink_oneshot, to be used by triggers for one-shot blink of led devices. This is implemented extending the existing software-blink code, and uses the same timer and handler function. The behavior of the code is to do a blink-on, blink-off sequence when the function is called, ignoring other calls until the sequence is completed so that the leds keep blinking at constant rate if the functions are called repeatedly. This is meant to be used by drivers which needs to trigger on sporadic event, but doesn't have clear busy/idle trigger points. After the blink sequence the led remains off. This behavior can be inverted setting the "invert" argument, which blink the led off, than on and leave the led on after the sequence. (bryan.wu@canonical.com: rebase to commit 'leds: don't disable blinking when writing the same value to delay_on or delay_off') Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com> Acked-by: Shuah Khan <shuahkhan@gmail.com> Signed-off-by: Bryan Wu <bryan.wu@canonical.com>
-rw-r--r--drivers/leds/led-class.c19
-rw-r--r--drivers/leds/led-core.c45
-rw-r--r--drivers/leds/led-triggers.c30
-rw-r--r--include/linux/leds.h25
4 files changed, 108 insertions, 11 deletions
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index e663e6f413e9..81eb0916b44a 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -86,6 +86,11 @@ static void led_timer_function(unsigned long data)
86 return; 86 return;
87 } 87 }
88 88
89 if (led_cdev->flags & LED_BLINK_ONESHOT_STOP) {
90 led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
91 return;
92 }
93
89 brightness = led_get_brightness(led_cdev); 94 brightness = led_get_brightness(led_cdev);
90 if (!brightness) { 95 if (!brightness) {
91 /* Time to switch the LED on. */ 96 /* Time to switch the LED on. */
@@ -102,6 +107,20 @@ static void led_timer_function(unsigned long data)
102 107
103 led_set_brightness(led_cdev, brightness); 108 led_set_brightness(led_cdev, brightness);
104 109
110 /* Return in next iteration if led is in one-shot mode and we are in
111 * the final blink state so that the led is toggled each delay_on +
112 * delay_off milliseconds in worst case.
113 */
114 if (led_cdev->flags & LED_BLINK_ONESHOT) {
115 if (led_cdev->flags & LED_BLINK_INVERT) {
116 if (brightness)
117 led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
118 } else {
119 if (!brightness)
120 led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
121 }
122 }
123
105 mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay)); 124 mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
106} 125}
107 126
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index d65353d8d3fc..a6f4d910ca08 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -27,7 +27,6 @@ EXPORT_SYMBOL_GPL(leds_list);
27static void led_stop_software_blink(struct led_classdev *led_cdev) 27static void led_stop_software_blink(struct led_classdev *led_cdev)
28{ 28{
29 /* deactivate previous settings */ 29 /* deactivate previous settings */
30 del_timer_sync(&led_cdev->blink_timer);
31 led_cdev->blink_delay_on = 0; 30 led_cdev->blink_delay_on = 0;
32 led_cdev->blink_delay_off = 0; 31 led_cdev->blink_delay_off = 0;
33} 32}
@@ -61,13 +60,12 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
61} 60}
62 61
63 62
64void led_blink_set(struct led_classdev *led_cdev, 63void led_blink_setup(struct led_classdev *led_cdev,
65 unsigned long *delay_on, 64 unsigned long *delay_on,
66 unsigned long *delay_off) 65 unsigned long *delay_off)
67{ 66{
68 del_timer_sync(&led_cdev->blink_timer); 67 if (!(led_cdev->flags & LED_BLINK_ONESHOT) &&
69 68 led_cdev->blink_set &&
70 if (led_cdev->blink_set &&
71 !led_cdev->blink_set(led_cdev, delay_on, delay_off)) 69 !led_cdev->blink_set(led_cdev, delay_on, delay_off))
72 return; 70 return;
73 71
@@ -77,8 +75,41 @@ void led_blink_set(struct led_classdev *led_cdev,
77 75
78 led_set_software_blink(led_cdev, *delay_on, *delay_off); 76 led_set_software_blink(led_cdev, *delay_on, *delay_off);
79} 77}
78
79void led_blink_set(struct led_classdev *led_cdev,
80 unsigned long *delay_on,
81 unsigned long *delay_off)
82{
83 del_timer_sync(&led_cdev->blink_timer);
84
85 led_cdev->flags &= ~LED_BLINK_ONESHOT;
86 led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
87
88 led_blink_setup(led_cdev, delay_on, delay_off);
89}
80EXPORT_SYMBOL(led_blink_set); 90EXPORT_SYMBOL(led_blink_set);
81 91
92void led_blink_set_oneshot(struct led_classdev *led_cdev,
93 unsigned long *delay_on,
94 unsigned long *delay_off,
95 int invert)
96{
97 if ((led_cdev->flags & LED_BLINK_ONESHOT) &&
98 timer_pending(&led_cdev->blink_timer))
99 return;
100
101 led_cdev->flags |= LED_BLINK_ONESHOT;
102 led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
103
104 if (invert)
105 led_cdev->flags |= LED_BLINK_INVERT;
106 else
107 led_cdev->flags &= ~LED_BLINK_INVERT;
108
109 led_blink_setup(led_cdev, delay_on, delay_off);
110}
111EXPORT_SYMBOL(led_blink_set_oneshot);
112
82void led_brightness_set(struct led_classdev *led_cdev, 113void led_brightness_set(struct led_classdev *led_cdev,
83 enum led_brightness brightness) 114 enum led_brightness brightness)
84{ 115{
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index b449ed8d8712..fa0b9be019ea 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -230,9 +230,11 @@ void led_trigger_event(struct led_trigger *trig,
230} 230}
231EXPORT_SYMBOL_GPL(led_trigger_event); 231EXPORT_SYMBOL_GPL(led_trigger_event);
232 232
233void led_trigger_blink(struct led_trigger *trig, 233void led_trigger_blink_setup(struct led_trigger *trig,
234 unsigned long *delay_on, 234 unsigned long *delay_on,
235 unsigned long *delay_off) 235 unsigned long *delay_off,
236 int oneshot,
237 int invert)
236{ 238{
237 struct list_head *entry; 239 struct list_head *entry;
238 240
@@ -244,12 +246,32 @@ void led_trigger_blink(struct led_trigger *trig,
244 struct led_classdev *led_cdev; 246 struct led_classdev *led_cdev;
245 247
246 led_cdev = list_entry(entry, struct led_classdev, trig_list); 248 led_cdev = list_entry(entry, struct led_classdev, trig_list);
247 led_blink_set(led_cdev, delay_on, delay_off); 249 if (oneshot)
250 led_blink_set_oneshot(led_cdev, delay_on, delay_off,
251 invert);
252 else
253 led_blink_set(led_cdev, delay_on, delay_off);
248 } 254 }
249 read_unlock(&trig->leddev_list_lock); 255 read_unlock(&trig->leddev_list_lock);
250} 256}
257
258void led_trigger_blink(struct led_trigger *trig,
259 unsigned long *delay_on,
260 unsigned long *delay_off)
261{
262 led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
263}
251EXPORT_SYMBOL_GPL(led_trigger_blink); 264EXPORT_SYMBOL_GPL(led_trigger_blink);
252 265
266void led_trigger_blink_oneshot(struct led_trigger *trig,
267 unsigned long *delay_on,
268 unsigned long *delay_off,
269 int invert)
270{
271 led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
272}
273EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
274
253void led_trigger_register_simple(const char *name, struct led_trigger **tp) 275void led_trigger_register_simple(const char *name, struct led_trigger **tp)
254{ 276{
255 struct led_trigger *trig; 277 struct led_trigger *trig;
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 39eee41d8c6f..dd93a22044bb 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -38,6 +38,9 @@ struct led_classdev {
38#define LED_SUSPENDED (1 << 0) 38#define LED_SUSPENDED (1 << 0)
39 /* Upper 16 bits reflect control information */ 39 /* Upper 16 bits reflect control information */
40#define LED_CORE_SUSPENDRESUME (1 << 16) 40#define LED_CORE_SUSPENDRESUME (1 << 16)
41#define LED_BLINK_ONESHOT (1 << 17)
42#define LED_BLINK_ONESHOT_STOP (1 << 18)
43#define LED_BLINK_INVERT (1 << 19)
41 44
42 /* Set LED brightness level */ 45 /* Set LED brightness level */
43 /* Must not sleep, use a workqueue if needed */ 46 /* Must not sleep, use a workqueue if needed */
@@ -103,6 +106,24 @@ extern void led_blink_set(struct led_classdev *led_cdev,
103 unsigned long *delay_on, 106 unsigned long *delay_on,
104 unsigned long *delay_off); 107 unsigned long *delay_off);
105/** 108/**
109 * led_blink_set_oneshot - do a oneshot software blink
110 * @led_cdev: the LED to start blinking
111 * @delay_on: the time it should be on (in ms)
112 * @delay_off: the time it should ble off (in ms)
113 * @invert: blink off, then on, leaving the led on
114 *
115 * This function makes the LED blink one time for delay_on +
116 * delay_off time, ignoring the request if another one-shot
117 * blink is already in progress.
118 *
119 * If invert is set, led blinks for delay_off first, then for
120 * delay_on and leave the led on after the on-off cycle.
121 */
122extern void led_blink_set_oneshot(struct led_classdev *led_cdev,
123 unsigned long *delay_on,
124 unsigned long *delay_off,
125 int invert);
126/**
106 * led_brightness_set - set LED brightness 127 * led_brightness_set - set LED brightness
107 * @led_cdev: the LED to set 128 * @led_cdev: the LED to set
108 * @brightness: the brightness to set it to 129 * @brightness: the brightness to set it to
@@ -150,6 +171,10 @@ extern void led_trigger_event(struct led_trigger *trigger,
150extern void led_trigger_blink(struct led_trigger *trigger, 171extern void led_trigger_blink(struct led_trigger *trigger,
151 unsigned long *delay_on, 172 unsigned long *delay_on,
152 unsigned long *delay_off); 173 unsigned long *delay_off);
174extern void led_trigger_blink_oneshot(struct led_trigger *trigger,
175 unsigned long *delay_on,
176 unsigned long *delay_off,
177 int invert);
153 178
154#else 179#else
155 180