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
| pdata
->bled_pins
;
82 reg_val
= pdata
->fled_pins
| pdata
->bled_pins
| 0x01;
84 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x79, reg_val
);
90 dev_err(pchip
->dev
, "i2c failed to access register\n");
94 /* update and get brightness */
95 static int lm3639_bled_update_status(struct backlight_device
*bl
)
99 struct lm3639_chip_data
*pchip
= bl_get_data(bl
);
100 struct lm3639_platform_data
*pdata
= pchip
->pdata
;
102 ret
= regmap_read(pchip
->regmap
, REG_FLAG
, ®_val
);
107 dev_info(pchip
->dev
, "last flag is 0x%x\n", reg_val
);
110 if (pdata
->pin_pwm
) {
111 if (pdata
->pwm_set_intensity
)
112 pdata
->pwm_set_intensity(bl
->props
.brightness
,
116 "No pwm control func. in plat-data\n");
117 return bl
->props
.brightness
;
120 /* i2c control and set brigtness */
121 ret
= regmap_write(pchip
->regmap
, REG_BL_CONF_4
, bl
->props
.brightness
);
124 ret
= regmap_write(pchip
->regmap
, REG_BL_CONF_3
, bl
->props
.brightness
);
128 if (!bl
->props
.brightness
)
129 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x01, 0x00);
131 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x01, 0x01);
135 return bl
->props
.brightness
;
137 dev_err(pchip
->dev
, "i2c failed to access registers\n");
138 return bl
->props
.brightness
;
141 static int lm3639_bled_get_brightness(struct backlight_device
*bl
)
144 unsigned int reg_val
;
145 struct lm3639_chip_data
*pchip
= bl_get_data(bl
);
146 struct lm3639_platform_data
*pdata
= pchip
->pdata
;
148 if (pdata
->pin_pwm
) {
149 if (pdata
->pwm_get_intensity
)
150 bl
->props
.brightness
= pdata
->pwm_get_intensity();
153 "No pwm control func. in plat-data\n");
154 return bl
->props
.brightness
;
157 ret
= regmap_read(pchip
->regmap
, REG_BL_CONF_1
, ®_val
);
161 ret
= regmap_read(pchip
->regmap
, REG_BL_CONF_4
, ®_val
);
163 ret
= regmap_read(pchip
->regmap
, REG_BL_CONF_3
, ®_val
);
166 bl
->props
.brightness
= reg_val
;
168 return bl
->props
.brightness
;
170 dev_err(pchip
->dev
, "i2c failed to access register\n");
171 return bl
->props
.brightness
;
174 static const struct backlight_ops lm3639_bled_ops
= {
175 .options
= BL_CORE_SUSPENDRESUME
,
176 .update_status
= lm3639_bled_update_status
,
177 .get_brightness
= lm3639_bled_get_brightness
,
180 /* backlight mapping mode */
181 static ssize_t
lm3639_bled_mode_store(struct device
*dev
,
182 struct device_attribute
*devAttr
,
183 const char *buf
, size_t size
)
186 struct lm3639_chip_data
*pchip
= dev_get_drvdata(dev
);
189 ret
= kstrtouint(buf
, 10, &state
);
195 regmap_update_bits(pchip
->regmap
, REG_BL_CONF_1
, 0x10,
199 regmap_update_bits(pchip
->regmap
, REG_BL_CONF_1
, 0x10,
208 dev_err(pchip
->dev
, "%s:i2c access fail to register\n", __func__
);
212 dev_err(pchip
->dev
, "%s:input conversion fail\n", __func__
);
217 static DEVICE_ATTR(bled_mode
, S_IWUSR
, NULL
, lm3639_bled_mode_store
);
220 static void lm3639_torch_brightness_set(struct led_classdev
*cdev
,
221 enum led_brightness brightness
)
224 unsigned int reg_val
;
225 struct lm3639_chip_data
*pchip
;
227 pchip
= container_of(cdev
, struct lm3639_chip_data
, cdev_torch
);
229 ret
= regmap_read(pchip
->regmap
, REG_FLAG
, ®_val
);
233 dev_info(pchip
->dev
, "last flag is 0x%x\n", reg_val
);
235 /* brightness 0 means off state */
237 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x06, 0x00);
243 ret
= regmap_update_bits(pchip
->regmap
,
244 REG_FL_CONF_1
, 0x70, (brightness
- 1) << 4);
247 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x06, 0x02);
253 dev_err(pchip
->dev
, "i2c failed to access register\n");
258 static void lm3639_flash_brightness_set(struct led_classdev
*cdev
,
259 enum led_brightness brightness
)
262 unsigned int reg_val
;
263 struct lm3639_chip_data
*pchip
;
265 pchip
= container_of(cdev
, struct lm3639_chip_data
, cdev_flash
);
267 ret
= regmap_read(pchip
->regmap
, REG_FLAG
, ®_val
);
271 dev_info(pchip
->dev
, "last flag is 0x%x\n", reg_val
);
273 /* torch off before flash control */
274 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x06, 0x00);
278 /* brightness 0 means off state */
282 ret
= regmap_update_bits(pchip
->regmap
,
283 REG_FL_CONF_1
, 0x0F, brightness
- 1);
286 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x06, 0x06);
292 dev_err(pchip
->dev
, "i2c failed to access register\n");
296 static const struct regmap_config lm3639_regmap
= {
299 .max_register
= REG_MAX
,
302 static int lm3639_probe(struct i2c_client
*client
,
303 const struct i2c_device_id
*id
)
306 struct lm3639_chip_data
*pchip
;
307 struct lm3639_platform_data
*pdata
= client
->dev
.platform_data
;
308 struct backlight_properties props
;
310 if (!i2c_check_functionality(client
->adapter
, I2C_FUNC_I2C
)) {
311 dev_err(&client
->dev
, "i2c functionality check fail.\n");
316 dev_err(&client
->dev
, "Needs Platform Data.\n");
320 pchip
= devm_kzalloc(&client
->dev
,
321 sizeof(struct lm3639_chip_data
), GFP_KERNEL
);
325 pchip
->pdata
= pdata
;
326 pchip
->dev
= &client
->dev
;
328 pchip
->regmap
= devm_regmap_init_i2c(client
, &lm3639_regmap
);
329 if (IS_ERR(pchip
->regmap
)) {
330 ret
= PTR_ERR(pchip
->regmap
);
331 dev_err(&client
->dev
, "fail : allocate register map: %d\n",
335 i2c_set_clientdata(client
, pchip
);
337 /* chip initialize */
338 ret
= lm3639_chip_init(pchip
);
340 dev_err(&client
->dev
, "fail : chip init\n");
345 props
.type
= BACKLIGHT_RAW
;
346 props
.brightness
= pdata
->init_brt_led
;
347 props
.max_brightness
= pdata
->max_brt_led
;
349 backlight_device_register("lm3639_bled", pchip
->dev
, pchip
,
350 &lm3639_bled_ops
, &props
);
351 if (IS_ERR(pchip
->bled
)) {
352 dev_err(&client
->dev
, "fail : backlight register\n");
353 ret
= PTR_ERR(pchip
->bled
);
357 ret
= device_create_file(&(pchip
->bled
->dev
), &dev_attr_bled_mode
);
359 dev_err(&client
->dev
, "failed : add sysfs entries\n");
364 pchip
->cdev_flash
.name
= "lm3639_flash";
365 pchip
->cdev_flash
.max_brightness
= 16;
366 pchip
->cdev_flash
.brightness_set
= lm3639_flash_brightness_set
;
367 ret
= led_classdev_register((struct device
*)
368 &client
->dev
, &pchip
->cdev_flash
);
370 dev_err(&client
->dev
, "fail : flash register\n");
375 pchip
->cdev_torch
.name
= "lm3639_torch";
376 pchip
->cdev_torch
.max_brightness
= 8;
377 pchip
->cdev_torch
.brightness_set
= lm3639_torch_brightness_set
;
378 ret
= led_classdev_register((struct device
*)
379 &client
->dev
, &pchip
->cdev_torch
);
381 dev_err(&client
->dev
, "fail : torch register\n");
388 led_classdev_unregister(&pchip
->cdev_flash
);
390 device_remove_file(&(pchip
->bled
->dev
), &dev_attr_bled_mode
);
392 backlight_device_unregister(pchip
->bled
);
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
);
409 backlight_device_unregister(pchip
->bled
);
414 static const struct i2c_device_id lm3639_id
[] = {
419 MODULE_DEVICE_TABLE(i2c
, lm3639_id
);
420 static struct i2c_driver lm3639_i2c_driver
= {
424 .probe
= lm3639_probe
,
425 .remove
= lm3639_remove
,
426 .id_table
= lm3639_id
,
429 module_i2c_driver(lm3639_i2c_driver
);
431 MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639");
432 MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
433 MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
434 MODULE_LICENSE("GPL v2");