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 * @client - Pointer to the I2C client 95 * @led_dev - led class device pointer 96 * @regmap - Devices register map 97 * @eeprom_regmap - EEPROM register map 98 * @enable_gpio - VDDIO/EN gpio to enable communication interface 99 * @regulator - LED supply regulator pointer 100 * @label - LED label 101 **/ 102 struct lp8860_led { 103 struct mutex lock; 104 struct i2c_client *client; 105 struct led_classdev led_dev; 106 struct regmap *regmap; 107 struct regmap *eeprom_regmap; 108 struct gpio_desc *enable_gpio; 109 struct regulator *regulator; 110 const char *label; 111 }; 112 113 struct lp8860_eeprom_reg { 114 uint8_t reg; 115 uint8_t value; 116 }; 117 118 static struct lp8860_eeprom_reg lp8860_eeprom_disp_regs[] = { 119 { LP8860_EEPROM_REG_0, 0xed }, 120 { LP8860_EEPROM_REG_1, 0xdf }, 121 { LP8860_EEPROM_REG_2, 0xdc }, 122 { LP8860_EEPROM_REG_3, 0xf0 }, 123 { LP8860_EEPROM_REG_4, 0xdf }, 124 { LP8860_EEPROM_REG_5, 0xe5 }, 125 { LP8860_EEPROM_REG_6, 0xf2 }, 126 { LP8860_EEPROM_REG_7, 0x77 }, 127 { LP8860_EEPROM_REG_8, 0x77 }, 128 { LP8860_EEPROM_REG_9, 0x71 }, 129 { LP8860_EEPROM_REG_10, 0x3f }, 130 { LP8860_EEPROM_REG_11, 0xb7 }, 131 { LP8860_EEPROM_REG_12, 0x17 }, 132 { LP8860_EEPROM_REG_13, 0xef }, 133 { LP8860_EEPROM_REG_14, 0xb0 }, 134 { LP8860_EEPROM_REG_15, 0x87 }, 135 { LP8860_EEPROM_REG_16, 0xce }, 136 { LP8860_EEPROM_REG_17, 0x72 }, 137 { LP8860_EEPROM_REG_18, 0xe5 }, 138 { LP8860_EEPROM_REG_19, 0xdf }, 139 { LP8860_EEPROM_REG_20, 0x35 }, 140 { LP8860_EEPROM_REG_21, 0x06 }, 141 { LP8860_EEPROM_REG_22, 0xdc }, 142 { LP8860_EEPROM_REG_23, 0x88 }, 143 { LP8860_EEPROM_REG_24, 0x3E }, 144 }; 145 146 static int lp8860_unlock_eeprom(struct lp8860_led *led, int lock) 147 { 148 int ret; 149 150 mutex_lock(&led->lock); 151 152 if (lock == LP8860_UNLOCK_EEPROM) { 153 ret = regmap_write(led->regmap, 154 LP8860_EEPROM_UNLOCK, 155 LP8860_EEPROM_CODE_1); 156 if (ret) { 157 dev_err(&led->client->dev, "EEPROM Unlock failed\n"); 158 goto out; 159 } 160 161 ret = regmap_write(led->regmap, 162 LP8860_EEPROM_UNLOCK, 163 LP8860_EEPROM_CODE_2); 164 if (ret) { 165 dev_err(&led->client->dev, "EEPROM Unlock failed\n"); 166 goto out; 167 } 168 ret = regmap_write(led->regmap, 169 LP8860_EEPROM_UNLOCK, 170 LP8860_EEPROM_CODE_3); 171 if (ret) { 172 dev_err(&led->client->dev, "EEPROM Unlock failed\n"); 173 goto out; 174 } 175 } else { 176 ret = regmap_write(led->regmap, 177 LP8860_EEPROM_UNLOCK, 178 LP8860_LOCK_EEPROM); 179 } 180 181 out: 182 mutex_unlock(&led->lock); 183 return ret; 184 } 185 186 static int lp8860_fault_check(struct lp8860_led *led) 187 { 188 int ret, fault; 189 unsigned int read_buf; 190 191 ret = regmap_read(led->regmap, LP8860_LED_FAULT, &read_buf); 192 if (ret) 193 goto out; 194 195 fault = read_buf; 196 197 ret = regmap_read(led->regmap, LP8860_FAULT, &read_buf); 198 if (ret) 199 goto out; 200 201 fault |= read_buf; 202 203 /* Attempt to clear any faults */ 204 if (fault) 205 ret = regmap_write(led->regmap, LP8860_FAULT_CLEAR, 206 LP8860_CLEAR_FAULTS); 207 out: 208 return ret; 209 } 210 211 static int lp8860_brightness_set(struct led_classdev *led_cdev, 212 enum led_brightness brt_val) 213 { 214 struct lp8860_led *led = 215 container_of(led_cdev, struct lp8860_led, led_dev); 216 int disp_brightness = brt_val * 255; 217 int ret; 218 219 mutex_lock(&led->lock); 220 221 ret = lp8860_fault_check(led); 222 if (ret) { 223 dev_err(&led->client->dev, "Cannot read/clear faults\n"); 224 goto out; 225 } 226 227 ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_MSB, 228 (disp_brightness & 0xff00) >> 8); 229 if (ret) { 230 dev_err(&led->client->dev, "Cannot write CL1 MSB\n"); 231 goto out; 232 } 233 234 ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_LSB, 235 disp_brightness & 0xff); 236 if (ret) { 237 dev_err(&led->client->dev, "Cannot write CL1 LSB\n"); 238 goto out; 239 } 240 out: 241 mutex_unlock(&led->lock); 242 return ret; 243 } 244 245 static int lp8860_init(struct lp8860_led *led) 246 { 247 unsigned int read_buf; 248 int ret, i, reg_count; 249 250 if (led->enable_gpio) 251 gpiod_direction_output(led->enable_gpio, 1); 252 253 ret = lp8860_fault_check(led); 254 if (ret) 255 goto out; 256 257 ret = regmap_read(led->regmap, LP8860_STATUS, &read_buf); 258 if (ret) 259 goto out; 260 261 ret = lp8860_unlock_eeprom(led, LP8860_UNLOCK_EEPROM); 262 if (ret) { 263 dev_err(&led->client->dev, "Failed unlocking EEPROM\n"); 264 goto out; 265 } 266 267 reg_count = ARRAY_SIZE(lp8860_eeprom_disp_regs) / sizeof(lp8860_eeprom_disp_regs[0]); 268 for (i = 0; i < reg_count; i++) { 269 ret = regmap_write(led->eeprom_regmap, 270 lp8860_eeprom_disp_regs[i].reg, 271 lp8860_eeprom_disp_regs[i].value); 272 if (ret) { 273 dev_err(&led->client->dev, "Failed writing EEPROM\n"); 274 goto out; 275 } 276 } 277 278 ret = lp8860_unlock_eeprom(led, LP8860_LOCK_EEPROM); 279 if (ret) 280 goto out; 281 282 ret = regmap_write(led->regmap, 283 LP8860_EEPROM_CNTRL, 284 LP8860_PROGRAM_EEPROM); 285 if (ret) 286 dev_err(&led->client->dev, "Failed programming EEPROM\n"); 287 out: 288 if (ret) 289 if (led->enable_gpio) 290 gpiod_direction_output(led->enable_gpio, 0); 291 return ret; 292 } 293 294 static const struct reg_default lp8860_reg_defs[] = { 295 { LP8860_DISP_CL1_BRT_MSB, 0x00}, 296 { LP8860_DISP_CL1_BRT_LSB, 0x00}, 297 { LP8860_DISP_CL1_CURR_MSB, 0x00}, 298 { LP8860_DISP_CL1_CURR_LSB, 0x00}, 299 { LP8860_CL2_BRT_MSB, 0x00}, 300 { LP8860_CL2_BRT_LSB, 0x00}, 301 { LP8860_CL2_CURRENT, 0x00}, 302 { LP8860_CL3_BRT_MSB, 0x00}, 303 { LP8860_CL3_BRT_LSB, 0x00}, 304 { LP8860_CL3_CURRENT, 0x00}, 305 { LP8860_CL4_BRT_MSB, 0x00}, 306 { LP8860_CL4_BRT_LSB, 0x00}, 307 { LP8860_CL4_CURRENT, 0x00}, 308 { LP8860_CONFIG, 0x00}, 309 { LP8860_FAULT_CLEAR, 0x00}, 310 { LP8860_EEPROM_CNTRL, 0x80}, 311 { LP8860_EEPROM_UNLOCK, 0x00}, 312 }; 313 314 static const struct regmap_config lp8860_regmap_config = { 315 .reg_bits = 8, 316 .val_bits = 8, 317 318 .max_register = LP8860_EEPROM_UNLOCK, 319 .reg_defaults = lp8860_reg_defs, 320 .num_reg_defaults = ARRAY_SIZE(lp8860_reg_defs), 321 .cache_type = REGCACHE_NONE, 322 }; 323 324 static const struct reg_default lp8860_eeprom_defs[] = { 325 { LP8860_EEPROM_REG_0, 0x00 }, 326 { LP8860_EEPROM_REG_1, 0x00 }, 327 { LP8860_EEPROM_REG_2, 0x00 }, 328 { LP8860_EEPROM_REG_3, 0x00 }, 329 { LP8860_EEPROM_REG_4, 0x00 }, 330 { LP8860_EEPROM_REG_5, 0x00 }, 331 { LP8860_EEPROM_REG_6, 0x00 }, 332 { LP8860_EEPROM_REG_7, 0x00 }, 333 { LP8860_EEPROM_REG_8, 0x00 }, 334 { LP8860_EEPROM_REG_9, 0x00 }, 335 { LP8860_EEPROM_REG_10, 0x00 }, 336 { LP8860_EEPROM_REG_11, 0x00 }, 337 { LP8860_EEPROM_REG_12, 0x00 }, 338 { LP8860_EEPROM_REG_13, 0x00 }, 339 { LP8860_EEPROM_REG_14, 0x00 }, 340 { LP8860_EEPROM_REG_15, 0x00 }, 341 { LP8860_EEPROM_REG_16, 0x00 }, 342 { LP8860_EEPROM_REG_17, 0x00 }, 343 { LP8860_EEPROM_REG_18, 0x00 }, 344 { LP8860_EEPROM_REG_19, 0x00 }, 345 { LP8860_EEPROM_REG_20, 0x00 }, 346 { LP8860_EEPROM_REG_21, 0x00 }, 347 { LP8860_EEPROM_REG_22, 0x00 }, 348 { LP8860_EEPROM_REG_23, 0x00 }, 349 { LP8860_EEPROM_REG_24, 0x00 }, 350 }; 351 352 static const struct regmap_config lp8860_eeprom_regmap_config = { 353 .reg_bits = 8, 354 .val_bits = 8, 355 356 .max_register = LP8860_EEPROM_REG_24, 357 .reg_defaults = lp8860_eeprom_defs, 358 .num_reg_defaults = ARRAY_SIZE(lp8860_eeprom_defs), 359 .cache_type = REGCACHE_NONE, 360 }; 361 362 static int lp8860_probe(struct i2c_client *client, 363 const struct i2c_device_id *id) 364 { 365 int ret; 366 struct lp8860_led *led; 367 struct device_node *np = client->dev.of_node; 368 369 led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); 370 if (!led) 371 return -ENOMEM; 372 373 led->label = LP8860_DISP_LED_NAME; 374 375 if (client->dev.of_node) { 376 ret = of_property_read_string(np, "label", &led->label); 377 if (ret) { 378 dev_err(&client->dev, "Missing label in dt\n"); 379 return -EINVAL; 380 } 381 } 382 383 led->enable_gpio = devm_gpiod_get_optional(&client->dev, 384 "enable", GPIOD_OUT_LOW); 385 if (IS_ERR(led->enable_gpio)) { 386 ret = PTR_ERR(led->enable_gpio); 387 dev_err(&client->dev, "Failed to get enable gpio: %d\n", ret); 388 return ret; 389 } 390 391 led->regulator = devm_regulator_get(&client->dev, "vled"); 392 if (IS_ERR(led->regulator)) 393 led->regulator = NULL; 394 395 led->client = client; 396 led->led_dev.name = led->label; 397 led->led_dev.max_brightness = LED_FULL; 398 led->led_dev.brightness_set_blocking = lp8860_brightness_set; 399 400 mutex_init(&led->lock); 401 402 i2c_set_clientdata(client, led); 403 404 led->regmap = devm_regmap_init_i2c(client, &lp8860_regmap_config); 405 if (IS_ERR(led->regmap)) { 406 ret = PTR_ERR(led->regmap); 407 dev_err(&client->dev, "Failed to allocate register map: %d\n", 408 ret); 409 return ret; 410 } 411 412 led->eeprom_regmap = devm_regmap_init_i2c(client, &lp8860_eeprom_regmap_config); 413 if (IS_ERR(led->eeprom_regmap)) { 414 ret = PTR_ERR(led->eeprom_regmap); 415 dev_err(&client->dev, "Failed to allocate register map: %d\n", 416 ret); 417 return ret; 418 } 419 420 ret = lp8860_init(led); 421 if (ret) 422 return ret; 423 424 ret = led_classdev_register(&client->dev, &led->led_dev); 425 if (ret) { 426 dev_err(&client->dev, "led register err: %d\n", ret); 427 return ret; 428 } 429 430 return 0; 431 } 432 433 static int lp8860_remove(struct i2c_client *client) 434 { 435 struct lp8860_led *led = i2c_get_clientdata(client); 436 int ret; 437 438 led_classdev_unregister(&led->led_dev); 439 440 if (led->enable_gpio) 441 gpiod_direction_output(led->enable_gpio, 0); 442 443 if (led->regulator) { 444 ret = regulator_disable(led->regulator); 445 if (ret) 446 dev_err(&led->client->dev, 447 "Failed to disable regulator\n"); 448 } 449 450 return 0; 451 } 452 453 static const struct i2c_device_id lp8860_id[] = { 454 { "lp8860", 0 }, 455 { } 456 }; 457 MODULE_DEVICE_TABLE(i2c, lp8860_id); 458 459 #ifdef CONFIG_OF 460 static const struct of_device_id of_lp8860_leds_match[] = { 461 { .compatible = "ti,lp8860", }, 462 {}, 463 }; 464 MODULE_DEVICE_TABLE(of, of_lp8860_leds_match); 465 #endif 466 467 static struct i2c_driver lp8860_driver = { 468 .driver = { 469 .name = "lp8860", 470 .of_match_table = of_match_ptr(of_lp8860_leds_match), 471 }, 472 .probe = lp8860_probe, 473 .remove = lp8860_remove, 474 .id_table = lp8860_id, 475 }; 476 module_i2c_driver(lp8860_driver); 477 478 MODULE_DESCRIPTION("Texas Instruments LP8860 LED driver"); 479 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 480 MODULE_LICENSE("GPL"); 481