1 // SPDX-License-Identifier: GPL-2.0-only
3 * Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip
4 * Copyright (C) 2012 Texas Instruments
6 #include <linux/module.h>
7 #include <linux/slab.h>
9 #include <linux/leds.h>
10 #include <linux/backlight.h>
11 #include <linux/err.h>
12 #include <linux/delay.h>
13 #include <linux/uaccess.h>
14 #include <linux/interrupt.h>
15 #include <linux/regmap.h>
16 #include <linux/platform_data/lm3639_bl.h>
18 #define REG_DEV_ID 0x00
19 #define REG_CHECKSUM 0x01
20 #define REG_BL_CONF_1 0x02
21 #define REG_BL_CONF_2 0x03
22 #define REG_BL_CONF_3 0x04
23 #define REG_BL_CONF_4 0x05
24 #define REG_FL_CONF_1 0x06
25 #define REG_FL_CONF_2 0x07
26 #define REG_FL_CONF_3 0x08
27 #define REG_IO_CTRL 0x09
28 #define REG_ENABLE 0x0A
30 #define REG_MAX REG_FLAG
32 struct lm3639_chip_data
{
34 struct lm3639_platform_data
*pdata
;
36 struct backlight_device
*bled
;
37 struct led_classdev cdev_flash
;
38 struct led_classdev cdev_torch
;
39 struct regmap
*regmap
;
41 unsigned int bled_mode
;
42 unsigned int bled_map
;
43 unsigned int last_flag
;
47 static int lm3639_chip_init(struct lm3639_chip_data
*pchip
)
51 struct lm3639_platform_data
*pdata
= pchip
->pdata
;
53 /* input pins config. */
55 regmap_update_bits(pchip
->regmap
, REG_BL_CONF_1
, 0x08,
60 reg_val
= (pdata
->pin_pwm
& 0x40) | pdata
->pin_strobe
| pdata
->pin_tx
;
61 ret
= regmap_update_bits(pchip
->regmap
, REG_IO_CTRL
, 0x7C, reg_val
);
66 ret
= regmap_write(pchip
->regmap
, REG_BL_CONF_4
, pdata
->init_brt_led
);
70 ret
= regmap_write(pchip
->regmap
, REG_BL_CONF_3
, pdata
->init_brt_led
);
74 /* output pins config. */
75 if (!pdata
->init_brt_led
) {
76 reg_val
= pdata
->fled_pins
;
77 reg_val
|= pdata
->bled_pins
;
79 reg_val
= pdata
->fled_pins
;
80 reg_val
|= pdata
->bled_pins
| 0x01;
83 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x79, reg_val
);
89 dev_err(pchip
->dev
, "i2c failed to access register\n");
93 /* update and get brightness */
94 static int lm3639_bled_update_status(struct backlight_device
*bl
)
98 struct lm3639_chip_data
*pchip
= bl_get_data(bl
);
99 struct lm3639_platform_data
*pdata
= pchip
->pdata
;
101 ret
= regmap_read(pchip
->regmap
, REG_FLAG
, ®_val
);
106 dev_info(pchip
->dev
, "last flag is 0x%x\n", reg_val
);
109 if (pdata
->pin_pwm
) {
110 if (pdata
->pwm_set_intensity
)
111 pdata
->pwm_set_intensity(bl
->props
.brightness
,
115 "No pwm control func. in plat-data\n");
116 return bl
->props
.brightness
;
119 /* i2c control and set brigtness */
120 ret
= regmap_write(pchip
->regmap
, REG_BL_CONF_4
, bl
->props
.brightness
);
123 ret
= regmap_write(pchip
->regmap
, REG_BL_CONF_3
, bl
->props
.brightness
);
127 if (!bl
->props
.brightness
)
128 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x01, 0x00);
130 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x01, 0x01);
134 return bl
->props
.brightness
;
136 dev_err(pchip
->dev
, "i2c failed to access registers\n");
137 return bl
->props
.brightness
;
140 static int lm3639_bled_get_brightness(struct backlight_device
*bl
)
143 unsigned int reg_val
;
144 struct lm3639_chip_data
*pchip
= bl_get_data(bl
);
145 struct lm3639_platform_data
*pdata
= pchip
->pdata
;
147 if (pdata
->pin_pwm
) {
148 if (pdata
->pwm_get_intensity
)
149 bl
->props
.brightness
= pdata
->pwm_get_intensity();
152 "No pwm control func. in plat-data\n");
153 return bl
->props
.brightness
;
156 ret
= regmap_read(pchip
->regmap
, REG_BL_CONF_1
, ®_val
);
160 ret
= regmap_read(pchip
->regmap
, REG_BL_CONF_4
, ®_val
);
162 ret
= regmap_read(pchip
->regmap
, REG_BL_CONF_3
, ®_val
);
165 bl
->props
.brightness
= reg_val
;
167 return bl
->props
.brightness
;
169 dev_err(pchip
->dev
, "i2c failed to access register\n");
170 return bl
->props
.brightness
;
173 static const struct backlight_ops lm3639_bled_ops
= {
174 .options
= BL_CORE_SUSPENDRESUME
,
175 .update_status
= lm3639_bled_update_status
,
176 .get_brightness
= lm3639_bled_get_brightness
,
179 /* backlight mapping mode */
180 static ssize_t
lm3639_bled_mode_store(struct device
*dev
,
181 struct device_attribute
*devAttr
,
182 const char *buf
, size_t size
)
185 struct lm3639_chip_data
*pchip
= dev_get_drvdata(dev
);
188 ret
= kstrtouint(buf
, 10, &state
);
194 regmap_update_bits(pchip
->regmap
, REG_BL_CONF_1
, 0x10,
198 regmap_update_bits(pchip
->regmap
, REG_BL_CONF_1
, 0x10,
207 dev_err(pchip
->dev
, "%s:i2c access fail to register\n", __func__
);
211 dev_err(pchip
->dev
, "%s:input conversion fail\n", __func__
);
216 static DEVICE_ATTR(bled_mode
, S_IWUSR
, NULL
, lm3639_bled_mode_store
);
219 static void lm3639_torch_brightness_set(struct led_classdev
*cdev
,
220 enum led_brightness brightness
)
223 unsigned int reg_val
;
224 struct lm3639_chip_data
*pchip
;
226 pchip
= container_of(cdev
, struct lm3639_chip_data
, cdev_torch
);
228 ret
= regmap_read(pchip
->regmap
, REG_FLAG
, ®_val
);
232 dev_info(pchip
->dev
, "last flag is 0x%x\n", reg_val
);
234 /* brightness 0 means off state */
236 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x06, 0x00);
242 ret
= regmap_update_bits(pchip
->regmap
,
243 REG_FL_CONF_1
, 0x70, (brightness
- 1) << 4);
246 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x06, 0x02);
252 dev_err(pchip
->dev
, "i2c failed to access register\n");
256 static void lm3639_flash_brightness_set(struct led_classdev
*cdev
,
257 enum led_brightness brightness
)
260 unsigned int reg_val
;
261 struct lm3639_chip_data
*pchip
;
263 pchip
= container_of(cdev
, struct lm3639_chip_data
, cdev_flash
);
265 ret
= regmap_read(pchip
->regmap
, REG_FLAG
, ®_val
);
269 dev_info(pchip
->dev
, "last flag is 0x%x\n", reg_val
);
271 /* torch off before flash control */
272 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x06, 0x00);
276 /* brightness 0 means off state */
280 ret
= regmap_update_bits(pchip
->regmap
,
281 REG_FL_CONF_1
, 0x0F, brightness
- 1);
284 ret
= regmap_update_bits(pchip
->regmap
, REG_ENABLE
, 0x06, 0x06);
290 dev_err(pchip
->dev
, "i2c failed to access register\n");
293 static const struct regmap_config lm3639_regmap
= {
296 .max_register
= REG_MAX
,
299 static int lm3639_probe(struct i2c_client
*client
,
300 const struct i2c_device_id
*id
)
303 struct lm3639_chip_data
*pchip
;
304 struct lm3639_platform_data
*pdata
= dev_get_platdata(&client
->dev
);
305 struct backlight_properties props
;
307 if (!i2c_check_functionality(client
->adapter
, I2C_FUNC_I2C
)) {
308 dev_err(&client
->dev
, "i2c functionality check fail.\n");
313 dev_err(&client
->dev
, "Needs Platform Data.\n");
317 pchip
= devm_kzalloc(&client
->dev
,
318 sizeof(struct lm3639_chip_data
), GFP_KERNEL
);
322 pchip
->pdata
= pdata
;
323 pchip
->dev
= &client
->dev
;
325 pchip
->regmap
= devm_regmap_init_i2c(client
, &lm3639_regmap
);
326 if (IS_ERR(pchip
->regmap
)) {
327 ret
= PTR_ERR(pchip
->regmap
);
328 dev_err(&client
->dev
, "fail : allocate register map: %d\n",
332 i2c_set_clientdata(client
, pchip
);
334 /* chip initialize */
335 ret
= lm3639_chip_init(pchip
);
337 dev_err(&client
->dev
, "fail : chip init\n");
342 props
.type
= BACKLIGHT_RAW
;
343 props
.brightness
= pdata
->init_brt_led
;
344 props
.max_brightness
= pdata
->max_brt_led
;
346 devm_backlight_device_register(pchip
->dev
, "lm3639_bled",
347 pchip
->dev
, pchip
, &lm3639_bled_ops
,
349 if (IS_ERR(pchip
->bled
)) {
350 dev_err(&client
->dev
, "fail : backlight register\n");
351 ret
= PTR_ERR(pchip
->bled
);
355 ret
= device_create_file(&(pchip
->bled
->dev
), &dev_attr_bled_mode
);
357 dev_err(&client
->dev
, "failed : add sysfs entries\n");
362 pchip
->cdev_flash
.name
= "lm3639_flash";
363 pchip
->cdev_flash
.max_brightness
= 16;
364 pchip
->cdev_flash
.brightness_set
= lm3639_flash_brightness_set
;
365 ret
= led_classdev_register((struct device
*)
366 &client
->dev
, &pchip
->cdev_flash
);
368 dev_err(&client
->dev
, "fail : flash register\n");
373 pchip
->cdev_torch
.name
= "lm3639_torch";
374 pchip
->cdev_torch
.max_brightness
= 8;
375 pchip
->cdev_torch
.brightness_set
= lm3639_torch_brightness_set
;
376 ret
= led_classdev_register((struct device
*)
377 &client
->dev
, &pchip
->cdev_torch
);
379 dev_err(&client
->dev
, "fail : torch register\n");
386 led_classdev_unregister(&pchip
->cdev_flash
);
388 device_remove_file(&(pchip
->bled
->dev
), &dev_attr_bled_mode
);
393 static int lm3639_remove(struct i2c_client
*client
)
395 struct lm3639_chip_data
*pchip
= i2c_get_clientdata(client
);
397 regmap_write(pchip
->regmap
, REG_ENABLE
, 0x00);
399 led_classdev_unregister(&pchip
->cdev_torch
);
400 led_classdev_unregister(&pchip
->cdev_flash
);
402 device_remove_file(&(pchip
->bled
->dev
), &dev_attr_bled_mode
);
406 static const struct i2c_device_id lm3639_id
[] = {
411 MODULE_DEVICE_TABLE(i2c
, lm3639_id
);
412 static struct i2c_driver lm3639_i2c_driver
= {
416 .probe
= lm3639_probe
,
417 .remove
= lm3639_remove
,
418 .id_table
= lm3639_id
,
421 module_i2c_driver(lm3639_i2c_driver
);
423 MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639");
424 MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
425 MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
426 MODULE_LICENSE("GPL v2");