2 * Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip
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.
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/i2c.h>
13 #include <linux/leds.h>
14 #include <linux/backlight.h>
15 #include <linux/err.h>
16 #include <linux/delay.h>
17 #include <linux/uaccess.h>
18 #include <linux/interrupt.h>
19 #include <linux/regmap.h>
20 #include <linux/platform_data/lm3639_bl.h>
22 #define REG_DEV_ID 0x00
23 #define REG_CHECKSUM 0x01
24 #define REG_BL_CONF_1 0x02
25 #define REG_BL_CONF_2 0x03
26 #define REG_BL_CONF_3 0x04
27 #define REG_BL_CONF_4 0x05
28 #define REG_FL_CONF_1 0x06
29 #define REG_FL_CONF_2 0x07
30 #define REG_FL_CONF_3 0x08
31 #define REG_IO_CTRL 0x09
32 #define REG_ENABLE 0x0A
34 #define REG_MAX REG_FLAG
36 struct lm3639_chip_data {
38 struct lm3639_platform_data *pdata;
40 struct backlight_device *bled;
41 struct led_classdev cdev_flash;
42 struct led_classdev cdev_torch;
43 struct regmap *regmap;
45 unsigned int bled_mode;
46 unsigned int bled_map;
47 unsigned int last_flag;
51 static int lm3639_chip_init(struct lm3639_chip_data *pchip)
55 struct lm3639_platform_data *pdata = pchip->pdata;
57 /* input pins config. */
59 regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x08,
64 reg_val = (pdata->pin_pwm & 0x40) | pdata->pin_strobe | pdata->pin_tx;
65 ret = regmap_update_bits(pchip->regmap, REG_IO_CTRL, 0x7C, reg_val);
70 ret = regmap_write(pchip->regmap, REG_BL_CONF_4, pdata->init_brt_led);
74 ret = regmap_write(pchip->regmap, REG_BL_CONF_3, pdata->init_brt_led);
78 /* output pins config. */
79 if (!pdata->init_brt_led) {
80 reg_val = pdata->fled_pins;
81 reg_val |= pdata->bled_pins;
83 reg_val = pdata->fled_pins;
84 reg_val |= pdata->bled_pins | 0x01;
87 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val);
93 dev_err(pchip->dev, "i2c failed to access register\n");
97 /* update and get brightness */
98 static int lm3639_bled_update_status(struct backlight_device *bl)
101 unsigned int reg_val;
102 struct lm3639_chip_data *pchip = bl_get_data(bl);
103 struct lm3639_platform_data *pdata = pchip->pdata;
105 ret = regmap_read(pchip->regmap, REG_FLAG, ®_val);
110 dev_info(pchip->dev, "last flag is 0x%x\n", reg_val);
113 if (pdata->pin_pwm) {
114 if (pdata->pwm_set_intensity)
115 pdata->pwm_set_intensity(bl->props.brightness,
119 "No pwm control func. in plat-data\n");
120 return bl->props.brightness;
123 /* i2c control and set brigtness */
124 ret = regmap_write(pchip->regmap, REG_BL_CONF_4, bl->props.brightness);
127 ret = regmap_write(pchip->regmap, REG_BL_CONF_3, bl->props.brightness);
131 if (!bl->props.brightness)
132 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x00);
134 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x01);
138 return bl->props.brightness;
140 dev_err(pchip->dev, "i2c failed to access registers\n");
141 return bl->props.brightness;
144 static int lm3639_bled_get_brightness(struct backlight_device *bl)
147 unsigned int reg_val;
148 struct lm3639_chip_data *pchip = bl_get_data(bl);
149 struct lm3639_platform_data *pdata = pchip->pdata;
151 if (pdata->pin_pwm) {
152 if (pdata->pwm_get_intensity)
153 bl->props.brightness = pdata->pwm_get_intensity();
156 "No pwm control func. in plat-data\n");
157 return bl->props.brightness;
160 ret = regmap_read(pchip->regmap, REG_BL_CONF_1, ®_val);
164 ret = regmap_read(pchip->regmap, REG_BL_CONF_4, ®_val);
166 ret = regmap_read(pchip->regmap, REG_BL_CONF_3, ®_val);
169 bl->props.brightness = reg_val;
171 return bl->props.brightness;
173 dev_err(pchip->dev, "i2c failed to access register\n");
174 return bl->props.brightness;
177 static const struct backlight_ops lm3639_bled_ops = {
178 .options = BL_CORE_SUSPENDRESUME,
179 .update_status = lm3639_bled_update_status,
180 .get_brightness = lm3639_bled_get_brightness,
183 /* backlight mapping mode */
184 static ssize_t lm3639_bled_mode_store(struct device *dev,
185 struct device_attribute *devAttr,
186 const char *buf, size_t size)
189 struct lm3639_chip_data *pchip = dev_get_drvdata(dev);
192 ret = kstrtouint(buf, 10, &state);
198 regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10,
202 regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10,
211 dev_err(pchip->dev, "%s:i2c access fail to register\n", __func__);
215 dev_err(pchip->dev, "%s:input conversion fail\n", __func__);
220 static DEVICE_ATTR(bled_mode, S_IWUSR, NULL, lm3639_bled_mode_store);
223 static void lm3639_torch_brightness_set(struct led_classdev *cdev,
224 enum led_brightness brightness)
227 unsigned int reg_val;
228 struct lm3639_chip_data *pchip;
230 pchip = container_of(cdev, struct lm3639_chip_data, cdev_torch);
232 ret = regmap_read(pchip->regmap, REG_FLAG, ®_val);
236 dev_info(pchip->dev, "last flag is 0x%x\n", reg_val);
238 /* brightness 0 means off state */
240 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00);
246 ret = regmap_update_bits(pchip->regmap,
247 REG_FL_CONF_1, 0x70, (brightness - 1) << 4);
250 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x02);
256 dev_err(pchip->dev, "i2c failed to access register\n");
260 static void lm3639_flash_brightness_set(struct led_classdev *cdev,
261 enum led_brightness brightness)
264 unsigned int reg_val;
265 struct lm3639_chip_data *pchip;
267 pchip = container_of(cdev, struct lm3639_chip_data, cdev_flash);
269 ret = regmap_read(pchip->regmap, REG_FLAG, ®_val);
273 dev_info(pchip->dev, "last flag is 0x%x\n", reg_val);
275 /* torch off before flash control */
276 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00);
280 /* brightness 0 means off state */
284 ret = regmap_update_bits(pchip->regmap,
285 REG_FL_CONF_1, 0x0F, brightness - 1);
288 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x06);
294 dev_err(pchip->dev, "i2c failed to access register\n");
297 static const struct regmap_config lm3639_regmap = {
300 .max_register = REG_MAX,
303 static int lm3639_probe(struct i2c_client *client,
304 const struct i2c_device_id *id)
307 struct lm3639_chip_data *pchip;
308 struct lm3639_platform_data *pdata = dev_get_platdata(&client->dev);
309 struct backlight_properties props;
311 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
312 dev_err(&client->dev, "i2c functionality check fail.\n");
317 dev_err(&client->dev, "Needs Platform Data.\n");
321 pchip = devm_kzalloc(&client->dev,
322 sizeof(struct lm3639_chip_data), GFP_KERNEL);
326 pchip->pdata = pdata;
327 pchip->dev = &client->dev;
329 pchip->regmap = devm_regmap_init_i2c(client, &lm3639_regmap);
330 if (IS_ERR(pchip->regmap)) {
331 ret = PTR_ERR(pchip->regmap);
332 dev_err(&client->dev, "fail : allocate register map: %d\n",
336 i2c_set_clientdata(client, pchip);
338 /* chip initialize */
339 ret = lm3639_chip_init(pchip);
341 dev_err(&client->dev, "fail : chip init\n");
346 props.type = BACKLIGHT_RAW;
347 props.brightness = pdata->init_brt_led;
348 props.max_brightness = pdata->max_brt_led;
350 devm_backlight_device_register(pchip->dev, "lm3639_bled",
351 pchip->dev, pchip, &lm3639_bled_ops,
353 if (IS_ERR(pchip->bled)) {
354 dev_err(&client->dev, "fail : backlight register\n");
355 ret = PTR_ERR(pchip->bled);
359 ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
361 dev_err(&client->dev, "failed : add sysfs entries\n");
366 pchip->cdev_flash.name = "lm3639_flash";
367 pchip->cdev_flash.max_brightness = 16;
368 pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set;
369 ret = led_classdev_register((struct device *)
370 &client->dev, &pchip->cdev_flash);
372 dev_err(&client->dev, "fail : flash register\n");
377 pchip->cdev_torch.name = "lm3639_torch";
378 pchip->cdev_torch.max_brightness = 8;
379 pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set;
380 ret = led_classdev_register((struct device *)
381 &client->dev, &pchip->cdev_torch);
383 dev_err(&client->dev, "fail : torch register\n");
390 led_classdev_unregister(&pchip->cdev_flash);
392 device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
397 static int lm3639_remove(struct i2c_client *client)
399 struct lm3639_chip_data *pchip = i2c_get_clientdata(client);
401 regmap_write(pchip->regmap, REG_ENABLE, 0x00);
403 if (&pchip->cdev_torch)
404 led_classdev_unregister(&pchip->cdev_torch);
405 if (&pchip->cdev_flash)
406 led_classdev_unregister(&pchip->cdev_flash);
408 device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
412 static const struct i2c_device_id lm3639_id[] = {
417 MODULE_DEVICE_TABLE(i2c, lm3639_id);
418 static struct i2c_driver lm3639_i2c_driver = {
422 .probe = lm3639_probe,
423 .remove = lm3639_remove,
424 .id_table = lm3639_id,
427 module_i2c_driver(lm3639_i2c_driver);
429 MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639");
430 MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
431 MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
432 MODULE_LICENSE("GPL v2");