Commit 4c79141d authored by Márton Németh's avatar Márton Németh Committed by Richard Purdie

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: default avatarMárton Németh <nm127@freemail.hu>
Signed-off-by: default avatarRichard Purdie <rpurdie@rpsys.net>
parent 6c152bee
......@@ -48,6 +48,26 @@ above leaves scope for further attributes should they be needed. If sections
of the name don't apply, just leave that section blank.
Hardware accelerated blink of LEDs
==================================
Some LEDs can be programmed to blink without any CPU interaction. To
support this feature, a LED driver can optionally implement the
blink_set() function (see <linux/leds.h>). If implemeted, triggers can
attempt to use it before falling back to software timers. The blink_set()
function should return 0 if the blink setting is supported, or -EINVAL
otherwise, which means that LED blinking will be handled by software.
The blink_set() function should choose a user friendly blinking
value if it is called with *delay_on==0 && *delay_off==0 parameters. In
this case the driver should give back the chosen value through delay_on
and delay_off parameters to the leds subsystem.
Any call to the brightness_set() callback function should cancel the
previously programmed hardware blinking function so setting the brightness
to 0 can also cancel the blinking of the LED.
Known Issues
============
......@@ -56,10 +76,6 @@ would cause nightmare dependency issues. I see this as a minor issue
compared to the benefits the simple trigger functionality brings. The
rest of the LED subsystem can be modular.
Some leds can be programmed to flash in hardware. As this isn't a generic
LED device property, this should be exported as a device specific sysfs
attribute rather than part of the class if this functionality is required.
Future Development
==================
......
......@@ -152,7 +152,11 @@ config LEDS_TRIGGER_TIMER
depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled by a programmable timer
via sysfs. If unsure, say Y.
via sysfs. Some LED hardware can be programmed to start
blinking the LED without any further software interaction.
For more details read Documentation/leds-class.txt.
If unsure, say Y.
config LEDS_TRIGGER_IDE_DISK
bool "LED IDE Disk Trigger"
......
......@@ -77,8 +77,21 @@ static ssize_t led_delay_on_store(struct device *dev,
count++;
if (count == size) {
timer_data->delay_on = state;
mod_timer(&timer_data->timer, jiffies + 1);
if (timer_data->delay_on != state) {
/* the new value differs from the previous */
timer_data->delay_on = state;
/* deactivate previous settings */
del_timer_sync(&timer_data->timer);
/* try to activate hardware acceleration, if any */
if (!led_cdev->blink_set ||
led_cdev->blink_set(led_cdev,
&timer_data->delay_on, &timer_data->delay_off)) {
/* no hardware acceleration, blink via timer */
mod_timer(&timer_data->timer, jiffies + 1);
}
}
ret = count;
}
......@@ -110,8 +123,21 @@ static ssize_t led_delay_off_store(struct device *dev,
count++;
if (count == size) {
timer_data->delay_off = state;
mod_timer(&timer_data->timer, jiffies + 1);
if (timer_data->delay_off != state) {
/* the new value differs from the previous */
timer_data->delay_off = state;
/* deactivate previous settings */
del_timer_sync(&timer_data->timer);
/* try to activate hardware acceleration, if any */
if (!led_cdev->blink_set ||
led_cdev->blink_set(led_cdev,
&timer_data->delay_on, &timer_data->delay_off)) {
/* no hardware acceleration, blink via timer */
mod_timer(&timer_data->timer, jiffies + 1);
}
}
ret = count;
}
......@@ -143,6 +169,13 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
if (rc)
goto err_out_delayon;
/* If there is hardware support for blinking, start one
* user friendly blink rate chosen by the driver.
*/
if (led_cdev->blink_set)
led_cdev->blink_set(led_cdev,
&timer_data->delay_on, &timer_data->delay_off);
return;
err_out_delayon:
......
......@@ -38,6 +38,11 @@ struct led_classdev {
void (*brightness_set)(struct led_classdev *led_cdev,
enum led_brightness brightness);
/* Activate hardware accelerated blink */
int (*blink_set)(struct led_classdev *led_cdev,
unsigned long *delay_on,
unsigned long *delay_off);
struct device *dev;
struct list_head node; /* LED Device list */
char *default_trigger; /* Trigger to use */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment