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");