aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorG.Shark Jeong <gshark.jeong@gmail.com>2012-09-05 03:05:58 -0400
committerBryan Wu <bryan.wu@canonical.com>2012-09-11 06:32:43 -0400
commitb98d13c725920e9ab7696e0d7d19c4db1bdf6737 (patch)
tree024bbd7b47d783f94b7f9fed71f25b406d31727c /drivers/leds
parent56a1e9adc83870ae9ad9ff1bf9fd8bccebdfe065 (diff)
leds: Add new LED driver for lm355x chips
This driver is a general version for LM355x,lm3554 and lm3556,led chips of TI. LM3554 : The LM3554 is a 2 MHz fixed-frequency synchronous boost converter with 1.2A dual high side led drivers. Datasheet: www.ti.com/lit/ds/symlink/lm3554.pdf LM3556 : The LM3556 is a 4 MHz fixed-frequency synchronous boost converter plus 1.5A constant current driver for a high-current white LED. Datasheet: www.national.com/ds/LM/LM3556.pdf (bryan.wu@canonical.com: use flush_work() to replace flush_work_sync() which is deprecated) Signed-off-by: G.Shark Jeong <gshark.jeong@gmail.com> Signed-off-by: Bryan Wu <bryan.wu@canonical.com>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig8
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/leds-lm3556.c512
-rw-r--r--drivers/leds/leds-lm355x.c572
4 files changed, 577 insertions, 517 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 86ea15a127f7..0dcb794df1fa 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -423,13 +423,13 @@ config LEDS_MAX8997
423 This option enables support for on-chip LED drivers on 423 This option enables support for on-chip LED drivers on
424 MAXIM MAX8997 PMIC. 424 MAXIM MAX8997 PMIC.
425 425
426config LEDS_LM3556 426config LEDS_LM355x
427 tristate "LED support for LM3556 Chip" 427 tristate "LED support for LM355x Chips, LM3554 and LM3556"
428 depends on LEDS_CLASS && I2C 428 depends on LEDS_CLASS && I2C
429 select REGMAP_I2C 429 select REGMAP_I2C
430 help 430 help
431 This option enables support for LEDs connected to LM3556. 431 This option enables support for LEDs connected to LM355x.
432 LM3556 includes Torch, Flash and Indicator functions. 432 LM355x includes Torch, Flash and Indicator functions.
433 433
434config LEDS_OT200 434config LEDS_OT200
435 tristate "LED support for the Bachmann OT200" 435 tristate "LED support for the Bachmann OT200"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index a4429a9217bc..b57a021d1fea 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -48,7 +48,7 @@ obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
48obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o 48obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
49obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o 49obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o
50obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o 50obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
51obj-$(CONFIG_LEDS_LM3556) += leds-lm3556.o 51obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
52obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o 52obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o
53 53
54# LED SPI Drivers 54# LED SPI Drivers
diff --git a/drivers/leds/leds-lm3556.c b/drivers/leds/leds-lm3556.c
deleted file mode 100644
index 3062abd9a532..000000000000
--- a/drivers/leds/leds-lm3556.c
+++ /dev/null
@@ -1,512 +0,0 @@
1/*
2 * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
3 * Copyright (C) 2012 Texas Instruments
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Please refer Documentation/leds/leds-lm3556.txt file.
10 */
11#include <linux/module.h>
12#include <linux/delay.h>
13#include <linux/i2c.h>
14#include <linux/leds.h>
15#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/fs.h>
18#include <linux/regmap.h>
19#include <linux/platform_data/leds-lm3556.h>
20
21#define REG_FILT_TIME (0x0)
22#define REG_IVFM_MODE (0x1)
23#define REG_NTC (0x2)
24#define REG_INDIC_TIME (0x3)
25#define REG_INDIC_BLINK (0x4)
26#define REG_INDIC_PERIOD (0x5)
27#define REG_TORCH_TIME (0x6)
28#define REG_CONF (0x7)
29#define REG_FLASH (0x8)
30#define REG_I_CTRL (0x9)
31#define REG_ENABLE (0xA)
32#define REG_FLAG (0xB)
33#define REG_MAX (0xB)
34
35#define IVFM_FILTER_TIME_SHIFT (3)
36#define UVLO_EN_SHIFT (7)
37#define HYSTERSIS_SHIFT (5)
38#define IVM_D_TH_SHIFT (2)
39#define IVFM_ADJ_MODE_SHIFT (0)
40#define NTC_EVENT_LVL_SHIFT (5)
41#define NTC_TRIP_TH_SHIFT (2)
42#define NTC_BIAS_I_LVL_SHIFT (0)
43#define INDIC_RAMP_UP_TIME_SHIFT (3)
44#define INDIC_RAMP_DN_TIME_SHIFT (0)
45#define INDIC_N_BLANK_SHIFT (4)
46#define INDIC_PULSE_TIME_SHIFT (0)
47#define INDIC_N_PERIOD_SHIFT (0)
48#define TORCH_RAMP_UP_TIME_SHIFT (3)
49#define TORCH_RAMP_DN_TIME_SHIFT (0)
50#define STROBE_USUAGE_SHIFT (7)
51#define STROBE_PIN_POLARITY_SHIFT (6)
52#define TORCH_PIN_POLARITY_SHIFT (5)
53#define TX_PIN_POLARITY_SHIFT (4)
54#define TX_EVENT_LVL_SHIFT (3)
55#define IVFM_EN_SHIFT (2)
56#define NTC_MODE_SHIFT (1)
57#define INDIC_MODE_SHIFT (0)
58#define INDUCTOR_I_LIMIT_SHIFT (6)
59#define FLASH_RAMP_TIME_SHIFT (3)
60#define FLASH_TOUT_TIME_SHIFT (0)
61#define TORCH_I_SHIFT (4)
62#define FLASH_I_SHIFT (0)
63#define NTC_EN_SHIFT (7)
64#define TX_PIN_EN_SHIFT (6)
65#define STROBE_PIN_EN_SHIFT (5)
66#define TORCH_PIN_EN_SHIFT (4)
67#define PRECHG_MODE_EN_SHIFT (3)
68#define PASS_MODE_ONLY_EN_SHIFT (2)
69#define MODE_BITS_SHIFT (0)
70
71#define IVFM_FILTER_TIME_MASK (0x3)
72#define UVLO_EN_MASK (0x1)
73#define HYSTERSIS_MASK (0x3)
74#define IVM_D_TH_MASK (0x7)
75#define IVFM_ADJ_MODE_MASK (0x3)
76#define NTC_EVENT_LVL_MASK (0x1)
77#define NTC_TRIP_TH_MASK (0x7)
78#define NTC_BIAS_I_LVL_MASK (0x3)
79#define INDIC_RAMP_UP_TIME_MASK (0x7)
80#define INDIC_RAMP_DN_TIME_MASK (0x7)
81#define INDIC_N_BLANK_MASK (0x7)
82#define INDIC_PULSE_TIME_MASK (0x7)
83#define INDIC_N_PERIOD_MASK (0x7)
84#define TORCH_RAMP_UP_TIME_MASK (0x7)
85#define TORCH_RAMP_DN_TIME_MASK (0x7)
86#define STROBE_USUAGE_MASK (0x1)
87#define STROBE_PIN_POLARITY_MASK (0x1)
88#define TORCH_PIN_POLARITY_MASK (0x1)
89#define TX_PIN_POLARITY_MASK (0x1)
90#define TX_EVENT_LVL_MASK (0x1)
91#define IVFM_EN_MASK (0x1)
92#define NTC_MODE_MASK (0x1)
93#define INDIC_MODE_MASK (0x1)
94#define INDUCTOR_I_LIMIT_MASK (0x3)
95#define FLASH_RAMP_TIME_MASK (0x7)
96#define FLASH_TOUT_TIME_MASK (0x7)
97#define TORCH_I_MASK (0x7)
98#define FLASH_I_MASK (0xF)
99#define NTC_EN_MASK (0x1)
100#define TX_PIN_EN_MASK (0x1)
101#define STROBE_PIN_EN_MASK (0x1)
102#define TORCH_PIN_EN_MASK (0x1)
103#define PRECHG_MODE_EN_MASK (0x1)
104#define PASS_MODE_ONLY_EN_MASK (0x1)
105#define MODE_BITS_MASK (0x13)
106#define EX_PIN_CONTROL_MASK (0xF1)
107#define EX_PIN_ENABLE_MASK (0x70)
108
109enum lm3556_indic_pulse_time {
110 PULSE_TIME_0_MS = 0,
111 PULSE_TIME_32_MS,
112 PULSE_TIME_64_MS,
113 PULSE_TIME_92_MS,
114 PULSE_TIME_128_MS,
115 PULSE_TIME_160_MS,
116 PULSE_TIME_196_MS,
117 PULSE_TIME_224_MS,
118 PULSE_TIME_256_MS,
119 PULSE_TIME_288_MS,
120 PULSE_TIME_320_MS,
121 PULSE_TIME_352_MS,
122 PULSE_TIME_384_MS,
123 PULSE_TIME_416_MS,
124 PULSE_TIME_448_MS,
125 PULSE_TIME_480_MS,
126};
127
128enum lm3556_indic_n_blank {
129 INDIC_N_BLANK_0 = 0,
130 INDIC_N_BLANK_1,
131 INDIC_N_BLANK_2,
132 INDIC_N_BLANK_3,
133 INDIC_N_BLANK_4,
134 INDIC_N_BLANK_5,
135 INDIC_N_BLANK_6,
136 INDIC_N_BLANK_7,
137 INDIC_N_BLANK_8,
138 INDIC_N_BLANK_9,
139 INDIC_N_BLANK_10,
140 INDIC_N_BLANK_11,
141 INDIC_N_BLANK_12,
142 INDIC_N_BLANK_13,
143 INDIC_N_BLANK_14,
144 INDIC_N_BLANK_15,
145};
146
147enum lm3556_indic_period {
148 INDIC_PERIOD_0 = 0,
149 INDIC_PERIOD_1,
150 INDIC_PERIOD_2,
151 INDIC_PERIOD_3,
152 INDIC_PERIOD_4,
153 INDIC_PERIOD_5,
154 INDIC_PERIOD_6,
155 INDIC_PERIOD_7,
156};
157
158enum lm3556_mode {
159 MODES_STASNDBY = 0,
160 MODES_INDIC,
161 MODES_TORCH,
162 MODES_FLASH
163};
164
165#define INDIC_PATTERN_SIZE 4
166
167struct indicator {
168 u8 blinking;
169 u8 period_cnt;
170};
171
172struct lm3556_chip_data {
173 struct device *dev;
174
175 struct led_classdev cdev_flash;
176 struct led_classdev cdev_torch;
177 struct led_classdev cdev_indicator;
178
179 struct lm3556_platform_data *pdata;
180 struct regmap *regmap;
181 struct mutex lock;
182
183 unsigned int last_flag;
184};
185
186/* indicator pattern */
187static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
188 [0] = {(INDIC_N_BLANK_1 << INDIC_N_BLANK_SHIFT)
189 | PULSE_TIME_32_MS, INDIC_PERIOD_1},
190 [1] = {(INDIC_N_BLANK_15 << INDIC_N_BLANK_SHIFT)
191 | PULSE_TIME_32_MS, INDIC_PERIOD_2},
192 [2] = {(INDIC_N_BLANK_10 << INDIC_N_BLANK_SHIFT)
193 | PULSE_TIME_32_MS, INDIC_PERIOD_4},
194 [3] = {(INDIC_N_BLANK_5 << INDIC_N_BLANK_SHIFT)
195 | PULSE_TIME_32_MS, INDIC_PERIOD_7},
196};
197
198/* chip initialize */
199static int __devinit lm3556_chip_init(struct lm3556_chip_data *chip)
200{
201 unsigned int reg_val;
202 int ret;
203 struct lm3556_platform_data *pdata = chip->pdata;
204
205 /* set config register */
206 ret = regmap_read(chip->regmap, REG_CONF, &reg_val);
207 if (ret < 0) {
208 dev_err(chip->dev, "Failed to read REG_CONF Register\n");
209 goto out;
210 }
211
212 reg_val &= (~EX_PIN_CONTROL_MASK);
213 reg_val |= ((pdata->torch_pin_polarity & 0x01)
214 << TORCH_PIN_POLARITY_SHIFT);
215 reg_val |= ((pdata->strobe_usuage & 0x01) << STROBE_USUAGE_SHIFT);
216 reg_val |= ((pdata->strobe_pin_polarity & 0x01)
217 << STROBE_PIN_POLARITY_SHIFT);
218 reg_val |= ((pdata->tx_pin_polarity & 0x01) << TX_PIN_POLARITY_SHIFT);
219 reg_val |= ((pdata->indicator_mode & 0x01) << INDIC_MODE_SHIFT);
220
221 ret = regmap_write(chip->regmap, REG_CONF, reg_val);
222 if (ret < 0) {
223 dev_err(chip->dev, "Failed to write REG_CONF Regisgter\n");
224 goto out;
225 }
226
227 /* set enable register */
228 ret = regmap_read(chip->regmap, REG_ENABLE, &reg_val);
229 if (ret < 0) {
230 dev_err(chip->dev, "Failed to read REG_ENABLE Register\n");
231 goto out;
232 }
233
234 reg_val &= (~EX_PIN_ENABLE_MASK);
235 reg_val |= ((pdata->torch_pin_en & 0x01) << TORCH_PIN_EN_SHIFT);
236 reg_val |= ((pdata->strobe_pin_en & 0x01) << STROBE_PIN_EN_SHIFT);
237 reg_val |= ((pdata->tx_pin_en & 0x01) << TX_PIN_EN_SHIFT);
238
239 ret = regmap_write(chip->regmap, REG_ENABLE, reg_val);
240 if (ret < 0) {
241 dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
242 goto out;
243 }
244
245out:
246 return ret;
247}
248
249/* chip control */
250static int lm3556_control(struct lm3556_chip_data *chip,
251 u8 brightness, enum lm3556_mode opmode)
252{
253 int ret;
254 struct lm3556_platform_data *pdata = chip->pdata;
255
256 ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
257 if (ret < 0) {
258 dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
259 goto out;
260 }
261
262 if (chip->last_flag)
263 dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);
264
265 /* brightness 0 means off-state */
266 if (!brightness)
267 opmode = MODES_STASNDBY;
268
269 switch (opmode) {
270 case MODES_TORCH:
271 ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
272 TORCH_I_MASK << TORCH_I_SHIFT,
273 (brightness - 1) << TORCH_I_SHIFT);
274
275 if (pdata->torch_pin_en)
276 opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
277 break;
278
279 case MODES_FLASH:
280 ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
281 FLASH_I_MASK << FLASH_I_SHIFT,
282 (brightness - 1) << FLASH_I_SHIFT);
283 break;
284
285 case MODES_INDIC:
286 ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
287 TORCH_I_MASK << TORCH_I_SHIFT,
288 (brightness - 1) << TORCH_I_SHIFT);
289 break;
290
291 case MODES_STASNDBY:
292 if (pdata->torch_pin_en)
293 opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
294 break;
295
296 default:
297 return ret;
298 }
299 if (ret < 0) {
300 dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
301 goto out;
302 }
303 ret = regmap_update_bits(chip->regmap, REG_ENABLE,
304 MODE_BITS_MASK << MODE_BITS_SHIFT,
305 opmode << MODE_BITS_SHIFT);
306
307out:
308 return ret;
309}
310
311/* torch */
312static void lm3556_torch_brightness_set(struct led_classdev *cdev,
313 enum led_brightness brightness)
314{
315 struct lm3556_chip_data *chip =
316 container_of(cdev, struct lm3556_chip_data, cdev_torch);
317
318 mutex_lock(&chip->lock);
319 lm3556_control(chip, brightness, MODES_TORCH);
320 mutex_unlock(&chip->lock);
321}
322
323/* flash */
324static void lm3556_strobe_brightness_set(struct led_classdev *cdev,
325 enum led_brightness brightness)
326{
327 struct lm3556_chip_data *chip =
328 container_of(cdev, struct lm3556_chip_data, cdev_flash);
329
330 mutex_lock(&chip->lock);
331 lm3556_control(chip, brightness, MODES_FLASH);
332 mutex_unlock(&chip->lock);
333}
334
335/* indicator */
336static void lm3556_indicator_brightness_set(struct led_classdev *cdev,
337 enum led_brightness brightness)
338{
339 struct lm3556_chip_data *chip =
340 container_of(cdev, struct lm3556_chip_data, cdev_indicator);
341
342 mutex_lock(&chip->lock);
343 lm3556_control(chip, brightness, MODES_INDIC);
344 mutex_unlock(&chip->lock);
345}
346
347/* indicator pattern */
348static ssize_t lm3556_indicator_pattern_store(struct device *dev,
349 struct device_attribute *devAttr,
350 const char *buf, size_t size)
351{
352 ssize_t ret;
353 struct led_classdev *led_cdev = dev_get_drvdata(dev);
354 struct lm3556_chip_data *chip =
355 container_of(led_cdev, struct lm3556_chip_data, cdev_indicator);
356 unsigned int state;
357
358 ret = kstrtouint(buf, 10, &state);
359 if (ret)
360 goto out;
361 if (state > INDIC_PATTERN_SIZE - 1)
362 state = INDIC_PATTERN_SIZE - 1;
363
364 ret = regmap_write(chip->regmap, REG_INDIC_BLINK,
365 indicator_pattern[state].blinking);
366 if (ret < 0) {
367 dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
368 goto out;
369 }
370
371 ret = regmap_write(chip->regmap, REG_INDIC_PERIOD,
372 indicator_pattern[state].period_cnt);
373 if (ret < 0) {
374 dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
375 goto out;
376 }
377
378 return size;
379out:
380 dev_err(chip->dev, "Indicator pattern doesn't saved\n");
381 return size;
382}
383
384static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
385
386static const struct regmap_config lm3556_regmap = {
387 .reg_bits = 8,
388 .val_bits = 8,
389 .max_register = REG_MAX,
390};
391
392/* module initialize */
393static int __devinit lm3556_probe(struct i2c_client *client,
394 const struct i2c_device_id *id)
395{
396 struct lm3556_platform_data *pdata = client->dev.platform_data;
397 struct lm3556_chip_data *chip;
398
399 int err;
400
401 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
402 dev_err(&client->dev, "i2c functionality check fail.\n");
403 return -EOPNOTSUPP;
404 }
405
406 if (pdata == NULL) {
407 dev_err(&client->dev, "Needs Platform Data.\n");
408 return -ENODATA;
409 }
410
411 chip =
412 devm_kzalloc(&client->dev, sizeof(struct lm3556_chip_data),
413 GFP_KERNEL);
414 if (!chip)
415 return -ENOMEM;
416
417 chip->dev = &client->dev;
418 chip->pdata = pdata;
419
420 chip->regmap = devm_regmap_init_i2c(client, &lm3556_regmap);
421 if (IS_ERR(chip->regmap)) {
422 err = PTR_ERR(chip->regmap);
423 dev_err(&client->dev, "Failed to allocate register map: %d\n",
424 err);
425 return err;
426 }
427
428 mutex_init(&chip->lock);
429 i2c_set_clientdata(client, chip);
430
431 err = lm3556_chip_init(chip);
432 if (err < 0)
433 goto err_out;
434
435 /* flash */
436 chip->cdev_flash.name = "flash";
437 chip->cdev_flash.max_brightness = 16;
438 chip->cdev_flash.brightness_set = lm3556_strobe_brightness_set;
439 err = led_classdev_register((struct device *)
440 &client->dev, &chip->cdev_flash);
441 if (err < 0)
442 goto err_out;
443 /* torch */
444 chip->cdev_torch.name = "torch";
445 chip->cdev_torch.max_brightness = 8;
446 chip->cdev_torch.brightness_set = lm3556_torch_brightness_set;
447 err = led_classdev_register((struct device *)
448 &client->dev, &chip->cdev_torch);
449 if (err < 0)
450 goto err_create_torch_file;
451 /* indicator */
452 chip->cdev_indicator.name = "indicator";
453 chip->cdev_indicator.max_brightness = 8;
454 chip->cdev_indicator.brightness_set = lm3556_indicator_brightness_set;
455 err = led_classdev_register((struct device *)
456 &client->dev, &chip->cdev_indicator);
457 if (err < 0)
458 goto err_create_indicator_file;
459
460 err = device_create_file(chip->cdev_indicator.dev, &dev_attr_pattern);
461 if (err < 0)
462 goto err_create_pattern_file;
463
464 dev_info(&client->dev, "LM3556 is initialized\n");
465 return 0;
466
467err_create_pattern_file:
468 led_classdev_unregister(&chip->cdev_indicator);
469err_create_indicator_file:
470 led_classdev_unregister(&chip->cdev_torch);
471err_create_torch_file:
472 led_classdev_unregister(&chip->cdev_flash);
473err_out:
474 return err;
475}
476
477static int __devexit lm3556_remove(struct i2c_client *client)
478{
479 struct lm3556_chip_data *chip = i2c_get_clientdata(client);
480
481 device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern);
482 led_classdev_unregister(&chip->cdev_indicator);
483 led_classdev_unregister(&chip->cdev_torch);
484 led_classdev_unregister(&chip->cdev_flash);
485 regmap_write(chip->regmap, REG_ENABLE, 0);
486 return 0;
487}
488
489static const struct i2c_device_id lm3556_id[] = {
490 {LM3556_NAME, 0},
491 {}
492};
493
494MODULE_DEVICE_TABLE(i2c, lm3556_id);
495
496static struct i2c_driver lm3556_i2c_driver = {
497 .driver = {
498 .name = LM3556_NAME,
499 .owner = THIS_MODULE,
500 .pm = NULL,
501 },
502 .probe = lm3556_probe,
503 .remove = __devexit_p(lm3556_remove),
504 .id_table = lm3556_id,
505};
506
507module_i2c_driver(lm3556_i2c_driver);
508
509MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3556");
510MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
511MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
512MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c
new file mode 100644
index 000000000000..065ec015d67a
--- /dev/null
+++ b/drivers/leds/leds-lm355x.c
@@ -0,0 +1,572 @@
1/*
2* Simple driver for Texas Instruments LM355x LED Flash driver chip
3* Copyright (C) 2012 Texas Instruments
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License version 2 as
7* published by the Free Software Foundation.
8*/
9
10#include <linux/module.h>
11#include <linux/delay.h>
12#include <linux/i2c.h>
13#include <linux/gpio.h>
14#include <linux/leds.h>
15#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/fs.h>
18#include <linux/regmap.h>
19#include <linux/workqueue.h>
20#include <linux/platform_data/leds-lm355x.h>
21
22enum lm355x_type {
23 CHIP_LM3554 = 0,
24 CHIP_LM3556,
25};
26
27enum lm355x_regs {
28 REG_FLAG = 0,
29 REG_TORCH_CFG,
30 REG_TORCH_CTRL,
31 REG_STROBE_CFG,
32 REG_FLASH_CTRL,
33 REG_INDI_CFG,
34 REG_INDI_CTRL,
35 REG_OPMODE,
36 REG_MAX,
37};
38
39/* operation mode */
40enum lm355x_mode {
41 MODE_SHDN = 0,
42 MODE_INDIC,
43 MODE_TORCH,
44 MODE_FLASH
45};
46
47/* register map info. */
48struct lm355x_reg_data {
49 u8 regno;
50 u8 mask;
51 u8 shift;
52};
53
54struct lm355x_chip_data {
55 struct device *dev;
56 enum lm355x_type type;
57
58 struct led_classdev cdev_flash;
59 struct led_classdev cdev_torch;
60 struct led_classdev cdev_indicator;
61
62 struct work_struct work_flash;
63 struct work_struct work_torch;
64 struct work_struct work_indicator;
65
66 u8 br_flash;
67 u8 br_torch;
68 u8 br_indicator;
69
70 struct lm355x_platform_data *pdata;
71 struct regmap *regmap;
72 struct mutex lock;
73
74 unsigned int last_flag;
75 struct lm355x_reg_data *regs;
76};
77
78/* specific indicator function for lm3556 */
79enum lm3556_indic_pulse_time {
80 PULSE_TIME_0_MS = 0,
81 PULSE_TIME_32_MS,
82 PULSE_TIME_64_MS,
83 PULSE_TIME_92_MS,
84 PULSE_TIME_128_MS,
85 PULSE_TIME_160_MS,
86 PULSE_TIME_196_MS,
87 PULSE_TIME_224_MS,
88 PULSE_TIME_256_MS,
89 PULSE_TIME_288_MS,
90 PULSE_TIME_320_MS,
91 PULSE_TIME_352_MS,
92 PULSE_TIME_384_MS,
93 PULSE_TIME_416_MS,
94 PULSE_TIME_448_MS,
95 PULSE_TIME_480_MS,
96};
97
98enum lm3556_indic_n_blank {
99 INDIC_N_BLANK_0 = 0,
100 INDIC_N_BLANK_1,
101 INDIC_N_BLANK_2,
102 INDIC_N_BLANK_3,
103 INDIC_N_BLANK_4,
104 INDIC_N_BLANK_5,
105 INDIC_N_BLANK_6,
106 INDIC_N_BLANK_7,
107 INDIC_N_BLANK_8,
108 INDIC_N_BLANK_9,
109 INDIC_N_BLANK_10,
110 INDIC_N_BLANK_11,
111 INDIC_N_BLANK_12,
112 INDIC_N_BLANK_13,
113 INDIC_N_BLANK_14,
114 INDIC_N_BLANK_15,
115};
116
117enum lm3556_indic_period {
118 INDIC_PERIOD_0 = 0,
119 INDIC_PERIOD_1,
120 INDIC_PERIOD_2,
121 INDIC_PERIOD_3,
122 INDIC_PERIOD_4,
123 INDIC_PERIOD_5,
124 INDIC_PERIOD_6,
125 INDIC_PERIOD_7,
126};
127
128#define INDIC_PATTERN_SIZE 4
129
130struct indicator {
131 u8 blinking;
132 u8 period_cnt;
133};
134
135/* indicator pattern data only for lm3556 */
136static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
137 [0] = {(INDIC_N_BLANK_1 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_1},
138 [1] = {(INDIC_N_BLANK_15 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_2},
139 [2] = {(INDIC_N_BLANK_10 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_4},
140 [3] = {(INDIC_N_BLANK_5 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_7},
141};
142
143static struct lm355x_reg_data lm3554_regs[REG_MAX] = {
144 [REG_FLAG] = {0xD0, 0xBF, 0},
145 [REG_TORCH_CFG] = {0xE0, 0x80, 7},
146 [REG_TORCH_CTRL] = {0xA0, 0x38, 3},
147 [REG_STROBE_CFG] = {0xE0, 0x04, 2},
148 [REG_FLASH_CTRL] = {0xB0, 0x78, 3},
149 [REG_INDI_CFG] = {0xE0, 0x08, 3},
150 [REG_INDI_CTRL] = {0xA0, 0xC0, 6},
151 [REG_OPMODE] = {0xA0, 0x03, 0},
152};
153
154static struct lm355x_reg_data lm3556_regs[REG_MAX] = {
155 [REG_FLAG] = {0x0B, 0xFF, 0},
156 [REG_TORCH_CFG] = {0x0A, 0x10, 4},
157 [REG_TORCH_CTRL] = {0x09, 0x70, 4},
158 [REG_STROBE_CFG] = {0x0A, 0x20, 5},
159 [REG_FLASH_CTRL] = {0x09, 0x0F, 0},
160 [REG_INDI_CFG] = {0xFF, 0xFF, 0},
161 [REG_INDI_CTRL] = {0x09, 0x70, 4},
162 [REG_OPMODE] = {0x0A, 0x03, 0},
163};
164
165static char lm355x_name[][I2C_NAME_SIZE] = {
166 [CHIP_LM3554] = LM3554_NAME,
167 [CHIP_LM3556] = LM3556_NAME,
168};
169
170/* chip initialize */
171static int __devinit lm355x_chip_init(struct lm355x_chip_data *chip)
172{
173 int ret;
174 unsigned int reg_val;
175 struct lm355x_platform_data *pdata = chip->pdata;
176
177 /* input and output pins configuration */
178 switch (chip->type) {
179 case CHIP_LM3554:
180 reg_val = pdata->pin_tx2 | pdata->ntc_pin;
181 ret = regmap_update_bits(chip->regmap, 0xE0, 0x28, reg_val);
182 if (ret < 0)
183 goto out;
184 reg_val = pdata->pass_mode;
185 ret = regmap_update_bits(chip->regmap, 0xA0, 0x04, reg_val);
186 if (ret < 0)
187 goto out;
188 break;
189
190 case CHIP_LM3556:
191 reg_val = pdata->pin_tx2 | pdata->ntc_pin | pdata->pass_mode;
192 ret = regmap_update_bits(chip->regmap, 0x0A, 0xC4, reg_val);
193 if (ret < 0)
194 goto out;
195 break;
196 default:
197 return -ENODATA;
198 }
199
200 return ret;
201out:
202 dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
203 return ret;
204}
205
206/* chip control */
207static void lm355x_control(struct lm355x_chip_data *chip,
208 u8 brightness, enum lm355x_mode opmode)
209{
210 int ret;
211 unsigned int reg_val;
212 struct lm355x_platform_data *pdata = chip->pdata;
213 struct lm355x_reg_data *preg = chip->regs;
214
215 ret = regmap_read(chip->regmap, preg[REG_FLAG].regno, &chip->last_flag);
216 if (ret < 0)
217 goto out;
218 if (chip->last_flag & preg[REG_FLAG].mask)
219 dev_info(chip->dev, "%s Last FLAG is 0x%x\n",
220 lm355x_name[chip->type],
221 chip->last_flag & preg[REG_FLAG].mask);
222 /* brightness 0 means shutdown */
223 if (!brightness)
224 opmode = MODE_SHDN;
225
226 switch (opmode) {
227 case MODE_TORCH:
228 ret =
229 regmap_update_bits(chip->regmap, preg[REG_TORCH_CTRL].regno,
230 preg[REG_TORCH_CTRL].mask,
231 (brightness - 1)
232 << preg[REG_TORCH_CTRL].shift);
233 if (ret < 0)
234 goto out;
235
236 if (pdata->pin_tx1 != LM355x_PIN_TORCH_DISABLE) {
237 ret =
238 regmap_update_bits(chip->regmap,
239 preg[REG_TORCH_CFG].regno,
240 preg[REG_TORCH_CFG].mask,
241 0x01 <<
242 preg[REG_TORCH_CFG].shift);
243 if (ret < 0)
244 goto out;
245 opmode = MODE_SHDN;
246 dev_info(chip->dev,
247 "torch brt is set - ext. torch pin mode\n");
248 }
249 break;
250
251 case MODE_FLASH:
252
253 ret =
254 regmap_update_bits(chip->regmap, preg[REG_FLASH_CTRL].regno,
255 preg[REG_FLASH_CTRL].mask,
256 (brightness - 1)
257 << preg[REG_FLASH_CTRL].shift);
258 if (ret < 0)
259 goto out;
260
261 if (pdata->pin_strobe != LM355x_PIN_STROBE_DISABLE) {
262 if (chip->type == CHIP_LM3554)
263 reg_val = 0x00;
264 else
265 reg_val = 0x01;
266 ret =
267 regmap_update_bits(chip->regmap,
268 preg[REG_STROBE_CFG].regno,
269 preg[REG_STROBE_CFG].mask,
270 reg_val <<
271 preg[REG_STROBE_CFG].shift);
272 if (ret < 0)
273 goto out;
274 opmode = MODE_SHDN;
275 dev_info(chip->dev,
276 "flash brt is set - ext. strobe pin mode\n");
277 }
278 break;
279
280 case MODE_INDIC:
281 ret =
282 regmap_update_bits(chip->regmap, preg[REG_INDI_CTRL].regno,
283 preg[REG_INDI_CTRL].mask,
284 (brightness - 1)
285 << preg[REG_INDI_CTRL].shift);
286 if (ret < 0)
287 goto out;
288
289 if (pdata->pin_tx2 != LM355x_PIN_TX_DISABLE) {
290 ret =
291 regmap_update_bits(chip->regmap,
292 preg[REG_INDI_CFG].regno,
293 preg[REG_INDI_CFG].mask,
294 0x01 <<
295 preg[REG_INDI_CFG].shift);
296 if (ret < 0)
297 goto out;
298 opmode = MODE_SHDN;
299 }
300 break;
301 case MODE_SHDN:
302 break;
303 default:
304 return;
305 }
306 /* operation mode control */
307 ret = regmap_update_bits(chip->regmap, preg[REG_OPMODE].regno,
308 preg[REG_OPMODE].mask,
309 opmode << preg[REG_OPMODE].shift);
310 if (ret < 0)
311 goto out;
312 return;
313out:
314 dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
315 return;
316}
317
318/* torch */
319static void lm355x_deferred_torch_brightness_set(struct work_struct *work)
320{
321 struct lm355x_chip_data *chip =
322 container_of(work, struct lm355x_chip_data, work_torch);
323
324 mutex_lock(&chip->lock);
325 lm355x_control(chip, chip->br_torch, MODE_TORCH);
326 mutex_unlock(&chip->lock);
327}
328
329static void lm355x_torch_brightness_set(struct led_classdev *cdev,
330 enum led_brightness brightness)
331{
332 struct lm355x_chip_data *chip =
333 container_of(cdev, struct lm355x_chip_data, cdev_torch);
334
335 chip->br_torch = brightness;
336 schedule_work(&chip->work_torch);
337}
338
339/* flash */
340static void lm355x_deferred_strobe_brightness_set(struct work_struct *work)
341{
342 struct lm355x_chip_data *chip =
343 container_of(work, struct lm355x_chip_data, work_flash);
344
345 mutex_lock(&chip->lock);
346 lm355x_control(chip, chip->br_flash, MODE_FLASH);
347 mutex_unlock(&chip->lock);
348}
349
350static void lm355x_strobe_brightness_set(struct led_classdev *cdev,
351 enum led_brightness brightness)
352{
353 struct lm355x_chip_data *chip =
354 container_of(cdev, struct lm355x_chip_data, cdev_flash);
355
356 chip->br_flash = brightness;
357 schedule_work(&chip->work_flash);
358}
359
360/* indicator */
361static void lm355x_deferred_indicator_brightness_set(struct work_struct *work)
362{
363 struct lm355x_chip_data *chip =
364 container_of(work, struct lm355x_chip_data, work_indicator);
365
366 mutex_lock(&chip->lock);
367 lm355x_control(chip, chip->br_indicator, MODE_INDIC);
368 mutex_unlock(&chip->lock);
369}
370
371static void lm355x_indicator_brightness_set(struct led_classdev *cdev,
372 enum led_brightness brightness)
373{
374 struct lm355x_chip_data *chip =
375 container_of(cdev, struct lm355x_chip_data, cdev_indicator);
376
377 chip->br_indicator = brightness;
378 schedule_work(&chip->work_indicator);
379}
380
381/* indicator pattern only for lm3556*/
382static ssize_t lm3556_indicator_pattern_store(struct device *dev,
383 struct device_attribute *devAttr,
384 const char *buf, size_t size)
385{
386 ssize_t ret;
387 struct led_classdev *led_cdev = dev_get_drvdata(dev);
388 struct lm355x_chip_data *chip =
389 container_of(led_cdev, struct lm355x_chip_data, cdev_indicator);
390 unsigned int state;
391
392 ret = kstrtouint(buf, 10, &state);
393 if (ret)
394 goto out;
395 if (state > INDIC_PATTERN_SIZE - 1)
396 state = INDIC_PATTERN_SIZE - 1;
397
398 ret = regmap_write(chip->regmap, 0x04,
399 indicator_pattern[state].blinking);
400 if (ret < 0)
401 goto out;
402
403 ret = regmap_write(chip->regmap, 0x05,
404 indicator_pattern[state].period_cnt);
405 if (ret < 0)
406 goto out;
407
408 return size;
409out:
410 dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
411 return size;
412}
413
414static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
415
416static const struct regmap_config lm355x_regmap = {
417 .reg_bits = 8,
418 .val_bits = 8,
419 .max_register = 0xFF,
420};
421
422/* module initialize */
423static int __devinit lm355x_probe(struct i2c_client *client,
424 const struct i2c_device_id *id)
425{
426 struct lm355x_platform_data *pdata = client->dev.platform_data;
427 struct lm355x_chip_data *chip;
428
429 int err;
430
431 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
432 dev_err(&client->dev, "i2c functionality check fail.\n");
433 return -EOPNOTSUPP;
434 }
435
436 if (pdata == NULL) {
437 dev_err(&client->dev, "needs Platform Data.\n");
438 return -ENODATA;
439 }
440
441 chip = devm_kzalloc(&client->dev,
442 sizeof(struct lm355x_chip_data), GFP_KERNEL);
443 if (!chip)
444 return -ENOMEM;
445
446 chip->dev = &client->dev;
447 chip->type = id->driver_data;
448 switch (id->driver_data) {
449 case CHIP_LM3554:
450 chip->regs = lm3554_regs;
451 break;
452 case CHIP_LM3556:
453 chip->regs = lm3556_regs;
454 break;
455 default:
456 return -ENOSYS;
457 }
458 chip->pdata = pdata;
459
460 chip->regmap = devm_regmap_init_i2c(client, &lm355x_regmap);
461 if (IS_ERR(chip->regmap)) {
462 err = PTR_ERR(chip->regmap);
463 dev_err(&client->dev,
464 "Failed to allocate register map: %d\n", err);
465 return err;
466 }
467
468 mutex_init(&chip->lock);
469 i2c_set_clientdata(client, chip);
470
471 err = lm355x_chip_init(chip);
472 if (err < 0)
473 goto err_out;
474
475 /* flash */
476 INIT_WORK(&chip->work_flash, lm355x_deferred_strobe_brightness_set);
477 chip->cdev_flash.name = "flash";
478 chip->cdev_flash.max_brightness = 16;
479 chip->cdev_flash.brightness_set = lm355x_strobe_brightness_set;
480 err = led_classdev_register((struct device *)
481 &client->dev, &chip->cdev_flash);
482 if (err < 0)
483 goto err_out;
484 /* torch */
485 INIT_WORK(&chip->work_torch, lm355x_deferred_torch_brightness_set);
486 chip->cdev_torch.name = "torch";
487 chip->cdev_torch.max_brightness = 8;
488 chip->cdev_torch.brightness_set = lm355x_torch_brightness_set;
489 err = led_classdev_register((struct device *)
490 &client->dev, &chip->cdev_torch);
491 if (err < 0)
492 goto err_create_torch_file;
493 /* indicator */
494 INIT_WORK(&chip->work_indicator,
495 lm355x_deferred_indicator_brightness_set);
496 chip->cdev_indicator.name = "indicator";
497 if (id->driver_data == CHIP_LM3554)
498 chip->cdev_indicator.max_brightness = 4;
499 else
500 chip->cdev_indicator.max_brightness = 8;
501 chip->cdev_indicator.brightness_set = lm355x_indicator_brightness_set;
502 err = led_classdev_register((struct device *)
503 &client->dev, &chip->cdev_indicator);
504 if (err < 0)
505 goto err_create_indicator_file;
506 /* indicator pattern control only for LM3554 */
507 if (id->driver_data == CHIP_LM3556) {
508 err =
509 device_create_file(chip->cdev_indicator.dev,
510 &dev_attr_pattern);
511 if (err < 0)
512 goto err_create_pattern_file;
513 }
514
515 dev_info(&client->dev, "%s is initialized\n",
516 lm355x_name[id->driver_data]);
517 return 0;
518
519err_create_pattern_file:
520 led_classdev_unregister(&chip->cdev_indicator);
521err_create_indicator_file:
522 led_classdev_unregister(&chip->cdev_torch);
523err_create_torch_file:
524 led_classdev_unregister(&chip->cdev_flash);
525err_out:
526 return err;
527}
528
529static int __devexit lm355x_remove(struct i2c_client *client)
530{
531 struct lm355x_chip_data *chip = i2c_get_clientdata(client);
532 struct lm355x_reg_data *preg = chip->regs;
533
534 regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0);
535 if (chip->type == CHIP_LM3556)
536 device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern);
537 led_classdev_unregister(&chip->cdev_indicator);
538 flush_work(&chip->work_indicator);
539 led_classdev_unregister(&chip->cdev_torch);
540 flush_work(&chip->work_torch);
541 led_classdev_unregister(&chip->cdev_flash);
542 flush_work(&chip->work_flash);
543 dev_info(&client->dev, "%s is removed\n", lm355x_name[chip->type]);
544
545 return 0;
546}
547
548static const struct i2c_device_id lm355x_id[] = {
549 {LM3554_NAME, CHIP_LM3554},
550 {LM3556_NAME, CHIP_LM3556},
551 {}
552};
553
554MODULE_DEVICE_TABLE(i2c, lm355x_id);
555
556static struct i2c_driver lm355x_i2c_driver = {
557 .driver = {
558 .name = LM355x_NAME,
559 .owner = THIS_MODULE,
560 .pm = NULL,
561 },
562 .probe = lm355x_probe,
563 .remove = __devexit_p(lm355x_remove),
564 .id_table = lm355x_id,
565};
566
567module_i2c_driver(lm355x_i2c_driver);
568
569MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM355x");
570MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
571MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
572MODULE_LICENSE("GPL v2");