root/drivers/leds/leds-lp8860.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lp8860_unlock_eeprom
  2. lp8860_fault_check
  3. lp8860_brightness_set
  4. lp8860_init
  5. lp8860_probe
  6. lp8860_remove

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

/* [<][>][^][v][top][bottom][index][help] */