2 * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
3 * Copyright (C) 2012 Texas Instruments
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.
9 * Please refer Documentation/leds/leds-lm3556.txt file.
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>
18 #include <linux/regmap.h>
19 #include <linux/platform_data/leds-lm3556.h>
21 #define REG_FILT_TIME (0x0)
22 #define REG_IVFM_MODE (0x1)
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)
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)
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)
109 enum lm3556_indic_pulse_time {
128 enum lm3556_indic_n_blank {
147 enum lm3556_indic_period {
165 #define INDIC_PATTERN_SIZE 4
172 struct lm3556_chip_data {
175 struct led_classdev cdev_flash;
176 struct led_classdev cdev_torch;
177 struct led_classdev cdev_indicator;
179 struct lm3556_platform_data *pdata;
180 struct regmap *regmap;
183 unsigned int last_flag;
186 /* indicator pattern */
187 static 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},
198 /* chip initialize */
199 static int __devinit lm3556_chip_init(struct lm3556_chip_data *chip)
201 unsigned int reg_val;
203 struct lm3556_platform_data *pdata = chip->pdata;
205 /* set config register */
206 ret = regmap_read(chip->regmap, REG_CONF, ®_val);
208 dev_err(chip->dev, "Failed to read REG_CONF Register\n");
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);
221 ret = regmap_write(chip->regmap, REG_CONF, reg_val);
223 dev_err(chip->dev, "Failed to write REG_CONF Regisgter\n");
227 /* set enable register */
228 ret = regmap_read(chip->regmap, REG_ENABLE, ®_val);
230 dev_err(chip->dev, "Failed to read REG_ENABLE Register\n");
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);
239 ret = regmap_write(chip->regmap, REG_ENABLE, reg_val);
241 dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
250 static int lm3556_control(struct lm3556_chip_data *chip,
251 u8 brightness, enum lm3556_mode opmode)
254 struct lm3556_platform_data *pdata = chip->pdata;
256 ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
258 dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
263 dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);
265 /* brightness 0 means off-state */
267 opmode = MODES_STASNDBY;
271 ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
272 TORCH_I_MASK << TORCH_I_SHIFT,
273 (brightness - 1) << TORCH_I_SHIFT);
275 if (pdata->torch_pin_en)
276 opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
280 ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
281 FLASH_I_MASK << FLASH_I_SHIFT,
282 (brightness - 1) << FLASH_I_SHIFT);
286 ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
287 TORCH_I_MASK << TORCH_I_SHIFT,
288 (brightness - 1) << TORCH_I_SHIFT);
292 if (pdata->torch_pin_en)
293 opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
300 dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
303 ret = regmap_update_bits(chip->regmap, REG_ENABLE,
304 MODE_BITS_MASK << MODE_BITS_SHIFT,
305 opmode << MODE_BITS_SHIFT);
312 static void lm3556_torch_brightness_set(struct led_classdev *cdev,
313 enum led_brightness brightness)
315 struct lm3556_chip_data *chip =
316 container_of(cdev, struct lm3556_chip_data, cdev_torch);
318 mutex_lock(&chip->lock);
319 lm3556_control(chip, brightness, MODES_TORCH);
320 mutex_unlock(&chip->lock);
324 static void lm3556_strobe_brightness_set(struct led_classdev *cdev,
325 enum led_brightness brightness)
327 struct lm3556_chip_data *chip =
328 container_of(cdev, struct lm3556_chip_data, cdev_flash);
330 mutex_lock(&chip->lock);
331 lm3556_control(chip, brightness, MODES_FLASH);
332 mutex_unlock(&chip->lock);
336 static void lm3556_indicator_brightness_set(struct led_classdev *cdev,
337 enum led_brightness brightness)
339 struct lm3556_chip_data *chip =
340 container_of(cdev, struct lm3556_chip_data, cdev_indicator);
342 mutex_lock(&chip->lock);
343 lm3556_control(chip, brightness, MODES_INDIC);
344 mutex_unlock(&chip->lock);
347 /* indicator pattern */
348 static ssize_t lm3556_indicator_pattern_store(struct device *dev,
349 struct device_attribute *devAttr,
350 const char *buf, size_t size)
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);
358 ret = kstrtouint(buf, 10, &state);
361 if (state > INDIC_PATTERN_SIZE - 1)
362 state = INDIC_PATTERN_SIZE - 1;
364 ret = regmap_write(chip->regmap, REG_INDIC_BLINK,
365 indicator_pattern[state].blinking);
367 dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
371 ret = regmap_write(chip->regmap, REG_INDIC_PERIOD,
372 indicator_pattern[state].period_cnt);
374 dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
380 dev_err(chip->dev, "Indicator pattern doesn't saved\n");
384 static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
386 static const struct regmap_config lm3556_regmap = {
389 .max_register = REG_MAX,
392 /* module initialize */
393 static int __devinit lm3556_probe(struct i2c_client *client,
394 const struct i2c_device_id *id)
396 struct lm3556_platform_data *pdata = client->dev.platform_data;
397 struct lm3556_chip_data *chip;
401 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
402 dev_err(&client->dev, "i2c functionality check fail.\n");
407 dev_err(&client->dev, "Needs Platform Data.\n");
412 devm_kzalloc(&client->dev, sizeof(struct lm3556_chip_data),
417 chip->dev = &client->dev;
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",
428 mutex_init(&chip->lock);
429 i2c_set_clientdata(client, chip);
431 err = lm3556_chip_init(chip);
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);
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);
450 goto err_create_torch_file;
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);
458 goto err_create_indicator_file;
460 err = device_create_file(chip->cdev_indicator.dev, &dev_attr_pattern);
462 goto err_create_pattern_file;
464 dev_info(&client->dev, "LM3556 is initialized\n");
467 err_create_pattern_file:
468 led_classdev_unregister(&chip->cdev_indicator);
469 err_create_indicator_file:
470 led_classdev_unregister(&chip->cdev_torch);
471 err_create_torch_file:
472 led_classdev_unregister(&chip->cdev_flash);
477 static int __devexit lm3556_remove(struct i2c_client *client)
479 struct lm3556_chip_data *chip = i2c_get_clientdata(client);
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);
489 static const struct i2c_device_id lm3556_id[] = {
494 MODULE_DEVICE_TABLE(i2c, lm3556_id);
496 static struct i2c_driver lm3556_i2c_driver = {
499 .owner = THIS_MODULE,
502 .probe = lm3556_probe,
503 .remove = __devexit_p(lm3556_remove),
504 .id_table = lm3556_id,
507 module_i2c_driver(lm3556_i2c_driver);
509 MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3556");
510 MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
511 MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
512 MODULE_LICENSE("GPL v2");