aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-class-led-driver-lm353365
-rw-r--r--drivers/leds/Kconfig13
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-lm3533.c785
4 files changed, 864 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-led-driver-lm3533 b/Documentation/ABI/testing/sysfs-class-led-driver-lm3533
new file mode 100644
index 00000000000..620ebb3b9ba
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-led-driver-lm3533
@@ -0,0 +1,65 @@
1What: /sys/class/leds/<led>/als_channel
2Date: May 2012
3KernelVersion: 3.5
4Contact: Johan Hovold <jhovold@gmail.com>
5Description:
6 Set the ALS output channel to use as input in
7 ALS-current-control mode (1, 2), where
8
9 1 - out_current1
10 2 - out_current2
11
12What: /sys/class/leds/<led>/als_en
13Date: May 2012
14KernelVersion: 3.5
15Contact: Johan Hovold <jhovold@gmail.com>
16Description:
17 Enable ALS-current-control mode (0, 1).
18
19What: /sys/class/leds/<led>/falltime
20What: /sys/class/leds/<led>/risetime
21Date: April 2012
22KernelVersion: 3.5
23Contact: Johan Hovold <jhovold@gmail.com>
24Description:
25 Set the pattern generator fall and rise times (0..7), where
26
27 0 - 2048 us
28 1 - 262 ms
29 2 - 524 ms
30 3 - 1.049 s
31 4 - 2.097 s
32 5 - 4.194 s
33 6 - 8.389 s
34 7 - 16.78 s
35
36What: /sys/class/leds/<led>/id
37Date: April 2012
38KernelVersion: 3.5
39Contact: Johan Hovold <jhovold@gmail.com>
40Description:
41 Get the id of this led (0..3).
42
43What: /sys/class/leds/<led>/linear
44Date: April 2012
45KernelVersion: 3.5
46Contact: Johan Hovold <jhovold@gmail.com>
47Description:
48 Set the brightness-mapping mode (0, 1), where
49
50 0 - exponential mode
51 1 - linear mode
52
53What: /sys/class/leds/<led>/pwm
54Date: April 2012
55KernelVersion: 3.5
56Contact: Johan Hovold <jhovold@gmail.com>
57Description:
58 Set the PWM-input control mask (5 bits), where
59
60 bit 5 - PWM-input enabled in Zone 4
61 bit 4 - PWM-input enabled in Zone 3
62 bit 3 - PWM-input enabled in Zone 2
63 bit 2 - PWM-input enabled in Zone 1
64 bit 1 - PWM-input enabled in Zone 0
65 bit 0 - PWM-input enabled
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 6b2e1e4fdeb..04cb8c88d74 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -50,6 +50,19 @@ config LEDS_LM3530
50 controlled manually or using PWM input or using ambient 50 controlled manually or using PWM input or using ambient
51 light automatically. 51 light automatically.
52 52
53config LEDS_LM3533
54 tristate "LED support for LM3533"
55 depends on LEDS_CLASS
56 depends on MFD_LM3533
57 help
58 This option enables support for the LEDs on National Semiconductor /
59 TI LM3533 Lighting Power chips.
60
61 The LEDs can be controlled directly, through PWM input, or by the
62 ambient-light-sensor interface. The chip supports
63 hardware-accelerated blinking with maximum on and off periods of 9.8
64 and 77 seconds respectively.
65
53config LEDS_LOCOMO 66config LEDS_LOCOMO
54 tristate "LED Support for Locomo device" 67 tristate "LED Support for Locomo device"
55 depends on LEDS_CLASS 68 depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 4a4b96e8c3e..f8958cd6cf6 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
10obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o 10obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
11obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o 11obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
12obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o 12obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
13obj-$(CONFIG_LEDS_LM3533) += leds-lm3533.o
13obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o 14obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
14obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o 15obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
15obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o 16obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c
new file mode 100644
index 00000000000..f56b6e7ffda
--- /dev/null
+++ b/drivers/leds/leds-lm3533.c
@@ -0,0 +1,785 @@
1/*
2 * leds-lm3533.c -- LM3533 LED driver
3 *
4 * Copyright (C) 2011-2012 Texas Instruments
5 *
6 * Author: Johan Hovold <jhovold@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/leds.h>
17#include <linux/mfd/core.h>
18#include <linux/mutex.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <linux/workqueue.h>
22
23#include <linux/mfd/lm3533.h>
24
25
26#define LM3533_LVCTRLBANK_MIN 2
27#define LM3533_LVCTRLBANK_MAX 5
28#define LM3533_LVCTRLBANK_COUNT 4
29#define LM3533_RISEFALLTIME_MAX 7
30#define LM3533_ALS_CHANNEL_LV_MIN 1
31#define LM3533_ALS_CHANNEL_LV_MAX 2
32
33#define LM3533_REG_CTRLBANK_BCONF_BASE 0x1b
34#define LM3533_REG_PATTERN_ENABLE 0x28
35#define LM3533_REG_PATTERN_LOW_TIME_BASE 0x71
36#define LM3533_REG_PATTERN_HIGH_TIME_BASE 0x72
37#define LM3533_REG_PATTERN_RISETIME_BASE 0x74
38#define LM3533_REG_PATTERN_FALLTIME_BASE 0x75
39
40#define LM3533_REG_PATTERN_STEP 0x10
41
42#define LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK 0x04
43#define LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK 0x02
44#define LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK 0x01
45
46#define LM3533_LED_FLAG_PATTERN_ENABLE 1
47
48
49struct lm3533_led {
50 struct lm3533 *lm3533;
51 struct lm3533_ctrlbank cb;
52 struct led_classdev cdev;
53 int id;
54
55 struct mutex mutex;
56 unsigned long flags;
57
58 struct work_struct work;
59 u8 new_brightness;
60};
61
62
63static inline struct lm3533_led *to_lm3533_led(struct led_classdev *cdev)
64{
65 return container_of(cdev, struct lm3533_led, cdev);
66}
67
68static inline int lm3533_led_get_ctrlbank_id(struct lm3533_led *led)
69{
70 return led->id + 2;
71}
72
73static inline u8 lm3533_led_get_lv_reg(struct lm3533_led *led, u8 base)
74{
75 return base + led->id;
76}
77
78static inline u8 lm3533_led_get_pattern(struct lm3533_led *led)
79{
80 return led->id;
81}
82
83static inline u8 lm3533_led_get_pattern_reg(struct lm3533_led *led,
84 u8 base)
85{
86 return base + lm3533_led_get_pattern(led) * LM3533_REG_PATTERN_STEP;
87}
88
89static int lm3533_led_pattern_enable(struct lm3533_led *led, int enable)
90{
91 u8 mask;
92 u8 val;
93 int pattern;
94 int state;
95 int ret = 0;
96
97 dev_dbg(led->cdev.dev, "%s - %d\n", __func__, enable);
98
99 mutex_lock(&led->mutex);
100
101 state = test_bit(LM3533_LED_FLAG_PATTERN_ENABLE, &led->flags);
102 if ((enable && state) || (!enable && !state))
103 goto out;
104
105 pattern = lm3533_led_get_pattern(led);
106 mask = 1 << (2 * pattern);
107
108 if (enable)
109 val = mask;
110 else
111 val = 0;
112
113 ret = lm3533_update(led->lm3533, LM3533_REG_PATTERN_ENABLE, val, mask);
114 if (ret) {
115 dev_err(led->cdev.dev, "failed to enable pattern %d (%d)\n",
116 pattern, enable);
117 goto out;
118 }
119
120 __change_bit(LM3533_LED_FLAG_PATTERN_ENABLE, &led->flags);
121out:
122 mutex_unlock(&led->mutex);
123
124 return ret;
125}
126
127static void lm3533_led_work(struct work_struct *work)
128{
129 struct lm3533_led *led = container_of(work, struct lm3533_led, work);
130
131 dev_dbg(led->cdev.dev, "%s - %u\n", __func__, led->new_brightness);
132
133 if (led->new_brightness == 0)
134 lm3533_led_pattern_enable(led, 0); /* disable blink */
135
136 lm3533_ctrlbank_set_brightness(&led->cb, led->new_brightness);
137}
138
139static void lm3533_led_set(struct led_classdev *cdev,
140 enum led_brightness value)
141{
142 struct lm3533_led *led = to_lm3533_led(cdev);
143
144 dev_dbg(led->cdev.dev, "%s - %d\n", __func__, value);
145
146 led->new_brightness = value;
147 schedule_work(&led->work);
148}
149
150static enum led_brightness lm3533_led_get(struct led_classdev *cdev)
151{
152 struct lm3533_led *led = to_lm3533_led(cdev);
153 u8 val;
154 int ret;
155
156 ret = lm3533_ctrlbank_get_brightness(&led->cb, &val);
157 if (ret)
158 return ret;
159
160 dev_dbg(led->cdev.dev, "%s - %u\n", __func__, val);
161
162 return val;
163}
164
165/* Pattern generator defines (delays in us). */
166#define LM3533_LED_DELAY1_VMIN 0x00
167#define LM3533_LED_DELAY2_VMIN 0x3d
168#define LM3533_LED_DELAY3_VMIN 0x80
169
170#define LM3533_LED_DELAY1_VMAX (LM3533_LED_DELAY2_VMIN - 1)
171#define LM3533_LED_DELAY2_VMAX (LM3533_LED_DELAY3_VMIN - 1)
172#define LM3533_LED_DELAY3_VMAX 0xff
173
174#define LM3533_LED_DELAY1_TMIN 16384U
175#define LM3533_LED_DELAY2_TMIN 1130496U
176#define LM3533_LED_DELAY3_TMIN 10305536U
177
178#define LM3533_LED_DELAY1_TMAX 999424U
179#define LM3533_LED_DELAY2_TMAX 9781248U
180#define LM3533_LED_DELAY3_TMAX 76890112U
181
182/* t_step = (t_max - t_min) / (v_max - v_min) */
183#define LM3533_LED_DELAY1_TSTEP 16384
184#define LM3533_LED_DELAY2_TSTEP 131072
185#define LM3533_LED_DELAY3_TSTEP 524288
186
187/* Delay limits for hardware accelerated blinking (in ms). */
188#define LM3533_LED_DELAY_ON_MAX \
189 ((LM3533_LED_DELAY2_TMAX + LM3533_LED_DELAY2_TSTEP / 2) / 1000)
190#define LM3533_LED_DELAY_OFF_MAX \
191 ((LM3533_LED_DELAY3_TMAX + LM3533_LED_DELAY3_TSTEP / 2) / 1000)
192
193/*
194 * Returns linear map of *t from [t_min,t_max] to [v_min,v_max] with a step
195 * size of t_step, where
196 *
197 * t_step = (t_max - t_min) / (v_max - v_min)
198 *
199 * and updates *t to reflect the mapped value.
200 */
201static u8 time_to_val(unsigned *t, unsigned t_min, unsigned t_step,
202 u8 v_min, u8 v_max)
203{
204 unsigned val;
205
206 val = (*t + t_step / 2 - t_min) / t_step + v_min;
207
208 *t = t_step * (val - v_min) + t_min;
209
210 return (u8)val;
211}
212
213/*
214 * Returns time code corresponding to *delay (in ms) and updates *delay to
215 * reflect actual hardware delay.
216 *
217 * Hardware supports 256 discrete delay times, divided into three groups with
218 * the following ranges and step-sizes:
219 *
220 * [ 16, 999] [0x00, 0x3e] step 16 ms
221 * [ 1130, 9781] [0x3d, 0x7f] step 131 ms
222 * [10306, 76890] [0x80, 0xff] step 524 ms
223 *
224 * Note that delay group 3 is only available for delay_off.
225 */
226static u8 lm3533_led_get_hw_delay(unsigned *delay)
227{
228 unsigned t;
229 u8 val;
230
231 t = *delay * 1000;
232
233 if (t >= (LM3533_LED_DELAY2_TMAX + LM3533_LED_DELAY3_TMIN) / 2) {
234 t = clamp(t, LM3533_LED_DELAY3_TMIN, LM3533_LED_DELAY3_TMAX);
235 val = time_to_val(&t, LM3533_LED_DELAY3_TMIN,
236 LM3533_LED_DELAY3_TSTEP,
237 LM3533_LED_DELAY3_VMIN,
238 LM3533_LED_DELAY3_VMAX);
239 } else if (t >= (LM3533_LED_DELAY1_TMAX + LM3533_LED_DELAY2_TMIN) / 2) {
240 t = clamp(t, LM3533_LED_DELAY2_TMIN, LM3533_LED_DELAY2_TMAX);
241 val = time_to_val(&t, LM3533_LED_DELAY2_TMIN,
242 LM3533_LED_DELAY2_TSTEP,
243 LM3533_LED_DELAY2_VMIN,
244 LM3533_LED_DELAY2_VMAX);
245 } else {
246 t = clamp(t, LM3533_LED_DELAY1_TMIN, LM3533_LED_DELAY1_TMAX);
247 val = time_to_val(&t, LM3533_LED_DELAY1_TMIN,
248 LM3533_LED_DELAY1_TSTEP,
249 LM3533_LED_DELAY1_VMIN,
250 LM3533_LED_DELAY1_VMAX);
251 }
252
253 *delay = (t + 500) / 1000;
254
255 return val;
256}
257
258/*
259 * Set delay register base to *delay (in ms) and update *delay to reflect
260 * actual hardware delay used.
261 */
262static u8 lm3533_led_delay_set(struct lm3533_led *led, u8 base,
263 unsigned long *delay)
264{
265 unsigned t;
266 u8 val;
267 u8 reg;
268 int ret;
269
270 t = (unsigned)*delay;
271
272 /* Delay group 3 is only available for low time (delay off). */
273 if (base != LM3533_REG_PATTERN_LOW_TIME_BASE)
274 t = min(t, LM3533_LED_DELAY2_TMAX / 1000);
275
276 val = lm3533_led_get_hw_delay(&t);
277
278 dev_dbg(led->cdev.dev, "%s - %lu: %u (0x%02x)\n", __func__,
279 *delay, t, val);
280 reg = lm3533_led_get_pattern_reg(led, base);
281 ret = lm3533_write(led->lm3533, reg, val);
282 if (ret)
283 dev_err(led->cdev.dev, "failed to set delay (%02x)\n", reg);
284
285 *delay = t;
286
287 return ret;
288}
289
290static int lm3533_led_delay_on_set(struct lm3533_led *led, unsigned long *t)
291{
292 return lm3533_led_delay_set(led, LM3533_REG_PATTERN_HIGH_TIME_BASE, t);
293}
294
295static int lm3533_led_delay_off_set(struct lm3533_led *led, unsigned long *t)
296{
297 return lm3533_led_delay_set(led, LM3533_REG_PATTERN_LOW_TIME_BASE, t);
298}
299
300static int lm3533_led_blink_set(struct led_classdev *cdev,
301 unsigned long *delay_on,
302 unsigned long *delay_off)
303{
304 struct lm3533_led *led = to_lm3533_led(cdev);
305 int ret;
306
307 dev_dbg(led->cdev.dev, "%s - on = %lu, off = %lu\n", __func__,
308 *delay_on, *delay_off);
309
310 if (*delay_on > LM3533_LED_DELAY_ON_MAX ||
311 *delay_off > LM3533_LED_DELAY_OFF_MAX)
312 return -EINVAL;
313
314 if (*delay_on == 0 && *delay_off == 0) {
315 *delay_on = 500;
316 *delay_off = 500;
317 }
318
319 ret = lm3533_led_delay_on_set(led, delay_on);
320 if (ret)
321 return ret;
322
323 ret = lm3533_led_delay_off_set(led, delay_off);
324 if (ret)
325 return ret;
326
327 return lm3533_led_pattern_enable(led, 1);
328}
329
330static ssize_t show_id(struct device *dev,
331 struct device_attribute *attr, char *buf)
332{
333 struct led_classdev *led_cdev = dev_get_drvdata(dev);
334 struct lm3533_led *led = to_lm3533_led(led_cdev);
335
336 return scnprintf(buf, PAGE_SIZE, "%d\n", led->id);
337}
338
339/*
340 * Pattern generator rise/fall times:
341 *
342 * 0 - 2048 us (default)
343 * 1 - 262 ms
344 * 2 - 524 ms
345 * 3 - 1.049 s
346 * 4 - 2.097 s
347 * 5 - 4.194 s
348 * 6 - 8.389 s
349 * 7 - 16.78 s
350 */
351static ssize_t show_risefalltime(struct device *dev,
352 struct device_attribute *attr,
353 char *buf, u8 base)
354{
355 struct led_classdev *led_cdev = dev_get_drvdata(dev);
356 struct lm3533_led *led = to_lm3533_led(led_cdev);
357 ssize_t ret;
358 u8 reg;
359 u8 val;
360
361 reg = lm3533_led_get_pattern_reg(led, base);
362 ret = lm3533_read(led->lm3533, reg, &val);
363 if (ret)
364 return ret;
365
366 return scnprintf(buf, PAGE_SIZE, "%x\n", val);
367}
368
369static ssize_t show_risetime(struct device *dev,
370 struct device_attribute *attr, char *buf)
371{
372 return show_risefalltime(dev, attr, buf,
373 LM3533_REG_PATTERN_RISETIME_BASE);
374}
375
376static ssize_t show_falltime(struct device *dev,
377 struct device_attribute *attr, char *buf)
378{
379 return show_risefalltime(dev, attr, buf,
380 LM3533_REG_PATTERN_FALLTIME_BASE);
381}
382
383static ssize_t store_risefalltime(struct device *dev,
384 struct device_attribute *attr,
385 const char *buf, size_t len, u8 base)
386{
387 struct led_classdev *led_cdev = dev_get_drvdata(dev);
388 struct lm3533_led *led = to_lm3533_led(led_cdev);
389 u8 val;
390 u8 reg;
391 int ret;
392
393 if (kstrtou8(buf, 0, &val) || val > LM3533_RISEFALLTIME_MAX)
394 return -EINVAL;
395
396 reg = lm3533_led_get_pattern_reg(led, base);
397 ret = lm3533_write(led->lm3533, reg, val);
398 if (ret)
399 return ret;
400
401 return len;
402}
403
404static ssize_t store_risetime(struct device *dev,
405 struct device_attribute *attr,
406 const char *buf, size_t len)
407{
408 return store_risefalltime(dev, attr, buf, len,
409 LM3533_REG_PATTERN_RISETIME_BASE);
410}
411
412static ssize_t store_falltime(struct device *dev,
413 struct device_attribute *attr,
414 const char *buf, size_t len)
415{
416 return store_risefalltime(dev, attr, buf, len,
417 LM3533_REG_PATTERN_FALLTIME_BASE);
418}
419
420static ssize_t show_als_channel(struct device *dev,
421 struct device_attribute *attr, char *buf)
422{
423 struct led_classdev *led_cdev = dev_get_drvdata(dev);
424 struct lm3533_led *led = to_lm3533_led(led_cdev);
425 unsigned channel;
426 u8 reg;
427 u8 val;
428 int ret;
429
430 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
431 ret = lm3533_read(led->lm3533, reg, &val);
432 if (ret)
433 return ret;
434
435 channel = (val & LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK) + 1;
436
437 return scnprintf(buf, PAGE_SIZE, "%u\n", channel);
438}
439
440static ssize_t store_als_channel(struct device *dev,
441 struct device_attribute *attr,
442 const char *buf, size_t len)
443{
444 struct led_classdev *led_cdev = dev_get_drvdata(dev);
445 struct lm3533_led *led = to_lm3533_led(led_cdev);
446 unsigned channel;
447 u8 reg;
448 u8 val;
449 u8 mask;
450 int ret;
451
452 if (kstrtouint(buf, 0, &channel))
453 return -EINVAL;
454
455 if (channel < LM3533_ALS_CHANNEL_LV_MIN ||
456 channel > LM3533_ALS_CHANNEL_LV_MAX)
457 return -EINVAL;
458
459 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
460 mask = LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK;
461 val = channel - 1;
462
463 ret = lm3533_update(led->lm3533, reg, val, mask);
464 if (ret)
465 return ret;
466
467 return len;
468}
469
470static ssize_t show_als_en(struct device *dev,
471 struct device_attribute *attr, char *buf)
472{
473 struct led_classdev *led_cdev = dev_get_drvdata(dev);
474 struct lm3533_led *led = to_lm3533_led(led_cdev);
475 bool enable;
476 u8 reg;
477 u8 val;
478 int ret;
479
480 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
481 ret = lm3533_read(led->lm3533, reg, &val);
482 if (ret)
483 return ret;
484
485 enable = val & LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK;
486
487 return scnprintf(buf, PAGE_SIZE, "%d\n", enable);
488}
489
490static ssize_t store_als_en(struct device *dev,
491 struct device_attribute *attr,
492 const char *buf, size_t len)
493{
494 struct led_classdev *led_cdev = dev_get_drvdata(dev);
495 struct lm3533_led *led = to_lm3533_led(led_cdev);
496 unsigned enable;
497 u8 reg;
498 u8 mask;
499 u8 val;
500 int ret;
501
502 if (kstrtouint(buf, 0, &enable))
503 return -EINVAL;
504
505 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
506 mask = LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK;
507
508 if (enable)
509 val = mask;
510 else
511 val = 0;
512
513 ret = lm3533_update(led->lm3533, reg, val, mask);
514 if (ret)
515 return ret;
516
517 return len;
518}
519
520static ssize_t show_linear(struct device *dev,
521 struct device_attribute *attr, char *buf)
522{
523 struct led_classdev *led_cdev = dev_get_drvdata(dev);
524 struct lm3533_led *led = to_lm3533_led(led_cdev);
525 u8 reg;
526 u8 val;
527 int linear;
528 int ret;
529
530 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
531 ret = lm3533_read(led->lm3533, reg, &val);
532 if (ret)
533 return ret;
534
535 if (val & LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK)
536 linear = 1;
537 else
538 linear = 0;
539
540 return scnprintf(buf, PAGE_SIZE, "%x\n", linear);
541}
542
543static ssize_t store_linear(struct device *dev,
544 struct device_attribute *attr,
545 const char *buf, size_t len)
546{
547 struct led_classdev *led_cdev = dev_get_drvdata(dev);
548 struct lm3533_led *led = to_lm3533_led(led_cdev);
549 unsigned long linear;
550 u8 reg;
551 u8 mask;
552 u8 val;
553 int ret;
554
555 if (kstrtoul(buf, 0, &linear))
556 return -EINVAL;
557
558 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
559 mask = LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK;
560
561 if (linear)
562 val = mask;
563 else
564 val = 0;
565
566 ret = lm3533_update(led->lm3533, reg, val, mask);
567 if (ret)
568 return ret;
569
570 return len;
571}
572
573static ssize_t show_pwm(struct device *dev,
574 struct device_attribute *attr,
575 char *buf)
576{
577 struct led_classdev *led_cdev = dev_get_drvdata(dev);
578 struct lm3533_led *led = to_lm3533_led(led_cdev);
579 u8 val;
580 int ret;
581
582 ret = lm3533_ctrlbank_get_pwm(&led->cb, &val);
583 if (ret)
584 return ret;
585
586 return scnprintf(buf, PAGE_SIZE, "%u\n", val);
587}
588
589static ssize_t store_pwm(struct device *dev,
590 struct device_attribute *attr,
591 const char *buf, size_t len)
592{
593 struct led_classdev *led_cdev = dev_get_drvdata(dev);
594 struct lm3533_led *led = to_lm3533_led(led_cdev);
595 u8 val;
596 int ret;
597
598 if (kstrtou8(buf, 0, &val))
599 return -EINVAL;
600
601 ret = lm3533_ctrlbank_set_pwm(&led->cb, val);
602 if (ret)
603 return ret;
604
605 return len;
606}
607
608static LM3533_ATTR_RW(als_channel);
609static LM3533_ATTR_RW(als_en);
610static LM3533_ATTR_RW(falltime);
611static LM3533_ATTR_RO(id);
612static LM3533_ATTR_RW(linear);
613static LM3533_ATTR_RW(pwm);
614static LM3533_ATTR_RW(risetime);
615
616static struct attribute *lm3533_led_attributes[] = {
617 &dev_attr_als_channel.attr,
618 &dev_attr_als_en.attr,
619 &dev_attr_falltime.attr,
620 &dev_attr_id.attr,
621 &dev_attr_linear.attr,
622 &dev_attr_pwm.attr,
623 &dev_attr_risetime.attr,
624 NULL,
625};
626
627static umode_t lm3533_led_attr_is_visible(struct kobject *kobj,
628 struct attribute *attr, int n)
629{
630 struct device *dev = container_of(kobj, struct device, kobj);
631 struct led_classdev *led_cdev = dev_get_drvdata(dev);
632 struct lm3533_led *led = to_lm3533_led(led_cdev);
633 umode_t mode = attr->mode;
634
635 if (attr == &dev_attr_als_channel.attr ||
636 attr == &dev_attr_als_en.attr) {
637 if (!led->lm3533->have_als)
638 mode = 0;
639 }
640
641 return mode;
642};
643
644static struct attribute_group lm3533_led_attribute_group = {
645 .is_visible = lm3533_led_attr_is_visible,
646 .attrs = lm3533_led_attributes
647};
648
649static int __devinit lm3533_led_setup(struct lm3533_led *led,
650 struct lm3533_led_platform_data *pdata)
651{
652 int ret;
653
654 ret = lm3533_ctrlbank_set_max_current(&led->cb, pdata->max_current);
655 if (ret)
656 return ret;
657
658 return lm3533_ctrlbank_set_pwm(&led->cb, pdata->pwm);
659}
660
661static int __devinit lm3533_led_probe(struct platform_device *pdev)
662{
663 struct lm3533 *lm3533;
664 struct lm3533_led_platform_data *pdata;
665 struct lm3533_led *led;
666 int ret;
667
668 dev_dbg(&pdev->dev, "%s\n", __func__);
669
670 lm3533 = dev_get_drvdata(pdev->dev.parent);
671 if (!lm3533)
672 return -EINVAL;
673
674 pdata = pdev->dev.platform_data;
675 if (!pdata) {
676 dev_err(&pdev->dev, "no platform data\n");
677 return -EINVAL;
678 }
679
680 if (pdev->id < 0 || pdev->id >= LM3533_LVCTRLBANK_COUNT) {
681 dev_err(&pdev->dev, "illegal LED id %d\n", pdev->id);
682 return -EINVAL;
683 }
684
685 led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
686 if (!led)
687 return -ENOMEM;
688
689 led->lm3533 = lm3533;
690 led->cdev.name = pdata->name;
691 led->cdev.default_trigger = pdata->default_trigger;
692 led->cdev.brightness_set = lm3533_led_set;
693 led->cdev.brightness_get = lm3533_led_get;
694 led->cdev.blink_set = lm3533_led_blink_set;
695 led->cdev.brightness = LED_OFF;
696 led->id = pdev->id;
697
698 mutex_init(&led->mutex);
699 INIT_WORK(&led->work, lm3533_led_work);
700
701 /* The class framework makes a callback to get brightness during
702 * registration so use parent device (for error reporting) until
703 * registered.
704 */
705 led->cb.lm3533 = lm3533;
706 led->cb.id = lm3533_led_get_ctrlbank_id(led);
707 led->cb.dev = lm3533->dev;
708
709 platform_set_drvdata(pdev, led);
710
711 ret = led_classdev_register(pdev->dev.parent, &led->cdev);
712 if (ret) {
713 dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id);
714 return ret;
715 }
716
717 led->cb.dev = led->cdev.dev;
718
719 ret = sysfs_create_group(&led->cdev.dev->kobj,
720 &lm3533_led_attribute_group);
721 if (ret < 0) {
722 dev_err(&pdev->dev, "failed to create sysfs attributes\n");
723 goto err_unregister;
724 }
725
726 ret = lm3533_led_setup(led, pdata);
727 if (ret)
728 goto err_sysfs_remove;
729
730 ret = lm3533_ctrlbank_enable(&led->cb);
731 if (ret)
732 goto err_sysfs_remove;
733
734 return 0;
735
736err_sysfs_remove:
737 sysfs_remove_group(&led->cdev.dev->kobj, &lm3533_led_attribute_group);
738err_unregister:
739 led_classdev_unregister(&led->cdev);
740 flush_work_sync(&led->work);
741
742 return ret;
743}
744
745static int __devexit lm3533_led_remove(struct platform_device *pdev)
746{
747 struct lm3533_led *led = platform_get_drvdata(pdev);
748
749 dev_dbg(&pdev->dev, "%s\n", __func__);
750
751 lm3533_ctrlbank_disable(&led->cb);
752 sysfs_remove_group(&led->cdev.dev->kobj, &lm3533_led_attribute_group);
753 led_classdev_unregister(&led->cdev);
754 flush_work_sync(&led->work);
755
756 return 0;
757}
758
759static void lm3533_led_shutdown(struct platform_device *pdev)
760{
761
762 struct lm3533_led *led = platform_get_drvdata(pdev);
763
764 dev_dbg(&pdev->dev, "%s\n", __func__);
765
766 lm3533_ctrlbank_disable(&led->cb);
767 lm3533_led_set(&led->cdev, LED_OFF); /* disable blink */
768 flush_work_sync(&led->work);
769}
770
771static struct platform_driver lm3533_led_driver = {
772 .driver = {
773 .name = "lm3533-leds",
774 .owner = THIS_MODULE,
775 },
776 .probe = lm3533_led_probe,
777 .remove = __devexit_p(lm3533_led_remove),
778 .shutdown = lm3533_led_shutdown,
779};
780module_platform_driver(lm3533_led_driver);
781
782MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
783MODULE_DESCRIPTION("LM3533 LED driver");
784MODULE_LICENSE("GPL");
785MODULE_ALIAS("platform:lm3533-leds");