Commit 0013b23d authored by Németh Márton's avatar Németh Márton Committed by Richard Purdie

leds: disable triggers on brightness set

Disable any active triggers when the brightness attribute is
set to zero.
Signed-off-by: default avatarHenrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: default avatarMárton Németh <nm127@freemail.hu>
Signed-off-by: default avatarRichard Purdie <rpurdie@rpsys.net>
parent b3ba31f8
...@@ -19,6 +19,12 @@ optimises away. ...@@ -19,6 +19,12 @@ optimises away.
Complex triggers whilst available to all LEDs have LED specific Complex triggers whilst available to all LEDs have LED specific
parameters and work on a per LED basis. The timer trigger is an example. parameters and work on a per LED basis. The timer trigger is an example.
The timer trigger will periodically change the LED brightness between
LED_OFF and the current brightness setting. The "on" and "off" time can
be specified via /sys/class/leds/<device>/delay_{on,off} in milliseconds.
You can change the brightness value of a LED independently of the timer
trigger. However, if you set the brightness value to LED_OFF it will
also disable the timer trigger.
You can change triggers in a similar manner to the way an IO scheduler You can change triggers in a similar manner to the way an IO scheduler
is chosen (via /sys/class/leds/<device>/trigger). Trigger specific is chosen (via /sys/class/leds/<device>/trigger). Trigger specific
...@@ -63,9 +69,9 @@ value if it is called with *delay_on==0 && *delay_off==0 parameters. In ...@@ -63,9 +69,9 @@ 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 this case the driver should give back the chosen value through delay_on
and delay_off parameters to the leds subsystem. and delay_off parameters to the leds subsystem.
Any call to the brightness_set() callback function should cancel the Setting the brightness to zero with brightness_set() callback function
previously programmed hardware blinking function so setting the brightness should completely turn off the LED and cancel the previously programmed
to 0 can also cancel the blinking of the LED. hardware blinking function, if any.
Known Issues Known Issues
......
...@@ -51,6 +51,9 @@ static ssize_t led_brightness_store(struct device *dev, ...@@ -51,6 +51,9 @@ static ssize_t led_brightness_store(struct device *dev,
if (count == size) { if (count == size) {
ret = count; ret = count;
if (state == LED_OFF)
led_trigger_remove(led_cdev);
led_set_brightness(led_cdev, state); led_set_brightness(led_cdev, state);
} }
......
...@@ -45,9 +45,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, ...@@ -45,9 +45,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
trigger_name[len - 1] = '\0'; trigger_name[len - 1] = '\0';
if (!strcmp(trigger_name, "none")) { if (!strcmp(trigger_name, "none")) {
down_write(&led_cdev->trigger_lock); led_trigger_remove(led_cdev);
led_trigger_set(led_cdev, NULL);
up_write(&led_cdev->trigger_lock);
return count; return count;
} }
...@@ -139,6 +137,13 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) ...@@ -139,6 +137,13 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
led_cdev->trigger = trigger; led_cdev->trigger = trigger;
} }
void led_trigger_remove(struct led_classdev *led_cdev)
{
down_write(&led_cdev->trigger_lock);
led_trigger_set(led_cdev, NULL);
up_write(&led_cdev->trigger_lock);
}
void led_trigger_set_default(struct led_classdev *led_cdev) void led_trigger_set_default(struct led_classdev *led_cdev)
{ {
struct led_trigger *trig; struct led_trigger *trig;
...@@ -231,6 +236,7 @@ void led_trigger_unregister_simple(struct led_trigger *trigger) ...@@ -231,6 +236,7 @@ void led_trigger_unregister_simple(struct led_trigger *trigger)
/* Used by LED Class */ /* Used by LED Class */
EXPORT_SYMBOL_GPL(led_trigger_set); EXPORT_SYMBOL_GPL(led_trigger_set);
EXPORT_SYMBOL_GPL(led_trigger_remove);
EXPORT_SYMBOL_GPL(led_trigger_set_default); EXPORT_SYMBOL_GPL(led_trigger_set_default);
EXPORT_SYMBOL_GPL(led_trigger_show); EXPORT_SYMBOL_GPL(led_trigger_show);
EXPORT_SYMBOL_GPL(led_trigger_store); EXPORT_SYMBOL_GPL(led_trigger_store);
......
...@@ -27,6 +27,11 @@ static inline void led_set_brightness(struct led_classdev *led_cdev, ...@@ -27,6 +27,11 @@ static inline void led_set_brightness(struct led_classdev *led_cdev,
led_cdev->brightness_set(led_cdev, value); led_cdev->brightness_set(led_cdev, value);
} }
static inline int led_get_brightness(struct led_classdev *led_cdev)
{
return led_cdev->brightness;
}
extern struct rw_semaphore leds_list_lock; extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list; extern struct list_head leds_list;
...@@ -34,9 +39,11 @@ extern struct list_head leds_list; ...@@ -34,9 +39,11 @@ extern struct list_head leds_list;
void led_trigger_set_default(struct led_classdev *led_cdev); void led_trigger_set_default(struct led_classdev *led_cdev);
void led_trigger_set(struct led_classdev *led_cdev, void led_trigger_set(struct led_classdev *led_cdev,
struct led_trigger *trigger); struct led_trigger *trigger);
void led_trigger_remove(struct led_classdev *led_cdev);
#else #else
#define led_trigger_set_default(x) do {} while(0) #define led_trigger_set_default(x) do {} while(0)
#define led_trigger_set(x, y) do {} while(0) #define led_trigger_set(x, y) do {} while(0)
#define led_trigger_remove(x) do {} while(0)
#endif #endif
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
......
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
#include "leds.h" #include "leds.h"
struct timer_trig_data { struct timer_trig_data {
int brightness_on; /* LED brightness during "on" period.
* (LED_OFF < brightness_on <= LED_FULL)
*/
unsigned long delay_on; /* milliseconds on */ unsigned long delay_on; /* milliseconds on */
unsigned long delay_off; /* milliseconds off */ unsigned long delay_off; /* milliseconds off */
struct timer_list timer; struct timer_list timer;
...@@ -34,17 +37,26 @@ static void led_timer_function(unsigned long data) ...@@ -34,17 +37,26 @@ static void led_timer_function(unsigned long data)
{ {
struct led_classdev *led_cdev = (struct led_classdev *) data; struct led_classdev *led_cdev = (struct led_classdev *) data;
struct timer_trig_data *timer_data = led_cdev->trigger_data; struct timer_trig_data *timer_data = led_cdev->trigger_data;
unsigned long brightness = LED_OFF; unsigned long brightness;
unsigned long delay = timer_data->delay_off; unsigned long delay;
if (!timer_data->delay_on || !timer_data->delay_off) { if (!timer_data->delay_on || !timer_data->delay_off) {
led_set_brightness(led_cdev, LED_OFF); led_set_brightness(led_cdev, LED_OFF);
return; return;
} }
if (!led_cdev->brightness) { brightness = led_get_brightness(led_cdev);
brightness = LED_FULL; if (!brightness) {
/* Time to switch the LED on. */
brightness = timer_data->brightness_on;
delay = timer_data->delay_on; delay = timer_data->delay_on;
} else {
/* Store the current brightness value to be able
* to restore it when the delay_off period is over.
*/
timer_data->brightness_on = brightness;
brightness = LED_OFF;
delay = timer_data->delay_off;
} }
led_set_brightness(led_cdev, brightness); led_set_brightness(led_cdev, brightness);
...@@ -156,6 +168,9 @@ static void timer_trig_activate(struct led_classdev *led_cdev) ...@@ -156,6 +168,9 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
if (!timer_data) if (!timer_data)
return; return;
timer_data->brightness_on = led_get_brightness(led_cdev);
if (timer_data->brightness_on == LED_OFF)
timer_data->brightness_on = LED_FULL;
led_cdev->trigger_data = timer_data; led_cdev->trigger_data = timer_data;
init_timer(&timer_data->timer); init_timer(&timer_data->timer);
......
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