blob: 3062abd9a532a06c0d79ace5c10544e9bdad90ad [file] [log] [blame]
G.Shark Jeong32abb472012-06-22 08:12:06 +08001/*
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");