aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMárton Németh <nm127@freemail.hu>2007-10-31 10:07:12 -0400
committerRichard Purdie <rpurdie@rpsys.net>2008-02-07 04:49:38 -0500
commit4c79141d28bc290ae307e3f81f5bc909c26faf6e (patch)
tree9c6dc51c441dfc1c84cc27ece43087515c06967c
parent6c152beefbf90579d21afc4f7e075b1f801f9a75 (diff)
leds: Add support for hardware accelerated LED flashing
Extends the leds subsystem with a blink_set() callback function which can be optionally implemented by a LED driver. If implemented, the driver can use the hardware acceleration for blinking a LED. Signed-off-by: Márton Németh <nm127@freemail.hu> Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
-rw-r--r--Documentation/leds-class.txt24
-rw-r--r--drivers/leds/Kconfig6
-rw-r--r--drivers/leds/ledtrig-timer.c41
-rw-r--r--include/linux/leds.h5
4 files changed, 67 insertions, 9 deletions
diff --git a/Documentation/leds-class.txt b/Documentation/leds-class.txt
index 877af6efc18b..56757c751d6f 100644
--- a/Documentation/leds-class.txt
+++ b/Documentation/leds-class.txt
@@ -48,6 +48,26 @@ above leaves scope for further attributes should they be needed. If sections
48of the name don't apply, just leave that section blank. 48of the name don't apply, just leave that section blank.
49 49
50 50
51Hardware accelerated blink of LEDs
52==================================
53
54Some LEDs can be programmed to blink without any CPU interaction. To
55support this feature, a LED driver can optionally implement the
56blink_set() function (see <linux/leds.h>). If implemeted, triggers can
57attempt to use it before falling back to software timers. The blink_set()
58function should return 0 if the blink setting is supported, or -EINVAL
59otherwise, which means that LED blinking will be handled by software.
60
61The blink_set() function should choose a user friendly blinking
62value if it is called with *delay_on==0 && *delay_off==0 parameters. In
63this case the driver should give back the chosen value through delay_on
64and delay_off parameters to the leds subsystem.
65
66Any call to the brightness_set() callback function should cancel the
67previously programmed hardware blinking function so setting the brightness
68to 0 can also cancel the blinking of the LED.
69
70
51Known Issues 71Known Issues
52============ 72============
53 73
@@ -56,10 +76,6 @@ would cause nightmare dependency issues. I see this as a minor issue
56compared to the benefits the simple trigger functionality brings. The 76compared to the benefits the simple trigger functionality brings. The
57rest of the LED subsystem can be modular. 77rest of the LED subsystem can be modular.
58 78
59Some leds can be programmed to flash in hardware. As this isn't a generic
60LED device property, this should be exported as a device specific sysfs
61attribute rather than part of the class if this functionality is required.
62
63 79
64Future Development 80Future Development
65================== 81==================
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index cf3a6d4d9475..659448ead685 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -152,7 +152,11 @@ config LEDS_TRIGGER_TIMER
152 depends on LEDS_TRIGGERS 152 depends on LEDS_TRIGGERS
153 help 153 help
154 This allows LEDs to be controlled by a programmable timer 154 This allows LEDs to be controlled by a programmable timer
155 via sysfs. If unsure, say Y. 155 via sysfs. Some LED hardware can be programmed to start
156 blinking the LED without any further software interaction.
157 For more details read Documentation/leds-class.txt.
158
159 If unsure, say Y.
156 160
157config LEDS_TRIGGER_IDE_DISK 161config LEDS_TRIGGER_IDE_DISK
158 bool "LED IDE Disk Trigger" 162 bool "LED IDE Disk Trigger"
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index ed9ff02c77ea..82c55d6e4902 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -77,8 +77,21 @@ static ssize_t led_delay_on_store(struct device *dev,
77 count++; 77 count++;
78 78
79 if (count == size) { 79 if (count == size) {
80 timer_data->delay_on = state; 80 if (timer_data->delay_on != state) {
81 mod_timer(&timer_data->timer, jiffies + 1); 81 /* the new value differs from the previous */
82 timer_data->delay_on = state;
83
84 /* deactivate previous settings */
85 del_timer_sync(&timer_data->timer);
86
87 /* try to activate hardware acceleration, if any */
88 if (!led_cdev->blink_set ||
89 led_cdev->blink_set(led_cdev,
90 &timer_data->delay_on, &timer_data->delay_off)) {
91 /* no hardware acceleration, blink via timer */
92 mod_timer(&timer_data->timer, jiffies + 1);
93 }
94 }
82 ret = count; 95 ret = count;
83 } 96 }
84 97
@@ -110,8 +123,21 @@ static ssize_t led_delay_off_store(struct device *dev,
110 count++; 123 count++;
111 124
112 if (count == size) { 125 if (count == size) {
113 timer_data->delay_off = state; 126 if (timer_data->delay_off != state) {
114 mod_timer(&timer_data->timer, jiffies + 1); 127 /* the new value differs from the previous */
128 timer_data->delay_off = state;
129
130 /* deactivate previous settings */
131 del_timer_sync(&timer_data->timer);
132
133 /* try to activate hardware acceleration, if any */
134 if (!led_cdev->blink_set ||
135 led_cdev->blink_set(led_cdev,
136 &timer_data->delay_on, &timer_data->delay_off)) {
137 /* no hardware acceleration, blink via timer */
138 mod_timer(&timer_data->timer, jiffies + 1);
139 }
140 }
115 ret = count; 141 ret = count;
116 } 142 }
117 143
@@ -143,6 +169,13 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
143 if (rc) 169 if (rc)
144 goto err_out_delayon; 170 goto err_out_delayon;
145 171
172 /* If there is hardware support for blinking, start one
173 * user friendly blink rate chosen by the driver.
174 */
175 if (led_cdev->blink_set)
176 led_cdev->blink_set(led_cdev,
177 &timer_data->delay_on, &timer_data->delay_off);
178
146 return; 179 return;
147 180
148err_out_delayon: 181err_out_delayon:
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 00f89fd6c52a..0201f6f51cea 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -38,6 +38,11 @@ struct led_classdev {
38 void (*brightness_set)(struct led_classdev *led_cdev, 38 void (*brightness_set)(struct led_classdev *led_cdev,
39 enum led_brightness brightness); 39 enum led_brightness brightness);
40 40
41 /* Activate hardware accelerated blink */
42 int (*blink_set)(struct led_classdev *led_cdev,
43 unsigned long *delay_on,
44 unsigned long *delay_off);
45
41 struct device *dev; 46 struct device *dev;
42 struct list_head node; /* LED Device list */ 47 struct list_head node; /* LED Device list */
43 char *default_trigger; /* Trigger to use */ 48 char *default_trigger; /* Trigger to use */