1/* 2 * TI LP8860 4-Channel LED Driver 3 * 4 * Copyright (C) 2014 Texas Instruments 5 * 6 * Author: Dan Murphy <dmurphy@ti.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 */ 13 14#include <linux/i2c.h> 15#include <linux/init.h> 16#include <linux/leds.h> 17#include <linux/regmap.h> 18#include <linux/regulator/consumer.h> 19#include <linux/module.h> 20#include <linux/mutex.h> 21#include <linux/of.h> 22#include <linux/of_gpio.h> 23#include <linux/gpio/consumer.h> 24#include <linux/slab.h> 25 26#define LP8860_DISP_CL1_BRT_MSB 0x00 27#define LP8860_DISP_CL1_BRT_LSB 0x01 28#define LP8860_DISP_CL1_CURR_MSB 0x02 29#define LP8860_DISP_CL1_CURR_LSB 0x03 30#define LP8860_CL2_BRT_MSB 0x04 31#define LP8860_CL2_BRT_LSB 0x05 32#define LP8860_CL2_CURRENT 0x06 33#define LP8860_CL3_BRT_MSB 0x07 34#define LP8860_CL3_BRT_LSB 0x08 35#define LP8860_CL3_CURRENT 0x09 36#define LP8860_CL4_BRT_MSB 0x0a 37#define LP8860_CL4_BRT_LSB 0x0b 38#define LP8860_CL4_CURRENT 0x0c 39#define LP8860_CONFIG 0x0d 40#define LP8860_STATUS 0x0e 41#define LP8860_FAULT 0x0f 42#define LP8860_LED_FAULT 0x10 43#define LP8860_FAULT_CLEAR 0x11 44#define LP8860_ID 0x12 45#define LP8860_TEMP_MSB 0x13 46#define LP8860_TEMP_LSB 0x14 47#define LP8860_DISP_LED_CURR_MSB 0x15 48#define LP8860_DISP_LED_CURR_LSB 0x16 49#define LP8860_DISP_LED_PWM_MSB 0x17 50#define LP8860_DISP_LED_PWM_LSB 0x18 51#define LP8860_EEPROM_CNTRL 0x19 52#define LP8860_EEPROM_UNLOCK 0x1a 53 54#define LP8860_EEPROM_REG_0 0x60 55#define LP8860_EEPROM_REG_1 0x61 56#define LP8860_EEPROM_REG_2 0x62 57#define LP8860_EEPROM_REG_3 0x63 58#define LP8860_EEPROM_REG_4 0x64 59#define LP8860_EEPROM_REG_5 0x65 60#define LP8860_EEPROM_REG_6 0x66 61#define LP8860_EEPROM_REG_7 0x67 62#define LP8860_EEPROM_REG_8 0x68 63#define LP8860_EEPROM_REG_9 0x69 64#define LP8860_EEPROM_REG_10 0x6a 65#define LP8860_EEPROM_REG_11 0x6b 66#define LP8860_EEPROM_REG_12 0x6c 67#define LP8860_EEPROM_REG_13 0x6d 68#define LP8860_EEPROM_REG_14 0x6e 69#define LP8860_EEPROM_REG_15 0x6f 70#define LP8860_EEPROM_REG_16 0x70 71#define LP8860_EEPROM_REG_17 0x71 72#define LP8860_EEPROM_REG_18 0x72 73#define LP8860_EEPROM_REG_19 0x73 74#define LP8860_EEPROM_REG_20 0x74 75#define LP8860_EEPROM_REG_21 0x75 76#define LP8860_EEPROM_REG_22 0x76 77#define LP8860_EEPROM_REG_23 0x77 78#define LP8860_EEPROM_REG_24 0x78 79 80#define LP8860_LOCK_EEPROM 0x00 81#define LP8860_UNLOCK_EEPROM 0x01 82#define LP8860_PROGRAM_EEPROM 0x02 83#define LP8860_EEPROM_CODE_1 0x08 84#define LP8860_EEPROM_CODE_2 0xba 85#define LP8860_EEPROM_CODE_3 0xef 86 87#define LP8860_CLEAR_FAULTS 0x01 88 89#define LP8860_DISP_LED_NAME "display_cluster" 90 91/** 92 * struct lp8860_led - 93 * @lock - Lock for reading/writing the device 94 * @work - Work item used to off load the brightness register writes 95 * @client - Pointer to the I2C client 96 * @led_dev - led class device pointer 97 * @regmap - Devices register map 98 * @eeprom_regmap - EEPROM register map 99 * @enable_gpio - VDDIO/EN gpio to enable communication interface 100 * @regulator - LED supply regulator pointer 101 * @brightness - Current brightness value requested 102 * @label - LED label 103**/ 104struct lp8860_led { 105 struct mutex lock; 106 struct work_struct work; 107 struct i2c_client *client; 108 struct led_classdev led_dev; 109 struct regmap *regmap; 110 struct regmap *eeprom_regmap; 111 struct gpio_desc *enable_gpio; 112 struct regulator *regulator; 113 enum led_brightness brightness; 114 const char *label; 115}; 116 117struct lp8860_eeprom_reg { 118 uint8_t reg; 119 uint8_t value; 120}; 121 122static struct lp8860_eeprom_reg lp8860_eeprom_disp_regs[] = { 123 { LP8860_EEPROM_REG_0, 0xed }, 124 { LP8860_EEPROM_REG_1, 0xdf }, 125 { LP8860_EEPROM_REG_2, 0xdc }, 126 { LP8860_EEPROM_REG_3, 0xf0 }, 127 { LP8860_EEPROM_REG_4, 0xdf }, 128 { LP8860_EEPROM_REG_5, 0xe5 }, 129 { LP8860_EEPROM_REG_6, 0xf2 }, 130 { LP8860_EEPROM_REG_7, 0x77 }, 131 { LP8860_EEPROM_REG_8, 0x77 }, 132 { LP8860_EEPROM_REG_9, 0x71 }, 133 { LP8860_EEPROM_REG_10, 0x3f }, 134 { LP8860_EEPROM_REG_11, 0xb7 }, 135 { LP8860_EEPROM_REG_12, 0x17 }, 136 { LP8860_EEPROM_REG_13, 0xef }, 137 { LP8860_EEPROM_REG_14, 0xb0 }, 138 { LP8860_EEPROM_REG_15, 0x87 }, 139 { LP8860_EEPROM_REG_16, 0xce }, 140 { LP8860_EEPROM_REG_17, 0x72 }, 141 { LP8860_EEPROM_REG_18, 0xe5 }, 142 { LP8860_EEPROM_REG_19, 0xdf }, 143 { LP8860_EEPROM_REG_20, 0x35 }, 144 { LP8860_EEPROM_REG_21, 0x06 }, 145 { LP8860_EEPROM_REG_22, 0xdc }, 146 { LP8860_EEPROM_REG_23, 0x88 }, 147 { LP8860_EEPROM_REG_24, 0x3E }, 148}; 149 150static int lp8860_unlock_eeprom(struct lp8860_led *led, int lock) 151{ 152 int ret; 153 154 mutex_lock(&led->lock); 155 156 if (lock == LP8860_UNLOCK_EEPROM) { 157 ret = regmap_write(led->regmap, 158 LP8860_EEPROM_UNLOCK, 159 LP8860_EEPROM_CODE_1); 160 if (ret) { 161 dev_err(&led->client->dev, "EEPROM Unlock failed\n"); 162 goto out; 163 } 164 165 ret = regmap_write(led->regmap, 166 LP8860_EEPROM_UNLOCK, 167 LP8860_EEPROM_CODE_2); 168 if (ret) { 169 dev_err(&led->client->dev, "EEPROM Unlock failed\n"); 170 goto out; 171 } 172 ret = regmap_write(led->regmap, 173 LP8860_EEPROM_UNLOCK, 174 LP8860_EEPROM_CODE_3); 175 if (ret) { 176 dev_err(&led->client->dev, "EEPROM Unlock failed\n"); 177 goto out; 178 } 179 } else { 180 ret = regmap_write(led->regmap, 181 LP8860_EEPROM_UNLOCK, 182 LP8860_LOCK_EEPROM); 183 } 184 185out: 186 mutex_unlock(&led->lock); 187 return ret; 188} 189 190static int lp8860_fault_check(struct lp8860_led *led) 191{ 192 int ret, fault; 193 unsigned int read_buf; 194 195 ret = regmap_read(led->regmap, LP8860_LED_FAULT, &read_buf); 196 if (ret) 197 goto out; 198 199 fault = read_buf; 200 201 ret = regmap_read(led->regmap, LP8860_FAULT, &read_buf); 202 if (ret) 203 goto out; 204 205 fault |= read_buf; 206 207 /* Attempt to clear any faults */ 208 if (fault) 209 ret = regmap_write(led->regmap, LP8860_FAULT_CLEAR, 210 LP8860_CLEAR_FAULTS); 211out: 212 return ret; 213} 214 215static void lp8860_led_brightness_work(struct work_struct *work) 216{ 217 struct lp8860_led *led = container_of(work, struct lp8860_led, work); 218 int ret; 219 int disp_brightness = led->brightness * 255; 220 221 mutex_lock(&led->lock); 222 223 ret = lp8860_fault_check(led); 224 if (ret) { 225 dev_err(&led->client->dev, "Cannot read/clear faults\n"); 226 goto out; 227 } 228 229 ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_MSB, 230 (disp_brightness & 0xff00) >> 8); 231 if (ret) { 232 dev_err(&led->client->dev, "Cannot write CL1 MSB\n"); 233 goto out; 234 } 235 236 ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_LSB, 237 disp_brightness & 0xff); 238 if (ret) { 239 dev_err(&led->client->dev, "Cannot write CL1 LSB\n"); 240 goto out; 241 } 242out: 243 mutex_unlock(&led->lock); 244} 245 246static void lp8860_brightness_set(struct led_classdev *led_cdev, 247 enum led_brightness brt_val) 248{ 249 struct lp8860_led *led = 250 container_of(led_cdev, struct lp8860_led, led_dev); 251 252 led->brightness = brt_val; 253 schedule_work(&led->work); 254} 255 256static int lp8860_init(struct lp8860_led *led) 257{ 258 unsigned int read_buf; 259 int ret, i, reg_count; 260 261 if (led->enable_gpio) 262 gpiod_direction_output(led->enable_gpio, 1); 263 264 ret = lp8860_fault_check(led); 265 if (ret) 266 goto out; 267 268 ret = regmap_read(led->regmap, LP8860_STATUS, &read_buf); 269 if (ret) 270 goto out; 271 272 ret = lp8860_unlock_eeprom(led, LP8860_UNLOCK_EEPROM); 273 if (ret) { 274 dev_err(&led->client->dev, "Failed unlocking EEPROM\n"); 275 goto out; 276 } 277 278 reg_count = ARRAY_SIZE(lp8860_eeprom_disp_regs) / sizeof(lp8860_eeprom_disp_regs[0]); 279 for (i = 0; i < reg_count; i++) { 280 ret = regmap_write(led->eeprom_regmap, 281 lp8860_eeprom_disp_regs[i].reg, 282 lp8860_eeprom_disp_regs[i].value); 283 if (ret) { 284 dev_err(&led->client->dev, "Failed writing EEPROM\n"); 285 goto out; 286 } 287 } 288 289 ret = lp8860_unlock_eeprom(led, LP8860_LOCK_EEPROM); 290 if (ret) 291 goto out; 292 293 ret = regmap_write(led->regmap, 294 LP8860_EEPROM_CNTRL, 295 LP8860_PROGRAM_EEPROM); 296 if (ret) 297 dev_err(&led->client->dev, "Failed programming EEPROM\n"); 298out: 299 if (ret) 300 if (led->enable_gpio) 301 gpiod_direction_output(led->enable_gpio, 0); 302 return ret; 303} 304 305static const struct reg_default lp8860_reg_defs[] = { 306 { LP8860_DISP_CL1_BRT_MSB, 0x00}, 307 { LP8860_DISP_CL1_BRT_LSB, 0x00}, 308 { LP8860_DISP_CL1_CURR_MSB, 0x00}, 309 { LP8860_DISP_CL1_CURR_LSB, 0x00}, 310 { LP8860_CL2_BRT_MSB, 0x00}, 311 { LP8860_CL2_BRT_LSB, 0x00}, 312 { LP8860_CL2_CURRENT, 0x00}, 313 { LP8860_CL3_BRT_MSB, 0x00}, 314 { LP8860_CL3_BRT_LSB, 0x00}, 315 { LP8860_CL3_CURRENT, 0x00}, 316 { LP8860_CL4_BRT_MSB, 0x00}, 317 { LP8860_CL4_BRT_LSB, 0x00}, 318 { LP8860_CL4_CURRENT, 0x00}, 319 { LP8860_CONFIG, 0x00}, 320 { LP8860_FAULT_CLEAR, 0x00}, 321 { LP8860_EEPROM_CNTRL, 0x80}, 322 { LP8860_EEPROM_UNLOCK, 0x00}, 323}; 324 325static const struct regmap_config lp8860_regmap_config = { 326 .reg_bits = 8, 327 .val_bits = 8, 328 329 .max_register = LP8860_EEPROM_UNLOCK, 330 .reg_defaults = lp8860_reg_defs, 331 .num_reg_defaults = ARRAY_SIZE(lp8860_reg_defs), 332 .cache_type = REGCACHE_NONE, 333}; 334 335static const struct reg_default lp8860_eeprom_defs[] = { 336 { LP8860_EEPROM_REG_0, 0x00 }, 337 { LP8860_EEPROM_REG_1, 0x00 }, 338 { LP8860_EEPROM_REG_2, 0x00 }, 339 { LP8860_EEPROM_REG_3, 0x00 }, 340 { LP8860_EEPROM_REG_4, 0x00 }, 341 { LP8860_EEPROM_REG_5, 0x00 }, 342 { LP8860_EEPROM_REG_6, 0x00 }, 343 { LP8860_EEPROM_REG_7, 0x00 }, 344 { LP8860_EEPROM_REG_8, 0x00 }, 345 { LP8860_EEPROM_REG_9, 0x00 }, 346 { LP8860_EEPROM_REG_10, 0x00 }, 347 { LP8860_EEPROM_REG_11, 0x00 }, 348 { LP8860_EEPROM_REG_12, 0x00 }, 349 { LP8860_EEPROM_REG_13, 0x00 }, 350 { LP8860_EEPROM_REG_14, 0x00 }, 351 { LP8860_EEPROM_REG_15, 0x00 }, 352 { LP8860_EEPROM_REG_16, 0x00 }, 353 { LP8860_EEPROM_REG_17, 0x00 }, 354 { LP8860_EEPROM_REG_18, 0x00 }, 355 { LP8860_EEPROM_REG_19, 0x00 }, 356 { LP8860_EEPROM_REG_20, 0x00 }, 357 { LP8860_EEPROM_REG_21, 0x00 }, 358 { LP8860_EEPROM_REG_22, 0x00 }, 359 { LP8860_EEPROM_REG_23, 0x00 }, 360 { LP8860_EEPROM_REG_24, 0x00 }, 361}; 362 363static const struct regmap_config lp8860_eeprom_regmap_config = { 364 .reg_bits = 8, 365 .val_bits = 8, 366 367 .max_register = LP8860_EEPROM_REG_24, 368 .reg_defaults = lp8860_eeprom_defs, 369 .num_reg_defaults = ARRAY_SIZE(lp8860_eeprom_defs), 370 .cache_type = REGCACHE_NONE, 371}; 372 373static int lp8860_probe(struct i2c_client *client, 374 const struct i2c_device_id *id) 375{ 376 int ret; 377 struct lp8860_led *led; 378 struct device_node *np = client->dev.of_node; 379 380 led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); 381 if (!led) 382 return -ENOMEM; 383 384 led->label = LP8860_DISP_LED_NAME; 385 386 if (client->dev.of_node) { 387 ret = of_property_read_string(np, "label", &led->label); 388 if (ret) { 389 dev_err(&client->dev, "Missing label in dt\n"); 390 return -EINVAL; 391 } 392 } 393 394 led->enable_gpio = devm_gpiod_get_optional(&client->dev, 395 "enable", GPIOD_OUT_LOW); 396 if (IS_ERR(led->enable_gpio)) { 397 ret = PTR_ERR(led->enable_gpio); 398 dev_err(&client->dev, "Failed to get enable gpio: %d\n", ret); 399 return ret; 400 } 401 402 led->regulator = devm_regulator_get(&client->dev, "vled"); 403 if (IS_ERR(led->regulator)) 404 led->regulator = NULL; 405 406 led->client = client; 407 led->led_dev.name = led->label; 408 led->led_dev.max_brightness = LED_FULL; 409 led->led_dev.brightness_set = lp8860_brightness_set; 410 411 mutex_init(&led->lock); 412 INIT_WORK(&led->work, lp8860_led_brightness_work); 413 414 i2c_set_clientdata(client, led); 415 416 led->regmap = devm_regmap_init_i2c(client, &lp8860_regmap_config); 417 if (IS_ERR(led->regmap)) { 418 ret = PTR_ERR(led->regmap); 419 dev_err(&client->dev, "Failed to allocate register map: %d\n", 420 ret); 421 return ret; 422 } 423 424 led->eeprom_regmap = devm_regmap_init_i2c(client, &lp8860_eeprom_regmap_config); 425 if (IS_ERR(led->eeprom_regmap)) { 426 ret = PTR_ERR(led->eeprom_regmap); 427 dev_err(&client->dev, "Failed to allocate register map: %d\n", 428 ret); 429 return ret; 430 } 431 432 ret = lp8860_init(led); 433 if (ret) 434 return ret; 435 436 ret = led_classdev_register(&client->dev, &led->led_dev); 437 if (ret) { 438 dev_err(&client->dev, "led register err: %d\n", ret); 439 return ret; 440 } 441 442 return 0; 443} 444 445static int lp8860_remove(struct i2c_client *client) 446{ 447 struct lp8860_led *led = i2c_get_clientdata(client); 448 int ret; 449 450 led_classdev_unregister(&led->led_dev); 451 cancel_work_sync(&led->work); 452 453 if (led->enable_gpio) 454 gpiod_direction_output(led->enable_gpio, 0); 455 456 if (led->regulator) { 457 ret = regulator_disable(led->regulator); 458 if (ret) 459 dev_err(&led->client->dev, 460 "Failed to disable regulator\n"); 461 } 462 463 return 0; 464} 465 466static const struct i2c_device_id lp8860_id[] = { 467 { "lp8860", 0 }, 468 { } 469}; 470MODULE_DEVICE_TABLE(i2c, lp8860_id); 471 472#ifdef CONFIG_OF 473static const struct of_device_id of_lp8860_leds_match[] = { 474 { .compatible = "ti,lp8860", }, 475 {}, 476}; 477MODULE_DEVICE_TABLE(of, of_lp8860_leds_match); 478#endif 479 480static struct i2c_driver lp8860_driver = { 481 .driver = { 482 .name = "lp8860", 483 .of_match_table = of_match_ptr(of_lp8860_leds_match), 484 }, 485 .probe = lp8860_probe, 486 .remove = lp8860_remove, 487 .id_table = lp8860_id, 488}; 489module_i2c_driver(lp8860_driver); 490 491MODULE_DESCRIPTION("Texas Instruments LP8860 LED driver"); 492MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 493MODULE_LICENSE("GPL"); 494