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 memset(&props, 0, sizeof(struct backlight_properties));
343 props.type = BACKLIGHT_RAW;
344 props.brightness = pdata->init_brt_led;
345 props.max_brightness = pdata->max_brt_led;
347 devm_backlight_device_register(pchip->dev, "lm3639_bled",
348 pchip->dev, pchip, &lm3639_bled_ops,
350 if (IS_ERR(pchip->bled)) {
351 dev_err(&client->dev, "fail : backlight register\n");
352 ret = PTR_ERR(pchip->bled);
356 ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
358 dev_err(&client->dev, "failed : add sysfs entries\n");
363 pchip->cdev_flash.name = "lm3639_flash";
364 pchip->cdev_flash.max_brightness = 16;
365 pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set;
366 ret = led_classdev_register((struct device *)
367 &client->dev, &pchip->cdev_flash);
369 dev_err(&client->dev, "fail : flash register\n");
374 pchip->cdev_torch.name = "lm3639_torch";
375 pchip->cdev_torch.max_brightness = 8;
376 pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set;
377 ret = led_classdev_register((struct device *)
378 &client->dev, &pchip->cdev_torch);
380 dev_err(&client->dev, "fail : torch register\n");
387 led_classdev_unregister(&pchip->cdev_flash);
389 device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
394 static int lm3639_remove(struct i2c_client *client)
396 struct lm3639_chip_data *pchip = i2c_get_clientdata(client);
398 regmap_write(pchip->regmap, REG_ENABLE, 0x00);
400 led_classdev_unregister(&pchip->cdev_torch);
401 led_classdev_unregister(&pchip->cdev_flash);
403 device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
407 static const struct i2c_device_id lm3639_id[] = {
412 MODULE_DEVICE_TABLE(i2c, lm3639_id);
413 static struct i2c_driver lm3639_i2c_driver = {
417 .probe = lm3639_probe,
418 .remove = lm3639_remove,
419 .id_table = lm3639_id,
422 module_i2c_driver(lm3639_i2c_driver);
424 MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639");
425 MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
426 MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
427 MODULE_LICENSE("GPL v2");