diff options
-rw-r--r-- | Documentation/leds-class.txt | 24 | ||||
-rw-r--r-- | drivers/leds/Kconfig | 6 | ||||
-rw-r--r-- | drivers/leds/ledtrig-timer.c | 41 | ||||
-rw-r--r-- | include/linux/leds.h | 5 |
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 | |||
48 | of the name don't apply, just leave that section blank. | 48 | of the name don't apply, just leave that section blank. |
49 | 49 | ||
50 | 50 | ||
51 | Hardware accelerated blink of LEDs | ||
52 | ================================== | ||
53 | |||
54 | Some LEDs can be programmed to blink without any CPU interaction. To | ||
55 | support this feature, a LED driver can optionally implement the | ||
56 | blink_set() function (see <linux/leds.h>). If implemeted, triggers can | ||
57 | attempt to use it before falling back to software timers. The blink_set() | ||
58 | function should return 0 if the blink setting is supported, or -EINVAL | ||
59 | otherwise, which means that LED blinking will be handled by software. | ||
60 | |||
61 | The blink_set() function should choose a user friendly blinking | ||
62 | value if it is called with *delay_on==0 && *delay_off==0 parameters. In | ||
63 | this case the driver should give back the chosen value through delay_on | ||
64 | and delay_off parameters to the leds subsystem. | ||
65 | |||
66 | Any call to the brightness_set() callback function should cancel the | ||
67 | previously programmed hardware blinking function so setting the brightness | ||
68 | to 0 can also cancel the blinking of the LED. | ||
69 | |||
70 | |||
51 | Known Issues | 71 | Known Issues |
52 | ============ | 72 | ============ |
53 | 73 | ||
@@ -56,10 +76,6 @@ would cause nightmare dependency issues. I see this as a minor issue | |||
56 | compared to the benefits the simple trigger functionality brings. The | 76 | compared to the benefits the simple trigger functionality brings. The |
57 | rest of the LED subsystem can be modular. | 77 | rest of the LED subsystem can be modular. |
58 | 78 | ||
59 | Some leds can be programmed to flash in hardware. As this isn't a generic | ||
60 | LED device property, this should be exported as a device specific sysfs | ||
61 | attribute rather than part of the class if this functionality is required. | ||
62 | |||
63 | 79 | ||
64 | Future Development | 80 | Future 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 | ||
157 | config LEDS_TRIGGER_IDE_DISK | 161 | config 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 | ||
148 | err_out_delayon: | 181 | err_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 */ |