diff options
| author | Márton Németh <nm127@freemail.hu> | 2007-10-31 10:07:12 -0400 |
|---|---|---|
| committer | Richard Purdie <rpurdie@rpsys.net> | 2008-02-07 04:49:38 -0500 |
| commit | 4c79141d28bc290ae307e3f81f5bc909c26faf6e (patch) | |
| tree | 9c6dc51c441dfc1c84cc27ece43087515c06967c | |
| parent | 6c152beefbf90579d21afc4f7e075b1f801f9a75 (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.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 */ |
