1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip 4 * Copyright (C) 2012 Texas Instruments 5 */ 6 #include <linux/module.h> 7 #include <linux/slab.h> 8 #include <linux/i2c.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> 17 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 29 #define REG_FLAG 0x0B 30 #define REG_MAX REG_FLAG 31 32 struct lm3639_chip_data { 33 struct device *dev; 34 struct lm3639_platform_data *pdata; 35 36 struct backlight_device *bled; 37 struct led_classdev cdev_flash; 38 struct led_classdev cdev_torch; 39 struct regmap *regmap; 40 41 unsigned int bled_mode; 42 unsigned int bled_map; 43 unsigned int last_flag; 44 }; 45 46 /* initialize chip */ 47 static int lm3639_chip_init(struct lm3639_chip_data *pchip) 48 { 49 int ret; 50 unsigned int reg_val; 51 struct lm3639_platform_data *pdata = pchip->pdata; 52 53 /* input pins config. */ 54 ret = 55 regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x08, 56 pdata->pin_pwm); 57 if (ret < 0) 58 goto out; 59 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); 62 if (ret < 0) 63 goto out; 64 65 /* init brightness */ 66 ret = regmap_write(pchip->regmap, REG_BL_CONF_4, pdata->init_brt_led); 67 if (ret < 0) 68 goto out; 69 70 ret = regmap_write(pchip->regmap, REG_BL_CONF_3, pdata->init_brt_led); 71 if (ret < 0) 72 goto out; 73 74 /* output pins config. */ 75 if (!pdata->init_brt_led) { 76 reg_val = pdata->fled_pins; 77 reg_val |= pdata->bled_pins; 78 } else { 79 reg_val = pdata->fled_pins; 80 reg_val |= pdata->bled_pins | 0x01; 81 } 82 83 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val); 84 if (ret < 0) 85 goto out; 86 87 return ret; 88 out: 89 dev_err(pchip->dev, "i2c failed to access register\n"); 90 return ret; 91 } 92 93 /* update and get brightness */ 94 static int lm3639_bled_update_status(struct backlight_device *bl) 95 { 96 int ret; 97 unsigned int reg_val; 98 struct lm3639_chip_data *pchip = bl_get_data(bl); 99 struct lm3639_platform_data *pdata = pchip->pdata; 100 101 ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); 102 if (ret < 0) 103 goto out; 104 105 if (reg_val != 0) 106 dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); 107 108 /* pwm control */ 109 if (pdata->pin_pwm) { 110 if (pdata->pwm_set_intensity) 111 pdata->pwm_set_intensity(bl->props.brightness, 112 pdata->max_brt_led); 113 else 114 dev_err(pchip->dev, 115 "No pwm control func. in plat-data\n"); 116 return bl->props.brightness; 117 } 118 119 /* i2c control and set brigtness */ 120 ret = regmap_write(pchip->regmap, REG_BL_CONF_4, bl->props.brightness); 121 if (ret < 0) 122 goto out; 123 ret = regmap_write(pchip->regmap, REG_BL_CONF_3, bl->props.brightness); 124 if (ret < 0) 125 goto out; 126 127 if (!bl->props.brightness) 128 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x00); 129 else 130 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x01); 131 if (ret < 0) 132 goto out; 133 134 return bl->props.brightness; 135 out: 136 dev_err(pchip->dev, "i2c failed to access registers\n"); 137 return bl->props.brightness; 138 } 139 140 static int lm3639_bled_get_brightness(struct backlight_device *bl) 141 { 142 int ret; 143 unsigned int reg_val; 144 struct lm3639_chip_data *pchip = bl_get_data(bl); 145 struct lm3639_platform_data *pdata = pchip->pdata; 146 147 if (pdata->pin_pwm) { 148 if (pdata->pwm_get_intensity) 149 bl->props.brightness = pdata->pwm_get_intensity(); 150 else 151 dev_err(pchip->dev, 152 "No pwm control func. in plat-data\n"); 153 return bl->props.brightness; 154 } 155 156 ret = regmap_read(pchip->regmap, REG_BL_CONF_1, ®_val); 157 if (ret < 0) 158 goto out; 159 if (reg_val & 0x10) 160 ret = regmap_read(pchip->regmap, REG_BL_CONF_4, ®_val); 161 else 162 ret = regmap_read(pchip->regmap, REG_BL_CONF_3, ®_val); 163 if (ret < 0) 164 goto out; 165 bl->props.brightness = reg_val; 166 167 return bl->props.brightness; 168 out: 169 dev_err(pchip->dev, "i2c failed to access register\n"); 170 return bl->props.brightness; 171 } 172 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, 177 }; 178 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) 183 { 184 ssize_t ret; 185 struct lm3639_chip_data *pchip = dev_get_drvdata(dev); 186 unsigned int state; 187 188 ret = kstrtouint(buf, 10, &state); 189 if (ret) 190 goto out_input; 191 192 if (!state) 193 ret = 194 regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, 195 0x00); 196 else 197 ret = 198 regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, 199 0x10); 200 201 if (ret < 0) 202 goto out; 203 204 return size; 205 206 out: 207 dev_err(pchip->dev, "%s:i2c access fail to register\n", __func__); 208 return ret; 209 210 out_input: 211 dev_err(pchip->dev, "%s:input conversion fail\n", __func__); 212 return ret; 213 214 } 215 216 static DEVICE_ATTR(bled_mode, S_IWUSR, NULL, lm3639_bled_mode_store); 217 218 /* torch */ 219 static void lm3639_torch_brightness_set(struct led_classdev *cdev, 220 enum led_brightness brightness) 221 { 222 int ret; 223 unsigned int reg_val; 224 struct lm3639_chip_data *pchip; 225 226 pchip = container_of(cdev, struct lm3639_chip_data, cdev_torch); 227 228 ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); 229 if (ret < 0) 230 goto out; 231 if (reg_val != 0) 232 dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); 233 234 /* brightness 0 means off state */ 235 if (!brightness) { 236 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); 237 if (ret < 0) 238 goto out; 239 return; 240 } 241 242 ret = regmap_update_bits(pchip->regmap, 243 REG_FL_CONF_1, 0x70, (brightness - 1) << 4); 244 if (ret < 0) 245 goto out; 246 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x02); 247 if (ret < 0) 248 goto out; 249 250 return; 251 out: 252 dev_err(pchip->dev, "i2c failed to access register\n"); 253 } 254 255 /* flash */ 256 static void lm3639_flash_brightness_set(struct led_classdev *cdev, 257 enum led_brightness brightness) 258 { 259 int ret; 260 unsigned int reg_val; 261 struct lm3639_chip_data *pchip; 262 263 pchip = container_of(cdev, struct lm3639_chip_data, cdev_flash); 264 265 ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); 266 if (ret < 0) 267 goto out; 268 if (reg_val != 0) 269 dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); 270 271 /* torch off before flash control */ 272 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); 273 if (ret < 0) 274 goto out; 275 276 /* brightness 0 means off state */ 277 if (!brightness) 278 return; 279 280 ret = regmap_update_bits(pchip->regmap, 281 REG_FL_CONF_1, 0x0F, brightness - 1); 282 if (ret < 0) 283 goto out; 284 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x06); 285 if (ret < 0) 286 goto out; 287 288 return; 289 out: 290 dev_err(pchip->dev, "i2c failed to access register\n"); 291 } 292 293 static const struct regmap_config lm3639_regmap = { 294 .reg_bits = 8, 295 .val_bits = 8, 296 .max_register = REG_MAX, 297 }; 298 299 static int lm3639_probe(struct i2c_client *client) 300 { 301 int ret; 302 struct lm3639_chip_data *pchip; 303 struct lm3639_platform_data *pdata = dev_get_platdata(&client->dev); 304 struct backlight_properties props; 305 306 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 307 dev_err(&client->dev, "i2c functionality check fail.\n"); 308 return -EOPNOTSUPP; 309 } 310 311 if (pdata == NULL) { 312 dev_err(&client->dev, "Needs Platform Data.\n"); 313 return -ENODATA; 314 } 315 316 pchip = devm_kzalloc(&client->dev, 317 sizeof(struct lm3639_chip_data), GFP_KERNEL); 318 if (!pchip) 319 return -ENOMEM; 320 321 pchip->pdata = pdata; 322 pchip->dev = &client->dev; 323 324 pchip->regmap = devm_regmap_init_i2c(client, &lm3639_regmap); 325 if (IS_ERR(pchip->regmap)) { 326 ret = PTR_ERR(pchip->regmap); 327 dev_err(&client->dev, "fail : allocate register map: %d\n", 328 ret); 329 return ret; 330 } 331 i2c_set_clientdata(client, pchip); 332 333 /* chip initialize */ 334 ret = lm3639_chip_init(pchip); 335 if (ret < 0) { 336 dev_err(&client->dev, "fail : chip init\n"); 337 goto err_out; 338 } 339 340 /* backlight */ 341 props.type = BACKLIGHT_RAW; 342 props.brightness = pdata->init_brt_led; 343 props.max_brightness = pdata->max_brt_led; 344 pchip->bled = 345 devm_backlight_device_register(pchip->dev, "lm3639_bled", 346 pchip->dev, pchip, &lm3639_bled_ops, 347 &props); 348 if (IS_ERR(pchip->bled)) { 349 dev_err(&client->dev, "fail : backlight register\n"); 350 ret = PTR_ERR(pchip->bled); 351 goto err_out; 352 } 353 354 ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode); 355 if (ret < 0) { 356 dev_err(&client->dev, "failed : add sysfs entries\n"); 357 goto err_out; 358 } 359 360 /* flash */ 361 pchip->cdev_flash.name = "lm3639_flash"; 362 pchip->cdev_flash.max_brightness = 16; 363 pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set; 364 ret = led_classdev_register((struct device *) 365 &client->dev, &pchip->cdev_flash); 366 if (ret < 0) { 367 dev_err(&client->dev, "fail : flash register\n"); 368 goto err_flash; 369 } 370 371 /* torch */ 372 pchip->cdev_torch.name = "lm3639_torch"; 373 pchip->cdev_torch.max_brightness = 8; 374 pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set; 375 ret = led_classdev_register((struct device *) 376 &client->dev, &pchip->cdev_torch); 377 if (ret < 0) { 378 dev_err(&client->dev, "fail : torch register\n"); 379 goto err_torch; 380 } 381 382 return 0; 383 384 err_torch: 385 led_classdev_unregister(&pchip->cdev_flash); 386 err_flash: 387 device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); 388 err_out: 389 return ret; 390 } 391 392 static void lm3639_remove(struct i2c_client *client) 393 { 394 struct lm3639_chip_data *pchip = i2c_get_clientdata(client); 395 396 regmap_write(pchip->regmap, REG_ENABLE, 0x00); 397 398 led_classdev_unregister(&pchip->cdev_torch); 399 led_classdev_unregister(&pchip->cdev_flash); 400 if (pchip->bled) 401 device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); 402 } 403 404 static const struct i2c_device_id lm3639_id[] = { 405 {LM3639_NAME, 0}, 406 {} 407 }; 408 409 MODULE_DEVICE_TABLE(i2c, lm3639_id); 410 static struct i2c_driver lm3639_i2c_driver = { 411 .driver = { 412 .name = LM3639_NAME, 413 }, 414 .probe = lm3639_probe, 415 .remove = lm3639_remove, 416 .id_table = lm3639_id, 417 }; 418 419 module_i2c_driver(lm3639_i2c_driver); 420 421 MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639"); 422 MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); 423 MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>"); 424 MODULE_LICENSE("GPL v2"); 425