aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-04-13 17:29:07 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-04-13 17:29:07 -0400
commitf499cae1e59d75d5eb24c23d47cf8986e6032c6d (patch)
tree1af6235c18391212c40116eb90b01eae8938efee /drivers/leds
parentfc3f55e672e1ed917dd9e215af81939cd3d717da (diff)
parent80a04d3f2f94fb68b5df05e3ac6697130bc3467a (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig75
-rw-r--r--drivers/leds/Makefile7
-rw-r--r--drivers/leds/led-class.c21
-rw-r--r--drivers/leds/led-triggers.c10
-rw-r--r--drivers/leds/leds-bd2802.c765
-rw-r--r--drivers/leds/leds-dac124s085.c150
-rw-r--r--drivers/leds/leds-gpio.c225
-rw-r--r--drivers/leds/leds-h1940.c2
-rw-r--r--drivers/leds/leds-pca9532.c2
-rw-r--r--drivers/leds/leds-pwm.c153
-rw-r--r--drivers/leds/leds-rb532.c77
-rw-r--r--drivers/leds/leds-s3c24xx.c7
-rw-r--r--drivers/leds/leds.h4
-rw-r--r--drivers/leds/ledtrig-default-on.c2
-rw-r--r--drivers/leds/ledtrig-gpio.c239
-rw-r--r--drivers/leds/ledtrig-heartbeat.c4
-rw-r--r--drivers/leds/ledtrig-ide-disk.c3
-rw-r--r--drivers/leds/ledtrig-timer.c2
18 files changed, 1685 insertions, 63 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index d9db17624f12..9b60b6b684d9 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -31,6 +31,13 @@ config LEDS_LOCOMO
31 This option enables support for the LEDs on Sharp Locomo. 31 This option enables support for the LEDs on Sharp Locomo.
32 Zaurus models SL-5500 and SL-5600. 32 Zaurus models SL-5500 and SL-5600.
33 33
34config LEDS_MIKROTIK_RB532
35 tristate "LED Support for Mikrotik Routerboard 532"
36 depends on LEDS_CLASS && MIKROTIK_RB532
37 help
38 This option enables support for the so called "User LED" of
39 Mikrotik's Routerboard 532.
40
34config LEDS_S3C24XX 41config LEDS_S3C24XX
35 tristate "LED Support for Samsung S3C24XX GPIO LEDs" 42 tristate "LED Support for Samsung S3C24XX GPIO LEDs"
36 depends on LEDS_CLASS && ARCH_S3C2410 43 depends on LEDS_CLASS && ARCH_S3C2410
@@ -117,11 +124,40 @@ config LEDS_GPIO
117 help 124 help
118 This option enables support for the LEDs connected to GPIO 125 This option enables support for the LEDs connected to GPIO
119 outputs. To be useful the particular board must have LEDs 126 outputs. To be useful the particular board must have LEDs
120 and they must be connected to the GPIO lines. 127 and they must be connected to the GPIO lines. The LEDs must be
128 defined as platform devices and/or OpenFirmware platform devices.
129 The code to use these bindings can be selected below.
130
131config LEDS_GPIO_PLATFORM
132 bool "Platform device bindings for GPIO LEDs"
133 depends on LEDS_GPIO
134 default y
135 help
136 Let the leds-gpio driver drive LEDs which have been defined as
137 platform devices. If you don't know what this means, say yes.
138
139config LEDS_GPIO_OF
140 bool "OpenFirmware platform device bindings for GPIO LEDs"
141 depends on LEDS_GPIO && OF_DEVICE
142 default y
143 help
144 Let the leds-gpio driver drive LEDs which have been defined as
145 of_platform devices. For instance, LEDs which are listed in a "dts"
146 file.
147
148config LEDS_LP5521
149 tristate "LED Support for the LP5521 LEDs"
150 depends on LEDS_CLASS && I2C
151 help
152 If you say 'Y' here you get support for the National Semiconductor
153 LP5521 LED driver used in n8x0 boards.
154
155 This driver can be built as a module by choosing 'M'. The module
156 will be called leds-lp5521.
121 157
122config LEDS_CLEVO_MAIL 158config LEDS_CLEVO_MAIL
123 tristate "Mail LED on Clevo notebook (EXPERIMENTAL)" 159 tristate "Mail LED on Clevo notebook"
124 depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI && EXPERIMENTAL 160 depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI
125 help 161 help
126 This driver makes the mail LED accessible from userspace 162 This driver makes the mail LED accessible from userspace
127 programs through the leds subsystem. This LED have three 163 programs through the leds subsystem. This LED have three
@@ -171,6 +207,26 @@ config LEDS_DA903X
171 This option enables support for on-chip LED drivers found 207 This option enables support for on-chip LED drivers found
172 on Dialog Semiconductor DA9030/DA9034 PMICs. 208 on Dialog Semiconductor DA9030/DA9034 PMICs.
173 209
210config LEDS_DAC124S085
211 tristate "LED Support for DAC124S085 SPI DAC"
212 depends on LEDS_CLASS && SPI
213 help
214 This option enables support for DAC124S085 SPI DAC from NatSemi,
215 which can be used to control up to four LEDs.
216
217config LEDS_PWM
218 tristate "PWM driven LED Support"
219 depends on LEDS_CLASS && HAVE_PWM
220 help
221 This option enables support for pwm driven LEDs
222
223config LEDS_BD2802
224 tristate "LED driver for BD2802 RGB LED"
225 depends on LEDS_CLASS && I2C
226 help
227 This option enables support for BD2802GU RGB LED driver chips
228 accessed via the I2C bus.
229
174comment "LED Triggers" 230comment "LED Triggers"
175 231
176config LEDS_TRIGGERS 232config LEDS_TRIGGERS
@@ -216,6 +272,19 @@ config LEDS_TRIGGER_BACKLIGHT
216 272
217 If unsure, say N. 273 If unsure, say N.
218 274
275config LEDS_TRIGGER_GPIO
276 tristate "LED GPIO Trigger"
277 depends on LEDS_TRIGGERS
278 depends on GPIOLIB
279 help
280 This allows LEDs to be controlled by gpio events. It's good
281 when using gpios as switches and triggering the needed LEDs
282 from there. One use case is n810's keypad LEDs that could
283 be triggered by this trigger when user slides up to show
284 keypad.
285
286 If unsure, say N.
287
219config LEDS_TRIGGER_DEFAULT_ON 288config LEDS_TRIGGER_DEFAULT_ON
220 tristate "LED Default ON Trigger" 289 tristate "LED Default ON Trigger"
221 depends on LEDS_TRIGGERS 290 depends on LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 9d76f0f160a4..2d41c4dcf92f 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -6,7 +6,9 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
6 6
7# LED Platform Drivers 7# LED Platform Drivers
8obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o 8obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
9obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
9obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o 10obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
11obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
10obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o 12obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
11obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o 13obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
12obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o 14obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
@@ -24,10 +26,15 @@ obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
24obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o 26obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o
25obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o 27obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
26obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o 28obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
29obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
30
31# LED SPI Drivers
32obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
27 33
28# LED Triggers 34# LED Triggers
29obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o 35obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
30obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o 36obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
31obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o 37obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
32obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o 38obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
39obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o
33obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o 40obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 52f82e3ea13a..f2cc13d76810 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -64,7 +64,16 @@ static ssize_t led_brightness_store(struct device *dev,
64 return ret; 64 return ret;
65} 65}
66 66
67static ssize_t led_max_brightness_show(struct device *dev,
68 struct device_attribute *attr, char *buf)
69{
70 struct led_classdev *led_cdev = dev_get_drvdata(dev);
71
72 return sprintf(buf, "%u\n", led_cdev->max_brightness);
73}
74
67static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store); 75static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
76static DEVICE_ATTR(max_brightness, 0444, led_max_brightness_show, NULL);
68#ifdef CONFIG_LEDS_TRIGGERS 77#ifdef CONFIG_LEDS_TRIGGERS
69static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store); 78static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
70#endif 79#endif
@@ -138,6 +147,13 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
138 list_add_tail(&led_cdev->node, &leds_list); 147 list_add_tail(&led_cdev->node, &leds_list);
139 up_write(&leds_list_lock); 148 up_write(&leds_list_lock);
140 149
150 if (!led_cdev->max_brightness)
151 led_cdev->max_brightness = LED_FULL;
152
153 rc = device_create_file(led_cdev->dev, &dev_attr_max_brightness);
154 if (rc)
155 goto err_out_attr_max;
156
141 led_update_brightness(led_cdev); 157 led_update_brightness(led_cdev);
142 158
143#ifdef CONFIG_LEDS_TRIGGERS 159#ifdef CONFIG_LEDS_TRIGGERS
@@ -155,9 +171,11 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
155 171
156#ifdef CONFIG_LEDS_TRIGGERS 172#ifdef CONFIG_LEDS_TRIGGERS
157err_out_led_list: 173err_out_led_list:
174 device_remove_file(led_cdev->dev, &dev_attr_max_brightness);
175#endif
176err_out_attr_max:
158 device_remove_file(led_cdev->dev, &dev_attr_brightness); 177 device_remove_file(led_cdev->dev, &dev_attr_brightness);
159 list_del(&led_cdev->node); 178 list_del(&led_cdev->node);
160#endif
161err_out: 179err_out:
162 device_unregister(led_cdev->dev); 180 device_unregister(led_cdev->dev);
163 return rc; 181 return rc;
@@ -172,6 +190,7 @@ EXPORT_SYMBOL_GPL(led_classdev_register);
172 */ 190 */
173void led_classdev_unregister(struct led_classdev *led_cdev) 191void led_classdev_unregister(struct led_classdev *led_cdev)
174{ 192{
193 device_remove_file(led_cdev->dev, &dev_attr_max_brightness);
175 device_remove_file(led_cdev->dev, &dev_attr_brightness); 194 device_remove_file(led_cdev->dev, &dev_attr_brightness);
176#ifdef CONFIG_LEDS_TRIGGERS 195#ifdef CONFIG_LEDS_TRIGGERS
177 device_remove_file(led_cdev->dev, &dev_attr_trigger); 196 device_remove_file(led_cdev->dev, &dev_attr_trigger);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index f910eaffe3a6..d8ddd9ef8994 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -156,12 +156,20 @@ EXPORT_SYMBOL_GPL(led_trigger_set_default);
156int led_trigger_register(struct led_trigger *trigger) 156int led_trigger_register(struct led_trigger *trigger)
157{ 157{
158 struct led_classdev *led_cdev; 158 struct led_classdev *led_cdev;
159 struct led_trigger *trig;
159 160
160 rwlock_init(&trigger->leddev_list_lock); 161 rwlock_init(&trigger->leddev_list_lock);
161 INIT_LIST_HEAD(&trigger->led_cdevs); 162 INIT_LIST_HEAD(&trigger->led_cdevs);
162 163
163 /* Add to the list of led triggers */
164 down_write(&triggers_list_lock); 164 down_write(&triggers_list_lock);
165 /* Make sure the trigger's name isn't already in use */
166 list_for_each_entry(trig, &trigger_list, next_trig) {
167 if (!strcmp(trig->name, trigger->name)) {
168 up_write(&triggers_list_lock);
169 return -EEXIST;
170 }
171 }
172 /* Add to the list of led triggers */
165 list_add_tail(&trigger->next_trig, &trigger_list); 173 list_add_tail(&trigger->next_trig, &trigger_list);
166 up_write(&triggers_list_lock); 174 up_write(&triggers_list_lock);
167 175
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
new file mode 100644
index 000000000000..4149ecb3a9b2
--- /dev/null
+++ b/drivers/leds/leds-bd2802.c
@@ -0,0 +1,765 @@
1/*
2 * leds-bd2802.c - RGB LED Driver
3 *
4 * Copyright (C) 2009 Samsung Electronics
5 * Kim Kyuwon <q1.kim@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/i2c.h>
17#include <linux/gpio.h>
18#include <linux/delay.h>
19#include <linux/leds.h>
20#include <linux/leds-bd2802.h>
21
22
23#define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0))
24
25#define BD2802_LED_OFFSET 0xa
26#define BD2802_COLOR_OFFSET 0x3
27
28#define BD2802_REG_CLKSETUP 0x00
29#define BD2802_REG_CONTROL 0x01
30#define BD2802_REG_HOURSETUP 0x02
31#define BD2802_REG_CURRENT1SETUP 0x03
32#define BD2802_REG_CURRENT2SETUP 0x04
33#define BD2802_REG_WAVEPATTERN 0x05
34
35#define BD2802_CURRENT_032 0x10 /* 3.2mA */
36#define BD2802_CURRENT_000 0x00 /* 0.0mA */
37
38#define BD2802_PATTERN_FULL 0x07
39#define BD2802_PATTERN_HALF 0x03
40
41enum led_ids {
42 LED1,
43 LED2,
44 LED_NUM,
45};
46
47enum led_colors {
48 RED,
49 GREEN,
50 BLUE,
51};
52
53enum led_bits {
54 BD2802_OFF,
55 BD2802_BLINK,
56 BD2802_ON,
57};
58
59/*
60 * State '0' : 'off'
61 * State '1' : 'blink'
62 * State '2' : 'on'.
63 */
64struct led_state {
65 unsigned r:2;
66 unsigned g:2;
67 unsigned b:2;
68};
69
70struct bd2802_led {
71 struct bd2802_led_platform_data *pdata;
72 struct i2c_client *client;
73 struct rw_semaphore rwsem;
74 struct work_struct work;
75
76 struct led_state led[2];
77
78 /*
79 * Making led_classdev as array is not recommended, because array
80 * members prevent using 'container_of' macro. So repetitive works
81 * are needed.
82 */
83 struct led_classdev cdev_led1r;
84 struct led_classdev cdev_led1g;
85 struct led_classdev cdev_led1b;
86 struct led_classdev cdev_led2r;
87 struct led_classdev cdev_led2g;
88 struct led_classdev cdev_led2b;
89
90 /*
91 * Advanced Configuration Function(ADF) mode:
92 * In ADF mode, user can set registers of BD2802GU directly,
93 * therefore BD2802GU doesn't enter reset state.
94 */
95 int adf_on;
96
97 enum led_ids led_id;
98 enum led_colors color;
99 enum led_bits state;
100};
101
102
103/*--------------------------------------------------------------*/
104/* BD2802GU helper functions */
105/*--------------------------------------------------------------*/
106
107static inline int bd2802_is_rgb_off(struct bd2802_led *led, enum led_ids id,
108 enum led_colors color)
109{
110 switch (color) {
111 case RED:
112 return !led->led[id].r;
113 case GREEN:
114 return !led->led[id].g;
115 case BLUE:
116 return !led->led[id].b;
117 default:
118 dev_err(&led->client->dev, "%s: Invalid color\n", __func__);
119 return -EINVAL;
120 }
121}
122
123static inline int bd2802_is_led_off(struct bd2802_led *led, enum led_ids id)
124{
125 if (led->led[id].r || led->led[id].g || led->led[id].b)
126 return 0;
127
128 return 1;
129}
130
131static inline int bd2802_is_all_off(struct bd2802_led *led)
132{
133 int i;
134
135 for (i = 0; i < LED_NUM; i++)
136 if (!bd2802_is_led_off(led, i))
137 return 0;
138
139 return 1;
140}
141
142static inline u8 bd2802_get_base_offset(enum led_ids id, enum led_colors color)
143{
144 return id * BD2802_LED_OFFSET + color * BD2802_COLOR_OFFSET;
145}
146
147static inline u8 bd2802_get_reg_addr(enum led_ids id, enum led_colors color,
148 u8 reg_offset)
149{
150 return reg_offset + bd2802_get_base_offset(id, color);
151}
152
153
154/*--------------------------------------------------------------*/
155/* BD2802GU core functions */
156/*--------------------------------------------------------------*/
157
158static int bd2802_write_byte(struct i2c_client *client, u8 reg, u8 val)
159{
160 int ret = i2c_smbus_write_byte_data(client, reg, val);
161 if (ret >= 0)
162 return 0;
163
164 dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
165 __func__, reg, val, ret);
166
167 return ret;
168}
169
170static void bd2802_update_state(struct bd2802_led *led, enum led_ids id,
171 enum led_colors color, enum led_bits led_bit)
172{
173 int i;
174 u8 value;
175
176 for (i = 0; i < LED_NUM; i++) {
177 if (i == id) {
178 switch (color) {
179 case RED:
180 led->led[i].r = led_bit;
181 break;
182 case GREEN:
183 led->led[i].g = led_bit;
184 break;
185 case BLUE:
186 led->led[i].b = led_bit;
187 break;
188 default:
189 dev_err(&led->client->dev,
190 "%s: Invalid color\n", __func__);
191 return;
192 }
193 }
194 }
195
196 if (led_bit == BD2802_BLINK || led_bit == BD2802_ON)
197 return;
198
199 if (!bd2802_is_led_off(led, id))
200 return;
201
202 if (bd2802_is_all_off(led) && !led->adf_on) {
203 gpio_set_value(led->pdata->reset_gpio, 0);
204 return;
205 }
206
207 /*
208 * In this case, other led is turned on, and current led is turned
209 * off. So set RGB LED Control register to stop the current RGB LED
210 */
211 value = (id == LED1) ? LED_CTL(1, 0) : LED_CTL(0, 1);
212 bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
213}
214
215static void bd2802_configure(struct bd2802_led *led)
216{
217 struct bd2802_led_platform_data *pdata = led->pdata;
218 u8 reg;
219
220 reg = bd2802_get_reg_addr(LED1, RED, BD2802_REG_HOURSETUP);
221 bd2802_write_byte(led->client, reg, pdata->rgb_time);
222
223 reg = bd2802_get_reg_addr(LED2, RED, BD2802_REG_HOURSETUP);
224 bd2802_write_byte(led->client, reg, pdata->rgb_time);
225}
226
227static void bd2802_reset_cancel(struct bd2802_led *led)
228{
229 gpio_set_value(led->pdata->reset_gpio, 1);
230 udelay(100);
231 bd2802_configure(led);
232}
233
234static void bd2802_enable(struct bd2802_led *led, enum led_ids id)
235{
236 enum led_ids other_led = (id == LED1) ? LED2 : LED1;
237 u8 value, other_led_on;
238
239 other_led_on = !bd2802_is_led_off(led, other_led);
240 if (id == LED1)
241 value = LED_CTL(other_led_on, 1);
242 else
243 value = LED_CTL(1 , other_led_on);
244
245 bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
246}
247
248static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
249 enum led_colors color)
250{
251 u8 reg;
252
253 if (bd2802_is_all_off(led) && !led->adf_on)
254 bd2802_reset_cancel(led);
255
256 reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
257 bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
258 reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
259 bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
260 reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
261 bd2802_write_byte(led->client, reg, BD2802_PATTERN_FULL);
262
263 bd2802_enable(led, id);
264 bd2802_update_state(led, id, color, BD2802_ON);
265}
266
267static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
268 enum led_colors color)
269{
270 u8 reg;
271
272 if (bd2802_is_all_off(led) && !led->adf_on)
273 bd2802_reset_cancel(led);
274
275 reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
276 bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
277 reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
278 bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
279 reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
280 bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF);
281
282 bd2802_enable(led, id);
283 bd2802_update_state(led, id, color, BD2802_BLINK);
284}
285
286static void bd2802_turn_on(struct bd2802_led *led, enum led_ids id,
287 enum led_colors color, enum led_bits led_bit)
288{
289 if (led_bit == BD2802_OFF) {
290 dev_err(&led->client->dev,
291 "Only 'blink' and 'on' are allowed\n");
292 return;
293 }
294
295 if (led_bit == BD2802_BLINK)
296 bd2802_set_blink(led, id, color);
297 else
298 bd2802_set_on(led, id, color);
299}
300
301static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id,
302 enum led_colors color)
303{
304 u8 reg;
305
306 if (bd2802_is_rgb_off(led, id, color))
307 return;
308
309 reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
310 bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
311 reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
312 bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
313
314 bd2802_update_state(led, id, color, BD2802_OFF);
315}
316
317static void bd2802_restore_state(struct bd2802_led *led)
318{
319 int i;
320
321 for (i = 0; i < LED_NUM; i++) {
322 if (led->led[i].r)
323 bd2802_turn_on(led, i, RED, led->led[i].r);
324 if (led->led[i].g)
325 bd2802_turn_on(led, i, GREEN, led->led[i].g);
326 if (led->led[i].b)
327 bd2802_turn_on(led, i, BLUE, led->led[i].b);
328 }
329}
330
331#define BD2802_SET_REGISTER(reg_addr, reg_name) \
332static ssize_t bd2802_store_reg##reg_addr(struct device *dev, \
333 struct device_attribute *attr, const char *buf, size_t count) \
334{ \
335 struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
336 unsigned long val; \
337 int ret; \
338 if (!count) \
339 return -EINVAL; \
340 ret = strict_strtoul(buf, 16, &val); \
341 if (ret) \
342 return ret; \
343 down_write(&led->rwsem); \
344 bd2802_write_byte(led->client, reg_addr, (u8) val); \
345 up_write(&led->rwsem); \
346 return count; \
347} \
348static struct device_attribute bd2802_reg##reg_addr##_attr = { \
349 .attr = {.name = reg_name, .mode = 0644, .owner = THIS_MODULE}, \
350 .store = bd2802_store_reg##reg_addr, \
351};
352
353BD2802_SET_REGISTER(0x00, "0x00");
354BD2802_SET_REGISTER(0x01, "0x01");
355BD2802_SET_REGISTER(0x02, "0x02");
356BD2802_SET_REGISTER(0x03, "0x03");
357BD2802_SET_REGISTER(0x04, "0x04");
358BD2802_SET_REGISTER(0x05, "0x05");
359BD2802_SET_REGISTER(0x06, "0x06");
360BD2802_SET_REGISTER(0x07, "0x07");
361BD2802_SET_REGISTER(0x08, "0x08");
362BD2802_SET_REGISTER(0x09, "0x09");
363BD2802_SET_REGISTER(0x0a, "0x0a");
364BD2802_SET_REGISTER(0x0b, "0x0b");
365BD2802_SET_REGISTER(0x0c, "0x0c");
366BD2802_SET_REGISTER(0x0d, "0x0d");
367BD2802_SET_REGISTER(0x0e, "0x0e");
368BD2802_SET_REGISTER(0x0f, "0x0f");
369BD2802_SET_REGISTER(0x10, "0x10");
370BD2802_SET_REGISTER(0x11, "0x11");
371BD2802_SET_REGISTER(0x12, "0x12");
372BD2802_SET_REGISTER(0x13, "0x13");
373BD2802_SET_REGISTER(0x14, "0x14");
374BD2802_SET_REGISTER(0x15, "0x15");
375
376static struct device_attribute *bd2802_addr_attributes[] = {
377 &bd2802_reg0x00_attr,
378 &bd2802_reg0x01_attr,
379 &bd2802_reg0x02_attr,
380 &bd2802_reg0x03_attr,
381 &bd2802_reg0x04_attr,
382 &bd2802_reg0x05_attr,
383 &bd2802_reg0x06_attr,
384 &bd2802_reg0x07_attr,
385 &bd2802_reg0x08_attr,
386 &bd2802_reg0x09_attr,
387 &bd2802_reg0x0a_attr,
388 &bd2802_reg0x0b_attr,
389 &bd2802_reg0x0c_attr,
390 &bd2802_reg0x0d_attr,
391 &bd2802_reg0x0e_attr,
392 &bd2802_reg0x0f_attr,
393 &bd2802_reg0x10_attr,
394 &bd2802_reg0x11_attr,
395 &bd2802_reg0x12_attr,
396 &bd2802_reg0x13_attr,
397 &bd2802_reg0x14_attr,
398 &bd2802_reg0x15_attr,
399};
400
401static void bd2802_enable_adv_conf(struct bd2802_led *led)
402{
403 int i, ret;
404
405 for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++) {
406 ret = device_create_file(&led->client->dev,
407 bd2802_addr_attributes[i]);
408 if (ret) {
409 dev_err(&led->client->dev, "failed to sysfs file %s\n",
410 bd2802_addr_attributes[i]->attr.name);
411 goto failed_remove_files;
412 }
413 }
414
415 if (bd2802_is_all_off(led))
416 bd2802_reset_cancel(led);
417
418 led->adf_on = 1;
419
420 return;
421
422failed_remove_files:
423 for (i--; i >= 0; i--)
424 device_remove_file(&led->client->dev,
425 bd2802_addr_attributes[i]);
426}
427
428static void bd2802_disable_adv_conf(struct bd2802_led *led)
429{
430 int i;
431
432 for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++)
433 device_remove_file(&led->client->dev,
434 bd2802_addr_attributes[i]);
435
436 if (bd2802_is_all_off(led))
437 gpio_set_value(led->pdata->reset_gpio, 0);
438
439 led->adf_on = 0;
440}
441
442static ssize_t bd2802_show_adv_conf(struct device *dev,
443 struct device_attribute *attr, char *buf)
444{
445 struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
446 ssize_t ret;
447
448 down_read(&led->rwsem);
449 if (led->adf_on)
450 ret = sprintf(buf, "on\n");
451 else
452 ret = sprintf(buf, "off\n");
453 up_read(&led->rwsem);
454
455 return ret;
456}
457
458static ssize_t bd2802_store_adv_conf(struct device *dev,
459 struct device_attribute *attr, const char *buf, size_t count)
460{
461 struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
462
463 if (!count)
464 return -EINVAL;
465
466 down_write(&led->rwsem);
467 if (!led->adf_on && !strncmp(buf, "on", 2))
468 bd2802_enable_adv_conf(led);
469 else if (led->adf_on && !strncmp(buf, "off", 3))
470 bd2802_disable_adv_conf(led);
471 up_write(&led->rwsem);
472
473 return count;
474}
475
476static struct device_attribute bd2802_adv_conf_attr = {
477 .attr = {
478 .name = "advanced_configuration",
479 .mode = 0644,
480 .owner = THIS_MODULE
481 },
482 .show = bd2802_show_adv_conf,
483 .store = bd2802_store_adv_conf,
484};
485
486static void bd2802_led_work(struct work_struct *work)
487{
488 struct bd2802_led *led = container_of(work, struct bd2802_led, work);
489
490 if (led->state)
491 bd2802_turn_on(led, led->led_id, led->color, led->state);
492 else
493 bd2802_turn_off(led, led->led_id, led->color);
494}
495
496#define BD2802_CONTROL_RGBS(name, id, clr) \
497static void bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
498 enum led_brightness value) \
499{ \
500 struct bd2802_led *led = \
501 container_of(led_cdev, struct bd2802_led, cdev_##name); \
502 led->led_id = id; \
503 led->color = clr; \
504 if (value == LED_OFF) \
505 led->state = BD2802_OFF; \
506 else \
507 led->state = BD2802_ON; \
508 schedule_work(&led->work); \
509} \
510static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
511 unsigned long *delay_on, unsigned long *delay_off) \
512{ \
513 struct bd2802_led *led = \
514 container_of(led_cdev, struct bd2802_led, cdev_##name); \
515 if (*delay_on == 0 || *delay_off == 0) \
516 return -EINVAL; \
517 led->led_id = id; \
518 led->color = clr; \
519 led->state = BD2802_BLINK; \
520 schedule_work(&led->work); \
521 return 0; \
522}
523
524BD2802_CONTROL_RGBS(led1r, LED1, RED);
525BD2802_CONTROL_RGBS(led1g, LED1, GREEN);
526BD2802_CONTROL_RGBS(led1b, LED1, BLUE);
527BD2802_CONTROL_RGBS(led2r, LED2, RED);
528BD2802_CONTROL_RGBS(led2g, LED2, GREEN);
529BD2802_CONTROL_RGBS(led2b, LED2, BLUE);
530
531static int bd2802_register_led_classdev(struct bd2802_led *led)
532{
533 int ret;
534
535 INIT_WORK(&led->work, bd2802_led_work);
536
537 led->cdev_led1r.name = "led1_R";
538 led->cdev_led1r.brightness = LED_OFF;
539 led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
540 led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
541 led->cdev_led1r.flags |= LED_CORE_SUSPENDRESUME;
542
543 ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
544 if (ret < 0) {
545 dev_err(&led->client->dev, "couldn't register LED %s\n",
546 led->cdev_led1r.name);
547 goto failed_unregister_led1_R;
548 }
549
550 led->cdev_led1g.name = "led1_G";
551 led->cdev_led1g.brightness = LED_OFF;
552 led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
553 led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
554 led->cdev_led1g.flags |= LED_CORE_SUSPENDRESUME;
555
556 ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
557 if (ret < 0) {
558 dev_err(&led->client->dev, "couldn't register LED %s\n",
559 led->cdev_led1g.name);
560 goto failed_unregister_led1_G;
561 }
562
563 led->cdev_led1b.name = "led1_B";
564 led->cdev_led1b.brightness = LED_OFF;
565 led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
566 led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
567 led->cdev_led1b.flags |= LED_CORE_SUSPENDRESUME;
568
569 ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
570 if (ret < 0) {
571 dev_err(&led->client->dev, "couldn't register LED %s\n",
572 led->cdev_led1b.name);
573 goto failed_unregister_led1_B;
574 }
575
576 led->cdev_led2r.name = "led2_R";
577 led->cdev_led2r.brightness = LED_OFF;
578 led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
579 led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
580 led->cdev_led2r.flags |= LED_CORE_SUSPENDRESUME;
581
582 ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
583 if (ret < 0) {
584 dev_err(&led->client->dev, "couldn't register LED %s\n",
585 led->cdev_led2r.name);
586 goto failed_unregister_led2_R;
587 }
588
589 led->cdev_led2g.name = "led2_G";
590 led->cdev_led2g.brightness = LED_OFF;
591 led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
592 led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
593 led->cdev_led2g.flags |= LED_CORE_SUSPENDRESUME;
594
595 ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
596 if (ret < 0) {
597 dev_err(&led->client->dev, "couldn't register LED %s\n",
598 led->cdev_led2g.name);
599 goto failed_unregister_led2_G;
600 }
601
602 led->cdev_led2b.name = "led2_B";
603 led->cdev_led2b.brightness = LED_OFF;
604 led->cdev_led2b.brightness_set = bd2802_set_led2b_brightness;
605 led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
606 led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
607
608 ret = led_classdev_register(&led->client->dev, &led->cdev_led2b);
609 if (ret < 0) {
610 dev_err(&led->client->dev, "couldn't register LED %s\n",
611 led->cdev_led2b.name);
612 goto failed_unregister_led2_B;
613 }
614
615 return 0;
616
617failed_unregister_led2_B:
618 led_classdev_unregister(&led->cdev_led2g);
619failed_unregister_led2_G:
620 led_classdev_unregister(&led->cdev_led2r);
621failed_unregister_led2_R:
622 led_classdev_unregister(&led->cdev_led1b);
623failed_unregister_led1_B:
624 led_classdev_unregister(&led->cdev_led1g);
625failed_unregister_led1_G:
626 led_classdev_unregister(&led->cdev_led1r);
627failed_unregister_led1_R:
628
629 return ret;
630}
631
632static void bd2802_unregister_led_classdev(struct bd2802_led *led)
633{
634 cancel_work_sync(&led->work);
635 led_classdev_unregister(&led->cdev_led1r);
636}
637
638static int __devinit bd2802_probe(struct i2c_client *client,
639 const struct i2c_device_id *id)
640{
641 struct bd2802_led *led;
642 struct bd2802_led_platform_data *pdata;
643 int ret;
644
645 led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
646 if (!led) {
647 dev_err(&client->dev, "failed to allocate driver data\n");
648 return -ENOMEM;
649 }
650
651 led->client = client;
652 pdata = led->pdata = client->dev.platform_data;
653 i2c_set_clientdata(client, led);
654
655 /* Configure RESET GPIO (L: RESET, H: RESET cancel) */
656 gpio_request(pdata->reset_gpio, "RGB_RESETB");
657 gpio_direction_output(pdata->reset_gpio, 1);
658
659 /* Tacss = min 0.1ms */
660 udelay(100);
661
662 /* Detect BD2802GU */
663 ret = bd2802_write_byte(client, BD2802_REG_CLKSETUP, 0x00);
664 if (ret < 0) {
665 dev_err(&client->dev, "failed to detect device\n");
666 goto failed_free;
667 } else
668 dev_info(&client->dev, "return 0x%02x\n", ret);
669
670 /* To save the power, reset BD2802 after detecting */
671 gpio_set_value(led->pdata->reset_gpio, 0);
672
673 init_rwsem(&led->rwsem);
674
675 ret = device_create_file(&client->dev, &bd2802_adv_conf_attr);
676 if (ret) {
677 dev_err(&client->dev, "failed to create sysfs file %s\n",
678 bd2802_adv_conf_attr.attr.name);
679 goto failed_free;
680 }
681
682 ret = bd2802_register_led_classdev(led);
683 if (ret < 0)
684 goto failed_unregister_dev_file;
685
686 return 0;
687
688failed_unregister_dev_file:
689 device_remove_file(&client->dev, &bd2802_adv_conf_attr);
690failed_free:
691 i2c_set_clientdata(client, NULL);
692 kfree(led);
693
694 return ret;
695}
696
697static int __exit bd2802_remove(struct i2c_client *client)
698{
699 struct bd2802_led *led = i2c_get_clientdata(client);
700
701 bd2802_unregister_led_classdev(led);
702 gpio_set_value(led->pdata->reset_gpio, 0);
703 if (led->adf_on)
704 bd2802_disable_adv_conf(led);
705 device_remove_file(&client->dev, &bd2802_adv_conf_attr);
706 i2c_set_clientdata(client, NULL);
707 kfree(led);
708
709 return 0;
710}
711
712static int bd2802_suspend(struct i2c_client *client, pm_message_t mesg)
713{
714 struct bd2802_led *led = i2c_get_clientdata(client);
715
716 gpio_set_value(led->pdata->reset_gpio, 0);
717
718 return 0;
719}
720
721static int bd2802_resume(struct i2c_client *client)
722{
723 struct bd2802_led *led = i2c_get_clientdata(client);
724
725 if (!bd2802_is_all_off(led) || led->adf_on) {
726 gpio_set_value(led->pdata->reset_gpio, 1);
727 udelay(100);
728 bd2802_restore_state(led);
729 }
730
731 return 0;
732}
733
734static const struct i2c_device_id bd2802_id[] = {
735 { "BD2802", 0 },
736 { }
737};
738MODULE_DEVICE_TABLE(i2c, bd2802_id);
739
740static struct i2c_driver bd2802_i2c_driver = {
741 .driver = {
742 .name = "BD2802",
743 },
744 .probe = bd2802_probe,
745 .remove = __exit_p(bd2802_remove),
746 .suspend = bd2802_suspend,
747 .resume = bd2802_resume,
748 .id_table = bd2802_id,
749};
750
751static int __init bd2802_init(void)
752{
753 return i2c_add_driver(&bd2802_i2c_driver);
754}
755module_init(bd2802_init);
756
757static void __exit bd2802_exit(void)
758{
759 i2c_del_driver(&bd2802_i2c_driver);
760}
761module_exit(bd2802_exit);
762
763MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
764MODULE_DESCRIPTION("BD2802 LED driver");
765MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-dac124s085.c b/drivers/leds/leds-dac124s085.c
new file mode 100644
index 000000000000..098d9aae7259
--- /dev/null
+++ b/drivers/leds/leds-dac124s085.c
@@ -0,0 +1,150 @@
1/*
2 * Copyright 2008
3 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
4 *
5 * This file is subject to the terms and conditions of version 2 of
6 * the GNU General Public License. See the file COPYING in the main
7 * directory of this archive for more details.
8 *
9 * LED driver for the DAC124S085 SPI DAC
10 */
11
12#include <linux/gfp.h>
13#include <linux/leds.h>
14#include <linux/module.h>
15#include <linux/mutex.h>
16#include <linux/slab.h>
17#include <linux/spinlock.h>
18#include <linux/workqueue.h>
19#include <linux/spi/spi.h>
20
21struct dac124s085_led {
22 struct led_classdev ldev;
23 struct spi_device *spi;
24 int id;
25 int brightness;
26 char name[sizeof("dac124s085-3")];
27
28 struct mutex mutex;
29 struct work_struct work;
30 spinlock_t lock;
31};
32
33struct dac124s085 {
34 struct dac124s085_led leds[4];
35};
36
37#define REG_WRITE (0 << 12)
38#define REG_WRITE_UPDATE (1 << 12)
39#define ALL_WRITE_UPDATE (2 << 12)
40#define POWER_DOWN_OUTPUT (3 << 12)
41
42static void dac124s085_led_work(struct work_struct *work)
43{
44 struct dac124s085_led *led = container_of(work, struct dac124s085_led,
45 work);
46 u16 word;
47
48 mutex_lock(&led->mutex);
49 word = cpu_to_le16(((led->id) << 14) | REG_WRITE_UPDATE |
50 (led->brightness & 0xfff));
51 spi_write(led->spi, (const u8 *)&word, sizeof(word));
52 mutex_unlock(&led->mutex);
53}
54
55static void dac124s085_set_brightness(struct led_classdev *ldev,
56 enum led_brightness brightness)
57{
58 struct dac124s085_led *led = container_of(ldev, struct dac124s085_led,
59 ldev);
60
61 spin_lock(&led->lock);
62 led->brightness = brightness;
63 schedule_work(&led->work);
64 spin_unlock(&led->lock);
65}
66
67static int dac124s085_probe(struct spi_device *spi)
68{
69 struct dac124s085 *dac;
70 struct dac124s085_led *led;
71 int i, ret;
72
73 dac = kzalloc(sizeof(*dac), GFP_KERNEL);
74 if (!dac)
75 return -ENOMEM;
76
77 spi->bits_per_word = 16;
78
79 for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
80 led = dac->leds + i;
81 led->id = i;
82 led->brightness = LED_OFF;
83 led->spi = spi;
84 snprintf(led->name, sizeof(led->name), "dac124s085-%d", i);
85 spin_lock_init(&led->lock);
86 INIT_WORK(&led->work, dac124s085_led_work);
87 mutex_init(&led->mutex);
88 led->ldev.name = led->name;
89 led->ldev.brightness = LED_OFF;
90 led->ldev.max_brightness = 0xfff;
91 led->ldev.brightness_set = dac124s085_set_brightness;
92 ret = led_classdev_register(&spi->dev, &led->ldev);
93 if (ret < 0)
94 goto eledcr;
95 }
96
97 spi_set_drvdata(spi, dac);
98
99 return 0;
100
101eledcr:
102 while (i--)
103 led_classdev_unregister(&dac->leds[i].ldev);
104
105 spi_set_drvdata(spi, NULL);
106 kfree(dac);
107 return ret;
108}
109
110static int dac124s085_remove(struct spi_device *spi)
111{
112 struct dac124s085 *dac = spi_get_drvdata(spi);
113 int i;
114
115 for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
116 led_classdev_unregister(&dac->leds[i].ldev);
117 cancel_work_sync(&dac->leds[i].work);
118 }
119
120 spi_set_drvdata(spi, NULL);
121 kfree(dac);
122
123 return 0;
124}
125
126static struct spi_driver dac124s085_driver = {
127 .probe = dac124s085_probe,
128 .remove = dac124s085_remove,
129 .driver = {
130 .name = "dac124s085",
131 .owner = THIS_MODULE,
132 },
133};
134
135static int __init dac124s085_leds_init(void)
136{
137 return spi_register_driver(&dac124s085_driver);
138}
139
140static void __exit dac124s085_leds_exit(void)
141{
142 spi_unregister_driver(&dac124s085_driver);
143}
144
145module_init(dac124s085_leds_init);
146module_exit(dac124s085_leds_exit);
147
148MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
149MODULE_DESCRIPTION("DAC124S085 LED driver");
150MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 2e3df08b649b..d2109054de85 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (C) 2007 8D Technologies inc. 4 * Copyright (C) 2007 8D Technologies inc.
5 * Raphael Assenat <raph@8d.com> 5 * Raphael Assenat <raph@8d.com>
6 * Copyright (C) 2008 Freescale Semiconductor, Inc.
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -71,11 +72,67 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
71 return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off); 72 return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off);
72} 73}
73 74
75static int __devinit create_gpio_led(const struct gpio_led *template,
76 struct gpio_led_data *led_dat, struct device *parent,
77 int (*blink_set)(unsigned, unsigned long *, unsigned long *))
78{
79 int ret;
80
81 /* skip leds that aren't available */
82 if (!gpio_is_valid(template->gpio)) {
83 printk(KERN_INFO "Skipping unavilable LED gpio %d (%s)\n",
84 template->gpio, template->name);
85 return 0;
86 }
87
88 ret = gpio_request(template->gpio, template->name);
89 if (ret < 0)
90 return ret;
91
92 led_dat->cdev.name = template->name;
93 led_dat->cdev.default_trigger = template->default_trigger;
94 led_dat->gpio = template->gpio;
95 led_dat->can_sleep = gpio_cansleep(template->gpio);
96 led_dat->active_low = template->active_low;
97 if (blink_set) {
98 led_dat->platform_gpio_blink_set = blink_set;
99 led_dat->cdev.blink_set = gpio_blink_set;
100 }
101 led_dat->cdev.brightness_set = gpio_led_set;
102 led_dat->cdev.brightness = LED_OFF;
103 if (!template->retain_state_suspended)
104 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
105
106 ret = gpio_direction_output(led_dat->gpio, led_dat->active_low);
107 if (ret < 0)
108 goto err;
109
110 INIT_WORK(&led_dat->work, gpio_led_work);
111
112 ret = led_classdev_register(parent, &led_dat->cdev);
113 if (ret < 0)
114 goto err;
115
116 return 0;
117err:
118 gpio_free(led_dat->gpio);
119 return ret;
120}
121
122static void delete_gpio_led(struct gpio_led_data *led)
123{
124 if (!gpio_is_valid(led->gpio))
125 return;
126 led_classdev_unregister(&led->cdev);
127 cancel_work_sync(&led->work);
128 gpio_free(led->gpio);
129}
130
131#ifdef CONFIG_LEDS_GPIO_PLATFORM
74static int gpio_led_probe(struct platform_device *pdev) 132static int gpio_led_probe(struct platform_device *pdev)
75{ 133{
76 struct gpio_led_platform_data *pdata = pdev->dev.platform_data; 134 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
77 struct gpio_led *cur_led; 135 struct gpio_led_data *leds_data;
78 struct gpio_led_data *leds_data, *led_dat;
79 int i, ret = 0; 136 int i, ret = 0;
80 137
81 if (!pdata) 138 if (!pdata)
@@ -87,35 +144,10 @@ static int gpio_led_probe(struct platform_device *pdev)
87 return -ENOMEM; 144 return -ENOMEM;
88 145
89 for (i = 0; i < pdata->num_leds; i++) { 146 for (i = 0; i < pdata->num_leds; i++) {
90 cur_led = &pdata->leds[i]; 147 ret = create_gpio_led(&pdata->leds[i], &leds_data[i],
91 led_dat = &leds_data[i]; 148 &pdev->dev, pdata->gpio_blink_set);
92
93 ret = gpio_request(cur_led->gpio, cur_led->name);
94 if (ret < 0) 149 if (ret < 0)
95 goto err; 150 goto err;
96
97 led_dat->cdev.name = cur_led->name;
98 led_dat->cdev.default_trigger = cur_led->default_trigger;
99 led_dat->gpio = cur_led->gpio;
100 led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
101 led_dat->active_low = cur_led->active_low;
102 if (pdata->gpio_blink_set) {
103 led_dat->platform_gpio_blink_set = pdata->gpio_blink_set;
104 led_dat->cdev.blink_set = gpio_blink_set;
105 }
106 led_dat->cdev.brightness_set = gpio_led_set;
107 led_dat->cdev.brightness = LED_OFF;
108 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
109
110 gpio_direction_output(led_dat->gpio, led_dat->active_low);
111
112 INIT_WORK(&led_dat->work, gpio_led_work);
113
114 ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
115 if (ret < 0) {
116 gpio_free(led_dat->gpio);
117 goto err;
118 }
119 } 151 }
120 152
121 platform_set_drvdata(pdev, leds_data); 153 platform_set_drvdata(pdev, leds_data);
@@ -123,13 +155,8 @@ static int gpio_led_probe(struct platform_device *pdev)
123 return 0; 155 return 0;
124 156
125err: 157err:
126 if (i > 0) { 158 for (i = i - 1; i >= 0; i--)
127 for (i = i - 1; i >= 0; i--) { 159 delete_gpio_led(&leds_data[i]);
128 led_classdev_unregister(&leds_data[i].cdev);
129 cancel_work_sync(&leds_data[i].work);
130 gpio_free(leds_data[i].gpio);
131 }
132 }
133 160
134 kfree(leds_data); 161 kfree(leds_data);
135 162
@@ -144,11 +171,8 @@ static int __devexit gpio_led_remove(struct platform_device *pdev)
144 171
145 leds_data = platform_get_drvdata(pdev); 172 leds_data = platform_get_drvdata(pdev);
146 173
147 for (i = 0; i < pdata->num_leds; i++) { 174 for (i = 0; i < pdata->num_leds; i++)
148 led_classdev_unregister(&leds_data[i].cdev); 175 delete_gpio_led(&leds_data[i]);
149 cancel_work_sync(&leds_data[i].work);
150 gpio_free(leds_data[i].gpio);
151 }
152 176
153 kfree(leds_data); 177 kfree(leds_data);
154 178
@@ -164,20 +188,133 @@ static struct platform_driver gpio_led_driver = {
164 }, 188 },
165}; 189};
166 190
191MODULE_ALIAS("platform:leds-gpio");
192#endif /* CONFIG_LEDS_GPIO_PLATFORM */
193
194/* Code to create from OpenFirmware platform devices */
195#ifdef CONFIG_LEDS_GPIO_OF
196#include <linux/of_platform.h>
197#include <linux/of_gpio.h>
198
199struct gpio_led_of_platform_data {
200 int num_leds;
201 struct gpio_led_data led_data[];
202};
203
204static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
205 const struct of_device_id *match)
206{
207 struct device_node *np = ofdev->node, *child;
208 struct gpio_led led;
209 struct gpio_led_of_platform_data *pdata;
210 int count = 0, ret;
211
212 /* count LEDs defined by this device, so we know how much to allocate */
213 for_each_child_of_node(np, child)
214 count++;
215 if (!count)
216 return 0; /* or ENODEV? */
217
218 pdata = kzalloc(sizeof(*pdata) + sizeof(struct gpio_led_data) * count,
219 GFP_KERNEL);
220 if (!pdata)
221 return -ENOMEM;
222
223 memset(&led, 0, sizeof(led));
224 for_each_child_of_node(np, child) {
225 enum of_gpio_flags flags;
226
227 led.gpio = of_get_gpio_flags(child, 0, &flags);
228 led.active_low = flags & OF_GPIO_ACTIVE_LOW;
229 led.name = of_get_property(child, "label", NULL) ? : child->name;
230 led.default_trigger =
231 of_get_property(child, "linux,default-trigger", NULL);
232
233 ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++],
234 &ofdev->dev, NULL);
235 if (ret < 0) {
236 of_node_put(child);
237 goto err;
238 }
239 }
240
241 dev_set_drvdata(&ofdev->dev, pdata);
242
243 return 0;
244
245err:
246 for (count = pdata->num_leds - 2; count >= 0; count--)
247 delete_gpio_led(&pdata->led_data[count]);
248
249 kfree(pdata);
250
251 return ret;
252}
253
254static int __devexit of_gpio_leds_remove(struct of_device *ofdev)
255{
256 struct gpio_led_of_platform_data *pdata = dev_get_drvdata(&ofdev->dev);
257 int i;
258
259 for (i = 0; i < pdata->num_leds; i++)
260 delete_gpio_led(&pdata->led_data[i]);
261
262 kfree(pdata);
263
264 dev_set_drvdata(&ofdev->dev, NULL);
265
266 return 0;
267}
268
269static const struct of_device_id of_gpio_leds_match[] = {
270 { .compatible = "gpio-leds", },
271 {},
272};
273
274static struct of_platform_driver of_gpio_leds_driver = {
275 .driver = {
276 .name = "of_gpio_leds",
277 .owner = THIS_MODULE,
278 },
279 .match_table = of_gpio_leds_match,
280 .probe = of_gpio_leds_probe,
281 .remove = __devexit_p(of_gpio_leds_remove),
282};
283#endif
284
167static int __init gpio_led_init(void) 285static int __init gpio_led_init(void)
168{ 286{
169 return platform_driver_register(&gpio_led_driver); 287 int ret;
288
289#ifdef CONFIG_LEDS_GPIO_PLATFORM
290 ret = platform_driver_register(&gpio_led_driver);
291 if (ret)
292 return ret;
293#endif
294#ifdef CONFIG_LEDS_GPIO_OF
295 ret = of_register_platform_driver(&of_gpio_leds_driver);
296#endif
297#ifdef CONFIG_LEDS_GPIO_PLATFORM
298 if (ret)
299 platform_driver_unregister(&gpio_led_driver);
300#endif
301
302 return ret;
170} 303}
171 304
172static void __exit gpio_led_exit(void) 305static void __exit gpio_led_exit(void)
173{ 306{
307#ifdef CONFIG_LEDS_GPIO_PLATFORM
174 platform_driver_unregister(&gpio_led_driver); 308 platform_driver_unregister(&gpio_led_driver);
309#endif
310#ifdef CONFIG_LEDS_GPIO_OF
311 of_unregister_platform_driver(&of_gpio_leds_driver);
312#endif
175} 313}
176 314
177module_init(gpio_led_init); 315module_init(gpio_led_init);
178module_exit(gpio_led_exit); 316module_exit(gpio_led_exit);
179 317
180MODULE_AUTHOR("Raphael Assenat <raph@8d.com>"); 318MODULE_AUTHOR("Raphael Assenat <raph@8d.com>, Trent Piepho <tpiepho@freescale.com>");
181MODULE_DESCRIPTION("GPIO LED driver"); 319MODULE_DESCRIPTION("GPIO LED driver");
182MODULE_LICENSE("GPL"); 320MODULE_LICENSE("GPL");
183MODULE_ALIAS("platform:leds-gpio");
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
index 11b77a70bbcb..1aa46a390a0d 100644
--- a/drivers/leds/leds-h1940.c
+++ b/drivers/leds/leds-h1940.c
@@ -104,7 +104,7 @@ static struct led_classdev h1940_blueled = {
104 .default_trigger = "h1940-bluetooth", 104 .default_trigger = "h1940-bluetooth",
105}; 105};
106 106
107static int __init h1940leds_probe(struct platform_device *pdev) 107static int __devinit h1940leds_probe(struct platform_device *pdev)
108{ 108{
109 int ret; 109 int ret;
110 110
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index bd3b431c9710..3937244fdcab 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -169,7 +169,7 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
169{ 169{
170 struct pca9532_data *data = input_get_drvdata(dev); 170 struct pca9532_data *data = input_get_drvdata(dev);
171 171
172 if (type != EV_SND && (code != SND_BELL || code != SND_TONE)) 172 if (!(type == EV_SND && (code == SND_BELL || code == SND_TONE)))
173 return -1; 173 return -1;
174 174
175 /* XXX: allow different kind of beeps with psc/pwm modifications */ 175 /* XXX: allow different kind of beeps with psc/pwm modifications */
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
new file mode 100644
index 000000000000..cdfdc8714e10
--- /dev/null
+++ b/drivers/leds/leds-pwm.c
@@ -0,0 +1,153 @@
1/*
2 * linux/drivers/leds-pwm.c
3 *
4 * simple PWM based LED control
5 *
6 * Copyright 2009 Luotao Fu @ Pengutronix (l.fu@pengutronix.de)
7 *
8 * based on leds-gpio.c by Raphael Assenat <raph@8d.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/platform_device.h>
19#include <linux/fb.h>
20#include <linux/leds.h>
21#include <linux/err.h>
22#include <linux/pwm.h>
23#include <linux/leds_pwm.h>
24
25struct led_pwm_data {
26 struct led_classdev cdev;
27 struct pwm_device *pwm;
28 unsigned int active_low;
29 unsigned int period;
30 unsigned int max_brightness;
31};
32
33static void led_pwm_set(struct led_classdev *led_cdev,
34 enum led_brightness brightness)
35{
36 struct led_pwm_data *led_dat =
37 container_of(led_cdev, struct led_pwm_data, cdev);
38 unsigned int max = led_dat->max_brightness;
39 unsigned int period = led_dat->period;
40
41 if (brightness == 0) {
42 pwm_config(led_dat->pwm, 0, period);
43 pwm_disable(led_dat->pwm);
44 } else {
45 pwm_config(led_dat->pwm, brightness * period / max, period);
46 pwm_enable(led_dat->pwm);
47 }
48}
49
50static int led_pwm_probe(struct platform_device *pdev)
51{
52 struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
53 struct led_pwm *cur_led;
54 struct led_pwm_data *leds_data, *led_dat;
55 int i, ret = 0;
56
57 if (!pdata)
58 return -EBUSY;
59
60 leds_data = kzalloc(sizeof(struct led_pwm_data) * pdata->num_leds,
61 GFP_KERNEL);
62 if (!leds_data)
63 return -ENOMEM;
64
65 for (i = 0; i < pdata->num_leds; i++) {
66 cur_led = &pdata->leds[i];
67 led_dat = &leds_data[i];
68
69 led_dat->pwm = pwm_request(cur_led->pwm_id,
70 cur_led->name);
71 if (IS_ERR(led_dat->pwm)) {
72 dev_err(&pdev->dev, "unable to request PWM %d\n",
73 cur_led->pwm_id);
74 goto err;
75 }
76
77 led_dat->cdev.name = cur_led->name;
78 led_dat->cdev.default_trigger = cur_led->default_trigger;
79 led_dat->active_low = cur_led->active_low;
80 led_dat->max_brightness = cur_led->max_brightness;
81 led_dat->period = cur_led->pwm_period_ns;
82 led_dat->cdev.brightness_set = led_pwm_set;
83 led_dat->cdev.brightness = LED_OFF;
84 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
85
86 ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
87 if (ret < 0) {
88 pwm_free(led_dat->pwm);
89 goto err;
90 }
91 }
92
93 platform_set_drvdata(pdev, leds_data);
94
95 return 0;
96
97err:
98 if (i > 0) {
99 for (i = i - 1; i >= 0; i--) {
100 led_classdev_unregister(&leds_data[i].cdev);
101 pwm_free(leds_data[i].pwm);
102 }
103 }
104
105 kfree(leds_data);
106
107 return ret;
108}
109
110static int __devexit led_pwm_remove(struct platform_device *pdev)
111{
112 int i;
113 struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
114 struct led_pwm_data *leds_data;
115
116 leds_data = platform_get_drvdata(pdev);
117
118 for (i = 0; i < pdata->num_leds; i++) {
119 led_classdev_unregister(&leds_data[i].cdev);
120 pwm_free(leds_data[i].pwm);
121 }
122
123 kfree(leds_data);
124
125 return 0;
126}
127
128static struct platform_driver led_pwm_driver = {
129 .probe = led_pwm_probe,
130 .remove = __devexit_p(led_pwm_remove),
131 .driver = {
132 .name = "leds_pwm",
133 .owner = THIS_MODULE,
134 },
135};
136
137static int __init led_pwm_init(void)
138{
139 return platform_driver_register(&led_pwm_driver);
140}
141
142static void __exit led_pwm_exit(void)
143{
144 platform_driver_unregister(&led_pwm_driver);
145}
146
147module_init(led_pwm_init);
148module_exit(led_pwm_exit);
149
150MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
151MODULE_DESCRIPTION("PWM LED driver for PXA");
152MODULE_LICENSE("GPL");
153MODULE_ALIAS("platform:leds-pwm");
diff --git a/drivers/leds/leds-rb532.c b/drivers/leds/leds-rb532.c
new file mode 100644
index 000000000000..c3525f37f73d
--- /dev/null
+++ b/drivers/leds/leds-rb532.c
@@ -0,0 +1,77 @@
1/*
2 * LEDs driver for the "User LED" on Routerboard532
3 *
4 * Copyright (C) 2009 Phil Sutter <n0-1@freewrt.org>
5 *
6 * Based on leds-cobalt-qube.c by Florian Fainelly and
7 * rb-diag.c (my own standalone driver for both LED and
8 * button of Routerboard532).
9 */
10
11#include <linux/leds.h>
12#include <linux/module.h>
13#include <linux/platform_device.h>
14
15#include <asm/mach-rc32434/gpio.h>
16#include <asm/mach-rc32434/rb.h>
17
18static void rb532_led_set(struct led_classdev *cdev,
19 enum led_brightness brightness)
20{
21 if (brightness)
22 set_latch_u5(LO_ULED, 0);
23
24 else
25 set_latch_u5(0, LO_ULED);
26}
27
28static enum led_brightness rb532_led_get(struct led_classdev *cdev)
29{
30 return (get_latch_u5() & LO_ULED) ? LED_FULL : LED_OFF;
31}
32
33static struct led_classdev rb532_uled = {
34 .name = "uled",
35 .brightness_set = rb532_led_set,
36 .brightness_get = rb532_led_get,
37 .default_trigger = "nand-disk",
38};
39
40static int __devinit rb532_led_probe(struct platform_device *pdev)
41{
42 return led_classdev_register(&pdev->dev, &rb532_uled);
43}
44
45static int __devexit rb532_led_remove(struct platform_device *pdev)
46{
47 led_classdev_unregister(&rb532_uled);
48 return 0;
49}
50
51static struct platform_driver rb532_led_driver = {
52 .probe = rb532_led_probe,
53 .remove = __devexit_p(rb532_led_remove),
54 .driver = {
55 .name = "rb532-led",
56 .owner = THIS_MODULE,
57 },
58};
59
60static int __init rb532_led_init(void)
61{
62 return platform_driver_register(&rb532_led_driver);
63}
64
65static void __exit rb532_led_exit(void)
66{
67 platform_driver_unregister(&rb532_led_driver);
68}
69
70module_init(rb532_led_init);
71module_exit(rb532_led_exit);
72
73MODULE_ALIAS("platform:rb532-led");
74
75MODULE_LICENSE("GPL");
76MODULE_DESCRIPTION("User LED support for Routerboard532");
77MODULE_AUTHOR("Phil Sutter <n0-1@freewrt.org>");
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index 4d81131542ae..aa2e7ae0cdae 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -102,14 +102,11 @@ static int s3c24xx_led_probe(struct platform_device *dev)
102 ret = led_classdev_register(&dev->dev, &led->cdev); 102 ret = led_classdev_register(&dev->dev, &led->cdev);
103 if (ret < 0) { 103 if (ret < 0) {
104 dev_err(&dev->dev, "led_classdev_register failed\n"); 104 dev_err(&dev->dev, "led_classdev_register failed\n");
105 goto exit_err1; 105 kfree(led);
106 return ret;
106 } 107 }
107 108
108 return 0; 109 return 0;
109
110 exit_err1:
111 kfree(led);
112 return ret;
113} 110}
114 111
115static struct platform_driver s3c24xx_led_driver = { 112static struct platform_driver s3c24xx_led_driver = {
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 5edbf52c4fa7..2dd8ecbfdc31 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -20,8 +20,8 @@
20static inline void led_set_brightness(struct led_classdev *led_cdev, 20static inline void led_set_brightness(struct led_classdev *led_cdev,
21 enum led_brightness value) 21 enum led_brightness value)
22{ 22{
23 if (value > LED_FULL) 23 if (value > led_cdev->max_brightness)
24 value = LED_FULL; 24 value = led_cdev->max_brightness;
25 led_cdev->brightness = value; 25 led_cdev->brightness = value;
26 if (!(led_cdev->flags & LED_SUSPENDED)) 26 if (!(led_cdev->flags & LED_SUSPENDED))
27 led_cdev->brightness_set(led_cdev, value); 27 led_cdev->brightness_set(led_cdev, value);
diff --git a/drivers/leds/ledtrig-default-on.c b/drivers/leds/ledtrig-default-on.c
index 92995e40cfa4..a4ef54b9d508 100644
--- a/drivers/leds/ledtrig-default-on.c
+++ b/drivers/leds/ledtrig-default-on.c
@@ -19,7 +19,7 @@
19 19
20static void defon_trig_activate(struct led_classdev *led_cdev) 20static void defon_trig_activate(struct led_classdev *led_cdev)
21{ 21{
22 led_set_brightness(led_cdev, LED_FULL); 22 led_set_brightness(led_cdev, led_cdev->max_brightness);
23} 23}
24 24
25static struct led_trigger defon_led_trigger = { 25static struct led_trigger defon_led_trigger = {
diff --git a/drivers/leds/ledtrig-gpio.c b/drivers/leds/ledtrig-gpio.c
new file mode 100644
index 000000000000..a247ae63374f
--- /dev/null
+++ b/drivers/leds/ledtrig-gpio.c
@@ -0,0 +1,239 @@
1/*
2 * ledtrig-gio.c - LED Trigger Based on GPIO events
3 *
4 * Copyright 2009 Felipe Balbi <me@felipebalbi.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/gpio.h>
16#include <linux/interrupt.h>
17#include <linux/workqueue.h>
18#include <linux/leds.h>
19#include "leds.h"
20
21struct gpio_trig_data {
22 struct led_classdev *led;
23 struct work_struct work;
24
25 unsigned desired_brightness; /* desired brightness when led is on */
26 unsigned inverted; /* true when gpio is inverted */
27 unsigned gpio; /* gpio that triggers the leds */
28};
29
30static irqreturn_t gpio_trig_irq(int irq, void *_led)
31{
32 struct led_classdev *led = _led;
33 struct gpio_trig_data *gpio_data = led->trigger_data;
34
35 /* just schedule_work since gpio_get_value can sleep */
36 schedule_work(&gpio_data->work);
37
38 return IRQ_HANDLED;
39};
40
41static void gpio_trig_work(struct work_struct *work)
42{
43 struct gpio_trig_data *gpio_data = container_of(work,
44 struct gpio_trig_data, work);
45 int tmp;
46
47 if (!gpio_data->gpio)
48 return;
49
50 tmp = gpio_get_value(gpio_data->gpio);
51 if (gpio_data->inverted)
52 tmp = !tmp;
53
54 if (tmp) {
55 if (gpio_data->desired_brightness)
56 led_set_brightness(gpio_data->led,
57 gpio_data->desired_brightness);
58 else
59 led_set_brightness(gpio_data->led, LED_FULL);
60 } else {
61 led_set_brightness(gpio_data->led, LED_OFF);
62 }
63}
64
65static ssize_t gpio_trig_brightness_show(struct device *dev,
66 struct device_attribute *attr, char *buf)
67{
68 struct led_classdev *led = dev_get_drvdata(dev);
69 struct gpio_trig_data *gpio_data = led->trigger_data;
70
71 return sprintf(buf, "%u\n", gpio_data->desired_brightness);
72}
73
74static ssize_t gpio_trig_brightness_store(struct device *dev,
75 struct device_attribute *attr, const char *buf, size_t n)
76{
77 struct led_classdev *led = dev_get_drvdata(dev);
78 struct gpio_trig_data *gpio_data = led->trigger_data;
79 unsigned desired_brightness;
80 int ret;
81
82 ret = sscanf(buf, "%u", &desired_brightness);
83 if (ret < 1 || desired_brightness > 255) {
84 dev_err(dev, "invalid value\n");
85 return -EINVAL;
86 }
87
88 gpio_data->desired_brightness = desired_brightness;
89
90 return n;
91}
92static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show,
93 gpio_trig_brightness_store);
94
95static ssize_t gpio_trig_inverted_show(struct device *dev,
96 struct device_attribute *attr, char *buf)
97{
98 struct led_classdev *led = dev_get_drvdata(dev);
99 struct gpio_trig_data *gpio_data = led->trigger_data;
100
101 return sprintf(buf, "%s\n", gpio_data->inverted ? "yes" : "no");
102}
103
104static ssize_t gpio_trig_inverted_store(struct device *dev,
105 struct device_attribute *attr, const char *buf, size_t n)
106{
107 struct led_classdev *led = dev_get_drvdata(dev);
108 struct gpio_trig_data *gpio_data = led->trigger_data;
109 unsigned inverted;
110 int ret;
111
112 ret = sscanf(buf, "%u", &inverted);
113 if (ret < 1) {
114 dev_err(dev, "invalid value\n");
115 return -EINVAL;
116 }
117
118 gpio_data->inverted = !!inverted;
119
120 return n;
121}
122static DEVICE_ATTR(inverted, 0644, gpio_trig_inverted_show,
123 gpio_trig_inverted_store);
124
125static ssize_t gpio_trig_gpio_show(struct device *dev,
126 struct device_attribute *attr, char *buf)
127{
128 struct led_classdev *led = dev_get_drvdata(dev);
129 struct gpio_trig_data *gpio_data = led->trigger_data;
130
131 return sprintf(buf, "%u\n", gpio_data->gpio);
132}
133
134static ssize_t gpio_trig_gpio_store(struct device *dev,
135 struct device_attribute *attr, const char *buf, size_t n)
136{
137 struct led_classdev *led = dev_get_drvdata(dev);
138 struct gpio_trig_data *gpio_data = led->trigger_data;
139 unsigned gpio;
140 int ret;
141
142 ret = sscanf(buf, "%u", &gpio);
143 if (ret < 1) {
144 dev_err(dev, "couldn't read gpio number\n");
145 flush_work(&gpio_data->work);
146 return -EINVAL;
147 }
148
149 if (!gpio) {
150 free_irq(gpio_to_irq(gpio_data->gpio), led);
151 return n;
152 }
153
154 if (gpio_data->gpio > 0 && gpio_data->gpio != gpio)
155 free_irq(gpio_to_irq(gpio_data->gpio), led);
156
157 gpio_data->gpio = gpio;
158 ret = request_irq(gpio_to_irq(gpio), gpio_trig_irq,
159 IRQF_SHARED | IRQF_TRIGGER_RISING
160 | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led);
161 if (ret)
162 dev_err(dev, "request_irq failed with error %d\n", ret);
163
164 return ret ? ret : n;
165}
166static DEVICE_ATTR(gpio, 0644, gpio_trig_gpio_show, gpio_trig_gpio_store);
167
168static void gpio_trig_activate(struct led_classdev *led)
169{
170 struct gpio_trig_data *gpio_data;
171 int ret;
172
173 gpio_data = kzalloc(sizeof(*gpio_data), GFP_KERNEL);
174 if (!gpio_data)
175 return;
176
177 ret = device_create_file(led->dev, &dev_attr_gpio);
178 if (ret)
179 goto err_gpio;
180
181 ret = device_create_file(led->dev, &dev_attr_inverted);
182 if (ret)
183 goto err_inverted;
184
185 ret = device_create_file(led->dev, &dev_attr_desired_brightness);
186 if (ret)
187 goto err_brightness;
188
189 gpio_data->led = led;
190 led->trigger_data = gpio_data;
191 INIT_WORK(&gpio_data->work, gpio_trig_work);
192
193 return;
194
195err_brightness:
196 device_remove_file(led->dev, &dev_attr_inverted);
197
198err_inverted:
199 device_remove_file(led->dev, &dev_attr_gpio);
200
201err_gpio:
202 kfree(gpio_data);
203}
204
205static void gpio_trig_deactivate(struct led_classdev *led)
206{
207 struct gpio_trig_data *gpio_data = led->trigger_data;
208
209 if (gpio_data) {
210 device_remove_file(led->dev, &dev_attr_gpio);
211 device_remove_file(led->dev, &dev_attr_inverted);
212 device_remove_file(led->dev, &dev_attr_desired_brightness);
213 flush_work(&gpio_data->work);
214 free_irq(gpio_to_irq(gpio_data->gpio),led);
215 kfree(gpio_data);
216 }
217}
218
219static struct led_trigger gpio_led_trigger = {
220 .name = "gpio",
221 .activate = gpio_trig_activate,
222 .deactivate = gpio_trig_deactivate,
223};
224
225static int __init gpio_trig_init(void)
226{
227 return led_trigger_register(&gpio_led_trigger);
228}
229module_init(gpio_trig_init);
230
231static void __exit gpio_trig_exit(void)
232{
233 led_trigger_unregister(&gpio_led_trigger);
234}
235module_exit(gpio_trig_exit);
236
237MODULE_AUTHOR("Felipe Balbi <me@felipebalbi.com>");
238MODULE_DESCRIPTION("GPIO LED trigger");
239MODULE_LICENSE("GPL");
diff --git a/drivers/leds/ledtrig-heartbeat.c b/drivers/leds/ledtrig-heartbeat.c
index 4bf8cec8b8c1..c1c1ea6f817b 100644
--- a/drivers/leds/ledtrig-heartbeat.c
+++ b/drivers/leds/ledtrig-heartbeat.c
@@ -47,7 +47,7 @@ static void led_heartbeat_function(unsigned long data)
47 msecs_to_jiffies(heartbeat_data->period); 47 msecs_to_jiffies(heartbeat_data->period);
48 delay = msecs_to_jiffies(70); 48 delay = msecs_to_jiffies(70);
49 heartbeat_data->phase++; 49 heartbeat_data->phase++;
50 brightness = LED_FULL; 50 brightness = led_cdev->max_brightness;
51 break; 51 break;
52 case 1: 52 case 1:
53 delay = heartbeat_data->period / 4 - msecs_to_jiffies(70); 53 delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
@@ -56,7 +56,7 @@ static void led_heartbeat_function(unsigned long data)
56 case 2: 56 case 2:
57 delay = msecs_to_jiffies(70); 57 delay = msecs_to_jiffies(70);
58 heartbeat_data->phase++; 58 heartbeat_data->phase++;
59 brightness = LED_FULL; 59 brightness = led_cdev->max_brightness;
60 break; 60 break;
61 default: 61 default:
62 delay = heartbeat_data->period - heartbeat_data->period / 4 - 62 delay = heartbeat_data->period - heartbeat_data->period / 4 -
diff --git a/drivers/leds/ledtrig-ide-disk.c b/drivers/leds/ledtrig-ide-disk.c
index 883a577b1b97..ec099fcbcb00 100644
--- a/drivers/leds/ledtrig-ide-disk.c
+++ b/drivers/leds/ledtrig-ide-disk.c
@@ -37,7 +37,8 @@ static void ledtrig_ide_timerfunc(unsigned long data)
37{ 37{
38 if (ide_lastactivity != ide_activity) { 38 if (ide_lastactivity != ide_activity) {
39 ide_lastactivity = ide_activity; 39 ide_lastactivity = ide_activity;
40 led_trigger_event(ledtrig_ide, LED_FULL); 40 /* INT_MAX will set each LED to its maximum brightness */
41 led_trigger_event(ledtrig_ide, INT_MAX);
41 mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10)); 42 mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
42 } else { 43 } else {
43 led_trigger_event(ledtrig_ide, LED_OFF); 44 led_trigger_event(ledtrig_ide, LED_OFF);
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index 3d6531396dda..3b83406de752 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -166,7 +166,7 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
166 166
167 timer_data->brightness_on = led_get_brightness(led_cdev); 167 timer_data->brightness_on = led_get_brightness(led_cdev);
168 if (timer_data->brightness_on == LED_OFF) 168 if (timer_data->brightness_on == LED_OFF)
169 timer_data->brightness_on = LED_FULL; 169 timer_data->brightness_on = led_cdev->max_brightness;
170 led_cdev->trigger_data = timer_data; 170 led_cdev->trigger_data = timer_data;
171 171
172 init_timer(&timer_data->timer); 172 init_timer(&timer_data->timer);