History

leds: Add new LED driver for lm3642 chips

This driver is a general version for LM642 led chip of TI. LM3642 : The LM3642 is a 4MHz fixed-frequency synchronous boost converter plus 1.5A constant current driver for a high-current white LED. The LM3642 is controlled via an I2C-compatible interface.

G.Shark Jeong committed 14 years ago

Commit 8b7cfbe1 parent f1625844 files · +521 −0Browse files

Unified · Split

4 files
  1. drivers/leds/Kconfig +11 −0
  2. drivers/leds/Makefile +1 −0
  3. drivers/leds/leds-lm3642.c +471 −0
  4. include/linux/platform_data/leds-lm3642.h +38 −0
drivers/leds/Kconfig+11−0
@@ -63,6 +63,17 @@ config LEDS_LM3533 · 62 unmodified lines
6363 hardware-accelerated blinking with maximum on and off periods of 9.8
6464 and 77 seconds respectively.
6565
66+config LEDS_LM3642
67+ tristate "LED support for LM3642 Chip"
68+ depends on LEDS_CLASS && I2C
69+ select REGMAP_I2C
70+ help
71+ This option enables support for LEDs connected to LM3642.
72+ The LM3642 is a 4MHz fixed-frequency synchronous boost
73+ converter plus 1.5A constant current driver for a high-current
74+ white LED.
75+
76+
6677 config LEDS_LOCOMO
6778 tristate "LED Support for Locomo device"
6879 depends on LEDS_CLASS
drivers/leds/Makefile+1−0
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o · 10 unmodified lines
1111 obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
1212 obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
1313 obj-$(CONFIG_LEDS_LM3533) += leds-lm3533.o
14+obj-$(CONFIG_LEDS_LM3642) += leds-lm3642.o
1415 obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
1516 obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
1617 obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
drivers/leds/leds-lm3642.c+471−0
@@ -0,0 +1,471 @@
1+/*
2+* Simple driver for Texas Instruments LM3642 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/leds.h>
14+#include <linux/slab.h>
15+#include <linux/platform_device.h>
16+#include <linux/fs.h>
17+#include <linux/regmap.h>
18+#include <linux/workqueue.h>
19+#include <linux/platform_data/leds-lm3642.h>
20+
21+#define REG_FILT_TIME (0x0)
22+#define REG_IVFM_MODE (0x1)
23+#define REG_TORCH_TIME (0x6)
24+#define REG_FLASH (0x8)
25+#define REG_I_CTRL (0x9)
26+#define REG_ENABLE (0xA)
27+#define REG_FLAG (0xB)
28+#define REG_MAX (0xB)
29+
30+#define UVLO_EN_SHIFT (7)
31+#define IVM_D_TH_SHIFT (2)
32+#define TORCH_RAMP_UP_TIME_SHIFT (3)
33+#define TORCH_RAMP_DN_TIME_SHIFT (0)
34+#define INDUCTOR_I_LIMIT_SHIFT (6)
35+#define FLASH_RAMP_TIME_SHIFT (3)
36+#define FLASH_TOUT_TIME_SHIFT (0)
37+#define TORCH_I_SHIFT (4)
38+#define FLASH_I_SHIFT (0)
39+#define IVFM_SHIFT (7)
40+#define TX_PIN_EN_SHIFT (6)
41+#define STROBE_PIN_EN_SHIFT (5)
42+#define TORCH_PIN_EN_SHIFT (4)
43+#define MODE_BITS_SHIFT (0)
44+
45+#define UVLO_EN_MASK (0x1)
46+#define IVM_D_TH_MASK (0x7)
47+#define TORCH_RAMP_UP_TIME_MASK (0x7)
48+#define TORCH_RAMP_DN_TIME_MASK (0x7)
49+#define INDUCTOR_I_LIMIT_MASK (0x1)
50+#define FLASH_RAMP_TIME_MASK (0x7)
51+#define FLASH_TOUT_TIME_MASK (0x7)
52+#define TORCH_I_MASK (0x7)
53+#define FLASH_I_MASK (0xF)
54+#define IVFM_MASK (0x1)
55+#define TX_PIN_EN_MASK (0x1)
56+#define STROBE_PIN_EN_MASK (0x1)
57+#define TORCH_PIN_EN_MASK (0x1)
58+#define MODE_BITS_MASK (0x73)
59+#define EX_PIN_CONTROL_MASK (0x71)
60+#define EX_PIN_ENABLE_MASK (0x70)
61+
62+enum lm3642_mode {
63+ MODES_STASNDBY = 0,
64+ MODES_INDIC,
65+ MODES_TORCH,
66+ MODES_FLASH
67+};
68+
69+struct lm3642_chip_data {
70+ struct device *dev;
71+
72+ struct led_classdev cdev_flash;
73+ struct led_classdev cdev_torch;
74+ struct led_classdev cdev_indicator;
75+
76+ struct work_struct work_flash;
77+ struct work_struct work_torch;
78+ struct work_struct work_indicator;
79+
80+ u8 br_flash;
81+ u8 br_torch;
82+ u8 br_indicator;
83+
84+ enum lm3642_torch_pin_enable torch_pin;
85+ enum lm3642_strobe_pin_enable strobe_pin;
86+ enum lm3642_tx_pin_enable tx_pin;
87+
88+ struct lm3642_platform_data *pdata;
89+ struct regmap *regmap;
90+ struct mutex lock;
91+
92+ unsigned int last_flag;
93+};
94+
95+/* chip initialize */
96+static int __devinit lm3642_chip_init(struct lm3642_chip_data *chip)
97+{
98+ unsigned int reg_val;
99+ int ret;
100+ struct lm3642_platform_data *pdata = chip->pdata;
101+
102+ /* set enable register */
103+ ret = regmap_read(chip->regmap, REG_ENABLE, &reg_val);
104+ if (ret < 0)
105+ goto out;
106+
107+ reg_val &= (~EX_PIN_ENABLE_MASK);
108+ reg_val |= pdata->tx_pin;
109+ ret = regmap_write(chip->regmap, REG_ENABLE, reg_val);
110+ if (ret < 0)
111+ goto out;
112+
113+out:
114+ dev_err(chip->dev, "Failed to read REG_ENABLE Register\n");
115+ return ret;
116+}
117+
118+/* chip control */
119+static int lm3642_control(struct lm3642_chip_data *chip,
120+ u8 brightness, enum lm3642_mode opmode)
121+{
122+ int ret;
123+
124+ ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
125+ if (ret < 0) {
126+ dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
127+ goto out;
128+ }
129+
130+ if (chip->last_flag)
131+ dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);
132+
133+ /* brightness 0 means off-state */
134+ if (!brightness)
135+ opmode = MODES_STASNDBY;
136+
137+ switch (opmode) {
138+ case MODES_TORCH:
139+ ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
140+ TORCH_I_MASK << TORCH_I_SHIFT,
141+ (brightness - 1) << TORCH_I_SHIFT);
142+
143+ if (chip->torch_pin)
144+ opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
145+ break;
146+
147+ case MODES_FLASH:
148+ ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
149+ FLASH_I_MASK << FLASH_I_SHIFT,
150+ (brightness - 1) << FLASH_I_SHIFT);
151+
152+ if (chip->strobe_pin)
153+ opmode |= (STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT);
154+ break;
155+
156+ case MODES_INDIC:
157+ ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
158+ TORCH_I_MASK << TORCH_I_SHIFT,
159+ (brightness - 1) << TORCH_I_SHIFT);
160+ break;
161+
162+ case MODES_STASNDBY:
163+
164+ break;
165+
166+ default:
167+ return ret;
168+ }
169+ if (ret < 0) {
170+ dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
171+ goto out;
172+ }
173+
174+ if (chip->tx_pin)
175+ opmode |= (TX_PIN_EN_MASK << TX_PIN_EN_SHIFT);
176+
177+ ret = regmap_update_bits(chip->regmap, REG_ENABLE,
178+ MODE_BITS_MASK << MODE_BITS_SHIFT,
179+ opmode << MODE_BITS_SHIFT);
180+out:
181+ return ret;
182+}
183+
184+/* torch */
185+
186+/* torch pin config for lm3642*/
187+static ssize_t lm3642_torch_pin_store(struct device *dev,
188+ struct device_attribute *devAttr,
189+ const char *buf, size_t size)
190+{
191+ ssize_t ret;
192+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
193+ struct lm3642_chip_data *chip =
194+ container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);
195+ unsigned int state;
196+
197+ ret = kstrtouint(buf, 10, &state);
198+ if (ret)
199+ goto out_strtoint;
200+ if (state != 0)
201+ state = 0x01 << TORCH_PIN_EN_SHIFT;
202+
203+ chip->torch_pin = state;
204+ ret = regmap_update_bits(chip->regmap, REG_ENABLE,
205+ TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT,
206+ state);
207+ if (ret < 0)
208+ goto out;
209+
210+ return size;
211+out:
212+ dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
213+ return size;
214+out_strtoint:
215+ dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
216+ return size;
217+}
218+
219+static DEVICE_ATTR(torch_pin, 0666, NULL, lm3642_torch_pin_store);
220+
221+static void lm3642_deferred_torch_brightness_set(struct work_struct *work)
222+{
223+ struct lm3642_chip_data *chip =
224+ container_of(work, struct lm3642_chip_data, work_torch);
225+
226+ mutex_lock(&chip->lock);
227+ lm3642_control(chip, chip->br_torch, MODES_TORCH);
228+ mutex_unlock(&chip->lock);
229+}
230+
231+static void lm3642_torch_brightness_set(struct led_classdev *cdev,
232+ enum led_brightness brightness)
233+{
234+ struct lm3642_chip_data *chip =
235+ container_of(cdev, struct lm3642_chip_data, cdev_torch);
236+
237+ chip->br_torch = brightness;
238+ schedule_work(&chip->work_torch);
239+}
240+
241+/* flash */
242+
243+/* strobe pin config for lm3642*/
244+static ssize_t lm3642_strobe_pin_store(struct device *dev,
245+ struct device_attribute *devAttr,
246+ const char *buf, size_t size)
247+{
248+ ssize_t ret;
249+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
250+ struct lm3642_chip_data *chip =
251+ container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);
252+ unsigned int state;
253+
254+ ret = kstrtouint(buf, 10, &state);
255+ if (ret)
256+ goto out_strtoint;
257+ if (state != 0)
258+ state = 0x01 << STROBE_PIN_EN_SHIFT;
259+
260+ chip->strobe_pin = state;
261+ ret = regmap_update_bits(chip->regmap, REG_ENABLE,
262+ STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT,
263+ state);
264+ if (ret < 0)
265+ goto out;
266+
267+ return size;
268+out:
269+ dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
270+ return size;
271+out_strtoint:
272+ dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
273+ return size;
274+}
275+
276+static DEVICE_ATTR(strobe_pin, 0666, NULL, lm3642_strobe_pin_store);
277+
278+static void lm3642_deferred_strobe_brightness_set(struct work_struct *work)
279+{
280+ struct lm3642_chip_data *chip =
281+ container_of(work, struct lm3642_chip_data, work_flash);
282+
283+ mutex_lock(&chip->lock);
284+ lm3642_control(chip, chip->br_flash, MODES_FLASH);
285+ mutex_unlock(&chip->lock);
286+}
287+
288+static void lm3642_strobe_brightness_set(struct led_classdev *cdev,
289+ enum led_brightness brightness)
290+{
291+ struct lm3642_chip_data *chip =
292+ container_of(cdev, struct lm3642_chip_data, cdev_flash);
293+
294+ chip->br_flash = brightness;
295+ schedule_work(&chip->work_flash);
296+}
297+
298+/* indicator */
299+static void lm3642_deferred_indicator_brightness_set(struct work_struct *work)
300+{
301+ struct lm3642_chip_data *chip =
302+ container_of(work, struct lm3642_chip_data, work_indicator);
303+
304+ mutex_lock(&chip->lock);
305+ lm3642_control(chip, chip->br_indicator, MODES_INDIC);
306+ mutex_unlock(&chip->lock);
307+}
308+
309+static void lm3642_indicator_brightness_set(struct led_classdev *cdev,
310+ enum led_brightness brightness)
311+{
312+ struct lm3642_chip_data *chip =
313+ container_of(cdev, struct lm3642_chip_data, cdev_indicator);
314+
315+ chip->br_indicator = brightness;
316+ schedule_work(&chip->work_indicator);
317+}
318+
319+static const struct regmap_config lm3642_regmap = {
320+ .reg_bits = 8,
321+ .val_bits = 8,
322+ .max_register = REG_MAX,
323+};
324+
325+static int __devinit lm3642_probe(struct i2c_client *client,
326+ const struct i2c_device_id *id)
327+{
328+ struct lm3642_platform_data *pdata = client->dev.platform_data;
329+ struct lm3642_chip_data *chip;
330+
331+ int err;
332+
333+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
334+ dev_err(&client->dev, "i2c functionality check fail.\n");
335+ return -EOPNOTSUPP;
336+ }
337+
338+ if (pdata == NULL) {
339+ dev_err(&client->dev, "needs Platform Data.\n");
340+ return -ENODATA;
341+ }
342+
343+ chip = devm_kzalloc(&client->dev,
344+ sizeof(struct lm3642_chip_data), GFP_KERNEL);
345+ if (!chip)
346+ return -ENOMEM;
347+
348+ chip->dev = &client->dev;
349+ chip->pdata = pdata;
350+
351+ chip->tx_pin = pdata->tx_pin;
352+ chip->torch_pin = pdata->torch_pin;
353+ chip->strobe_pin = pdata->strobe_pin;
354+
355+ chip->regmap = devm_regmap_init_i2c(client, &lm3642_regmap);
356+ if (IS_ERR(chip->regmap)) {
357+ err = PTR_ERR(chip->regmap);
358+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
359+ err);
360+ return err;
361+ }
362+
363+ mutex_init(&chip->lock);
364+ i2c_set_clientdata(client, chip);
365+
366+ err = lm3642_chip_init(chip);
367+ if (err < 0)
368+ goto err_out;
369+
370+ /* flash */
371+ INIT_WORK(&chip->work_flash, lm3642_deferred_strobe_brightness_set);
372+ chip->cdev_flash.name = "flash";
373+ chip->cdev_flash.max_brightness = 16;
374+ chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set;
375+ err = led_classdev_register((struct device *)
376+ &client->dev, &chip->cdev_flash);
377+ if (err < 0) {
378+ dev_err(chip->dev, "failed to register flash\n");
379+ goto err_out;
380+ }
381+ err = device_create_file(chip->cdev_flash.dev, &dev_attr_strobe_pin);
382+ if (err < 0) {
383+ dev_err(chip->dev, "failed to create strobe-pin file\n");
384+ goto err_create_flash_pin_file;
385+ }
386+
387+ /* torch */
388+ INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set);
389+ chip->cdev_torch.name = "torch";
390+ chip->cdev_torch.max_brightness = 8;
391+ chip->cdev_torch.brightness_set = lm3642_torch_brightness_set;
392+ err = led_classdev_register((struct device *)
393+ &client->dev, &chip->cdev_torch);
394+ if (err < 0) {
395+ dev_err(chip->dev, "failed to register torch\n");
396+ goto err_create_torch_file;
397+ }
398+ err = device_create_file(chip->cdev_torch.dev, &dev_attr_torch_pin);
399+ if (err < 0) {
400+ dev_err(chip->dev, "failed to create torch-pin file\n");
401+ goto err_create_torch_pin_file;
402+ }
403+
404+ /* indicator */
405+ INIT_WORK(&chip->work_indicator,
406+ lm3642_deferred_indicator_brightness_set);
407+ chip->cdev_indicator.name = "indicator";
408+ chip->cdev_indicator.max_brightness = 8;
409+ chip->cdev_indicator.brightness_set = lm3642_indicator_brightness_set;
410+ err = led_classdev_register((struct device *)
411+ &client->dev, &chip->cdev_indicator);
412+ if (err < 0) {
413+ dev_err(chip->dev, "failed to register indicator\n");
414+ goto err_create_indicator_file;
415+ }
416+
417+ dev_info(&client->dev, "LM3642 is initialized\n");
418+ return 0;
419+
420+err_create_indicator_file:
421+ device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin);
422+err_create_torch_pin_file:
423+ led_classdev_unregister(&chip->cdev_torch);
424+err_create_torch_file:
425+ device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin);
426+err_create_flash_pin_file:
427+ led_classdev_unregister(&chip->cdev_flash);
428+err_out:
429+ return err;
430+}
431+
432+static int __devexit lm3642_remove(struct i2c_client *client)
433+{
434+ struct lm3642_chip_data *chip = i2c_get_clientdata(client);
435+
436+ led_classdev_unregister(&chip->cdev_indicator);
437+ flush_work(&chip->work_indicator);
438+ device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin);
439+ led_classdev_unregister(&chip->cdev_torch);
440+ flush_work(&chip->work_torch);
441+ device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin);
442+ led_classdev_unregister(&chip->cdev_flash);
443+ flush_work(&chip->work_flash);
444+ regmap_write(chip->regmap, REG_ENABLE, 0);
445+ return 0;
446+}
447+
448+static const struct i2c_device_id lm3642_id[] = {
449+ {LM3642_NAME, 0},
450+ {}
451+};
452+
453+MODULE_DEVICE_TABLE(i2c, lm3642_id);
454+
455+static struct i2c_driver lm3642_i2c_driver = {
456+ .driver = {
457+ .name = LM3642_NAME,
458+ .owner = THIS_MODULE,
459+ .pm = NULL,
460+ },
461+ .probe = lm3642_probe,
462+ .remove = __devexit_p(lm3642_remove),
463+ .id_table = lm3642_id,
464+};
465+
466+module_i2c_driver(lm3642_i2c_driver);
467+
468+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3642");
469+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
470+MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
471+MODULE_LICENSE("GPL v2");
include/linux/platform_data/leds-lm3642.h+38−0
@@ -0,0 +1,38 @@
1+/*
2+* Copyright (C) 2012 Texas Instruments
3+*
4+* License Terms: GNU General Public License v2
5+*
6+* Simple driver for Texas Instruments LM3642 LED driver chip
7+*
8+* Author: G.Shark Jeong <gshark.jeong@gmail.com>
9+* Daniel Jeong <daniel.jeong@ti.com>
10+*/
11+
12+#ifndef __LINUX_LM3642_H
13+#define __LINUX_LM3642_H
14+
15+#define LM3642_NAME "leds-lm3642"
16+
17+enum lm3642_torch_pin_enable {
18+ LM3642_TORCH_PIN_DISABLE = 0x00,
19+ LM3642_TORCH_PIN_ENABLE = 0x10,
20+};
21+
22+enum lm3642_strobe_pin_enable {
23+ LM3642_STROBE_PIN_DISABLE = 0x00,
24+ LM3642_STROBE_PIN_ENABLE = 0x20,
25+};
26+
27+enum lm3642_tx_pin_enable {
28+ LM3642_TX_PIN_DISABLE = 0x00,
29+ LM3642_TX_PIN_ENABLE = 0x40,
30+};
31+
32+struct lm3642_platform_data {
33+ enum lm3642_torch_pin_enable torch_pin;
34+ enum lm3642_strobe_pin_enable strobe_pin;
35+ enum lm3642_tx_pin_enable tx_pin;
36+};
37+
38+#endif /* __LINUX_LM3642_H */