Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * TI LP8860 4-Channel LED Driver
0004  *
0005  * Copyright (C) 2014 Texas Instruments
0006  *
0007  * Author: Dan Murphy <dmurphy@ti.com>
0008  */
0009 
0010 #include <linux/i2c.h>
0011 #include <linux/init.h>
0012 #include <linux/leds.h>
0013 #include <linux/regmap.h>
0014 #include <linux/regulator/consumer.h>
0015 #include <linux/module.h>
0016 #include <linux/mutex.h>
0017 #include <linux/of.h>
0018 #include <linux/of_gpio.h>
0019 #include <linux/gpio/consumer.h>
0020 #include <linux/slab.h>
0021 
0022 #define LP8860_DISP_CL1_BRT_MSB     0x00
0023 #define LP8860_DISP_CL1_BRT_LSB     0x01
0024 #define LP8860_DISP_CL1_CURR_MSB    0x02
0025 #define LP8860_DISP_CL1_CURR_LSB    0x03
0026 #define LP8860_CL2_BRT_MSB      0x04
0027 #define LP8860_CL2_BRT_LSB      0x05
0028 #define LP8860_CL2_CURRENT      0x06
0029 #define LP8860_CL3_BRT_MSB      0x07
0030 #define LP8860_CL3_BRT_LSB      0x08
0031 #define LP8860_CL3_CURRENT      0x09
0032 #define LP8860_CL4_BRT_MSB      0x0a
0033 #define LP8860_CL4_BRT_LSB      0x0b
0034 #define LP8860_CL4_CURRENT      0x0c
0035 #define LP8860_CONFIG           0x0d
0036 #define LP8860_STATUS           0x0e
0037 #define LP8860_FAULT            0x0f
0038 #define LP8860_LED_FAULT        0x10
0039 #define LP8860_FAULT_CLEAR      0x11
0040 #define LP8860_ID           0x12
0041 #define LP8860_TEMP_MSB         0x13
0042 #define LP8860_TEMP_LSB         0x14
0043 #define LP8860_DISP_LED_CURR_MSB    0x15
0044 #define LP8860_DISP_LED_CURR_LSB    0x16
0045 #define LP8860_DISP_LED_PWM_MSB     0x17
0046 #define LP8860_DISP_LED_PWM_LSB     0x18
0047 #define LP8860_EEPROM_CNTRL     0x19
0048 #define LP8860_EEPROM_UNLOCK        0x1a
0049 
0050 #define LP8860_EEPROM_REG_0     0x60
0051 #define LP8860_EEPROM_REG_1     0x61
0052 #define LP8860_EEPROM_REG_2     0x62
0053 #define LP8860_EEPROM_REG_3     0x63
0054 #define LP8860_EEPROM_REG_4     0x64
0055 #define LP8860_EEPROM_REG_5     0x65
0056 #define LP8860_EEPROM_REG_6     0x66
0057 #define LP8860_EEPROM_REG_7     0x67
0058 #define LP8860_EEPROM_REG_8     0x68
0059 #define LP8860_EEPROM_REG_9     0x69
0060 #define LP8860_EEPROM_REG_10        0x6a
0061 #define LP8860_EEPROM_REG_11        0x6b
0062 #define LP8860_EEPROM_REG_12        0x6c
0063 #define LP8860_EEPROM_REG_13        0x6d
0064 #define LP8860_EEPROM_REG_14        0x6e
0065 #define LP8860_EEPROM_REG_15        0x6f
0066 #define LP8860_EEPROM_REG_16        0x70
0067 #define LP8860_EEPROM_REG_17        0x71
0068 #define LP8860_EEPROM_REG_18        0x72
0069 #define LP8860_EEPROM_REG_19        0x73
0070 #define LP8860_EEPROM_REG_20        0x74
0071 #define LP8860_EEPROM_REG_21        0x75
0072 #define LP8860_EEPROM_REG_22        0x76
0073 #define LP8860_EEPROM_REG_23        0x77
0074 #define LP8860_EEPROM_REG_24        0x78
0075 
0076 #define LP8860_LOCK_EEPROM      0x00
0077 #define LP8860_UNLOCK_EEPROM        0x01
0078 #define LP8860_PROGRAM_EEPROM       0x02
0079 #define LP8860_EEPROM_CODE_1        0x08
0080 #define LP8860_EEPROM_CODE_2        0xba
0081 #define LP8860_EEPROM_CODE_3        0xef
0082 
0083 #define LP8860_CLEAR_FAULTS     0x01
0084 
0085 #define LP8860_NAME         "lp8860"
0086 
0087 /**
0088  * struct lp8860_led
0089  * @lock: Lock for reading/writing the device
0090  * @client: Pointer to the I2C client
0091  * @led_dev: led class device pointer
0092  * @regmap: Devices register map
0093  * @eeprom_regmap: EEPROM register map
0094  * @enable_gpio: VDDIO/EN gpio to enable communication interface
0095  * @regulator: LED supply regulator pointer
0096  */
0097 struct lp8860_led {
0098     struct mutex lock;
0099     struct i2c_client *client;
0100     struct led_classdev led_dev;
0101     struct regmap *regmap;
0102     struct regmap *eeprom_regmap;
0103     struct gpio_desc *enable_gpio;
0104     struct regulator *regulator;
0105 };
0106 
0107 struct lp8860_eeprom_reg {
0108     uint8_t reg;
0109     uint8_t value;
0110 };
0111 
0112 static struct lp8860_eeprom_reg lp8860_eeprom_disp_regs[] = {
0113     { LP8860_EEPROM_REG_0, 0xed },
0114     { LP8860_EEPROM_REG_1, 0xdf },
0115     { LP8860_EEPROM_REG_2, 0xdc },
0116     { LP8860_EEPROM_REG_3, 0xf0 },
0117     { LP8860_EEPROM_REG_4, 0xdf },
0118     { LP8860_EEPROM_REG_5, 0xe5 },
0119     { LP8860_EEPROM_REG_6, 0xf2 },
0120     { LP8860_EEPROM_REG_7, 0x77 },
0121     { LP8860_EEPROM_REG_8, 0x77 },
0122     { LP8860_EEPROM_REG_9, 0x71 },
0123     { LP8860_EEPROM_REG_10, 0x3f },
0124     { LP8860_EEPROM_REG_11, 0xb7 },
0125     { LP8860_EEPROM_REG_12, 0x17 },
0126     { LP8860_EEPROM_REG_13, 0xef },
0127     { LP8860_EEPROM_REG_14, 0xb0 },
0128     { LP8860_EEPROM_REG_15, 0x87 },
0129     { LP8860_EEPROM_REG_16, 0xce },
0130     { LP8860_EEPROM_REG_17, 0x72 },
0131     { LP8860_EEPROM_REG_18, 0xe5 },
0132     { LP8860_EEPROM_REG_19, 0xdf },
0133     { LP8860_EEPROM_REG_20, 0x35 },
0134     { LP8860_EEPROM_REG_21, 0x06 },
0135     { LP8860_EEPROM_REG_22, 0xdc },
0136     { LP8860_EEPROM_REG_23, 0x88 },
0137     { LP8860_EEPROM_REG_24, 0x3E },
0138 };
0139 
0140 static int lp8860_unlock_eeprom(struct lp8860_led *led, int lock)
0141 {
0142     int ret;
0143 
0144     mutex_lock(&led->lock);
0145 
0146     if (lock == LP8860_UNLOCK_EEPROM) {
0147         ret = regmap_write(led->regmap,
0148             LP8860_EEPROM_UNLOCK,
0149             LP8860_EEPROM_CODE_1);
0150         if (ret) {
0151             dev_err(&led->client->dev, "EEPROM Unlock failed\n");
0152             goto out;
0153         }
0154 
0155         ret = regmap_write(led->regmap,
0156             LP8860_EEPROM_UNLOCK,
0157             LP8860_EEPROM_CODE_2);
0158         if (ret) {
0159             dev_err(&led->client->dev, "EEPROM Unlock failed\n");
0160             goto out;
0161         }
0162         ret = regmap_write(led->regmap,
0163             LP8860_EEPROM_UNLOCK,
0164             LP8860_EEPROM_CODE_3);
0165         if (ret) {
0166             dev_err(&led->client->dev, "EEPROM Unlock failed\n");
0167             goto out;
0168         }
0169     } else {
0170         ret = regmap_write(led->regmap,
0171             LP8860_EEPROM_UNLOCK,
0172             LP8860_LOCK_EEPROM);
0173     }
0174 
0175 out:
0176     mutex_unlock(&led->lock);
0177     return ret;
0178 }
0179 
0180 static int lp8860_fault_check(struct lp8860_led *led)
0181 {
0182     int ret, fault;
0183     unsigned int read_buf;
0184 
0185     ret = regmap_read(led->regmap, LP8860_LED_FAULT, &read_buf);
0186     if (ret)
0187         goto out;
0188 
0189     fault = read_buf;
0190 
0191     ret = regmap_read(led->regmap, LP8860_FAULT, &read_buf);
0192     if (ret)
0193         goto out;
0194 
0195     fault |= read_buf;
0196 
0197     /* Attempt to clear any faults */
0198     if (fault)
0199         ret = regmap_write(led->regmap, LP8860_FAULT_CLEAR,
0200             LP8860_CLEAR_FAULTS);
0201 out:
0202     return ret;
0203 }
0204 
0205 static int lp8860_brightness_set(struct led_classdev *led_cdev,
0206                 enum led_brightness brt_val)
0207 {
0208     struct lp8860_led *led =
0209             container_of(led_cdev, struct lp8860_led, led_dev);
0210     int disp_brightness = brt_val * 255;
0211     int ret;
0212 
0213     mutex_lock(&led->lock);
0214 
0215     ret = lp8860_fault_check(led);
0216     if (ret) {
0217         dev_err(&led->client->dev, "Cannot read/clear faults\n");
0218         goto out;
0219     }
0220 
0221     ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_MSB,
0222             (disp_brightness & 0xff00) >> 8);
0223     if (ret) {
0224         dev_err(&led->client->dev, "Cannot write CL1 MSB\n");
0225         goto out;
0226     }
0227 
0228     ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_LSB,
0229             disp_brightness & 0xff);
0230     if (ret) {
0231         dev_err(&led->client->dev, "Cannot write CL1 LSB\n");
0232         goto out;
0233     }
0234 out:
0235     mutex_unlock(&led->lock);
0236     return ret;
0237 }
0238 
0239 static int lp8860_init(struct lp8860_led *led)
0240 {
0241     unsigned int read_buf;
0242     int ret, i, reg_count;
0243 
0244     if (led->regulator) {
0245         ret = regulator_enable(led->regulator);
0246         if (ret) {
0247             dev_err(&led->client->dev,
0248                 "Failed to enable regulator\n");
0249             return ret;
0250         }
0251     }
0252 
0253     if (led->enable_gpio)
0254         gpiod_direction_output(led->enable_gpio, 1);
0255 
0256     ret = lp8860_fault_check(led);
0257     if (ret)
0258         goto out;
0259 
0260     ret = regmap_read(led->regmap, LP8860_STATUS, &read_buf);
0261     if (ret)
0262         goto out;
0263 
0264     ret = lp8860_unlock_eeprom(led, LP8860_UNLOCK_EEPROM);
0265     if (ret) {
0266         dev_err(&led->client->dev, "Failed unlocking EEPROM\n");
0267         goto out;
0268     }
0269 
0270     reg_count = ARRAY_SIZE(lp8860_eeprom_disp_regs) / sizeof(lp8860_eeprom_disp_regs[0]);
0271     for (i = 0; i < reg_count; i++) {
0272         ret = regmap_write(led->eeprom_regmap,
0273                 lp8860_eeprom_disp_regs[i].reg,
0274                 lp8860_eeprom_disp_regs[i].value);
0275         if (ret) {
0276             dev_err(&led->client->dev, "Failed writing EEPROM\n");
0277             goto out;
0278         }
0279     }
0280 
0281     ret = lp8860_unlock_eeprom(led, LP8860_LOCK_EEPROM);
0282     if (ret)
0283         goto out;
0284 
0285     ret = regmap_write(led->regmap,
0286             LP8860_EEPROM_CNTRL,
0287             LP8860_PROGRAM_EEPROM);
0288     if (ret) {
0289         dev_err(&led->client->dev, "Failed programming EEPROM\n");
0290         goto out;
0291     }
0292 
0293     return ret;
0294 
0295 out:
0296     if (ret)
0297         if (led->enable_gpio)
0298             gpiod_direction_output(led->enable_gpio, 0);
0299 
0300     if (led->regulator) {
0301         ret = regulator_disable(led->regulator);
0302         if (ret)
0303             dev_err(&led->client->dev,
0304                 "Failed to disable regulator\n");
0305     }
0306 
0307     return ret;
0308 }
0309 
0310 static const struct reg_default lp8860_reg_defs[] = {
0311     { LP8860_DISP_CL1_BRT_MSB, 0x00},
0312     { LP8860_DISP_CL1_BRT_LSB, 0x00},
0313     { LP8860_DISP_CL1_CURR_MSB, 0x00},
0314     { LP8860_DISP_CL1_CURR_LSB, 0x00},
0315     { LP8860_CL2_BRT_MSB, 0x00},
0316     { LP8860_CL2_BRT_LSB, 0x00},
0317     { LP8860_CL2_CURRENT, 0x00},
0318     { LP8860_CL3_BRT_MSB, 0x00},
0319     { LP8860_CL3_BRT_LSB, 0x00},
0320     { LP8860_CL3_CURRENT, 0x00},
0321     { LP8860_CL4_BRT_MSB, 0x00},
0322     { LP8860_CL4_BRT_LSB, 0x00},
0323     { LP8860_CL4_CURRENT, 0x00},
0324     { LP8860_CONFIG, 0x00},
0325     { LP8860_FAULT_CLEAR, 0x00},
0326     { LP8860_EEPROM_CNTRL, 0x80},
0327     { LP8860_EEPROM_UNLOCK, 0x00},
0328 };
0329 
0330 static const struct regmap_config lp8860_regmap_config = {
0331     .reg_bits = 8,
0332     .val_bits = 8,
0333 
0334     .max_register = LP8860_EEPROM_UNLOCK,
0335     .reg_defaults = lp8860_reg_defs,
0336     .num_reg_defaults = ARRAY_SIZE(lp8860_reg_defs),
0337     .cache_type = REGCACHE_NONE,
0338 };
0339 
0340 static const struct reg_default lp8860_eeprom_defs[] = {
0341     { LP8860_EEPROM_REG_0, 0x00 },
0342     { LP8860_EEPROM_REG_1, 0x00 },
0343     { LP8860_EEPROM_REG_2, 0x00 },
0344     { LP8860_EEPROM_REG_3, 0x00 },
0345     { LP8860_EEPROM_REG_4, 0x00 },
0346     { LP8860_EEPROM_REG_5, 0x00 },
0347     { LP8860_EEPROM_REG_6, 0x00 },
0348     { LP8860_EEPROM_REG_7, 0x00 },
0349     { LP8860_EEPROM_REG_8, 0x00 },
0350     { LP8860_EEPROM_REG_9, 0x00 },
0351     { LP8860_EEPROM_REG_10, 0x00 },
0352     { LP8860_EEPROM_REG_11, 0x00 },
0353     { LP8860_EEPROM_REG_12, 0x00 },
0354     { LP8860_EEPROM_REG_13, 0x00 },
0355     { LP8860_EEPROM_REG_14, 0x00 },
0356     { LP8860_EEPROM_REG_15, 0x00 },
0357     { LP8860_EEPROM_REG_16, 0x00 },
0358     { LP8860_EEPROM_REG_17, 0x00 },
0359     { LP8860_EEPROM_REG_18, 0x00 },
0360     { LP8860_EEPROM_REG_19, 0x00 },
0361     { LP8860_EEPROM_REG_20, 0x00 },
0362     { LP8860_EEPROM_REG_21, 0x00 },
0363     { LP8860_EEPROM_REG_22, 0x00 },
0364     { LP8860_EEPROM_REG_23, 0x00 },
0365     { LP8860_EEPROM_REG_24, 0x00 },
0366 };
0367 
0368 static const struct regmap_config lp8860_eeprom_regmap_config = {
0369     .reg_bits = 8,
0370     .val_bits = 8,
0371 
0372     .max_register = LP8860_EEPROM_REG_24,
0373     .reg_defaults = lp8860_eeprom_defs,
0374     .num_reg_defaults = ARRAY_SIZE(lp8860_eeprom_defs),
0375     .cache_type = REGCACHE_NONE,
0376 };
0377 
0378 static int lp8860_probe(struct i2c_client *client,
0379             const struct i2c_device_id *id)
0380 {
0381     int ret;
0382     struct lp8860_led *led;
0383     struct device_node *np = dev_of_node(&client->dev);
0384     struct device_node *child_node;
0385     struct led_init_data init_data = {};
0386 
0387     led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
0388     if (!led)
0389         return -ENOMEM;
0390 
0391     child_node = of_get_next_available_child(np, NULL);
0392     if (!child_node)
0393         return -EINVAL;
0394 
0395     led->enable_gpio = devm_gpiod_get_optional(&client->dev,
0396                            "enable", GPIOD_OUT_LOW);
0397     if (IS_ERR(led->enable_gpio)) {
0398         ret = PTR_ERR(led->enable_gpio);
0399         dev_err(&client->dev, "Failed to get enable gpio: %d\n", ret);
0400         return ret;
0401     }
0402 
0403     led->regulator = devm_regulator_get(&client->dev, "vled");
0404     if (IS_ERR(led->regulator))
0405         led->regulator = NULL;
0406 
0407     led->client = client;
0408     led->led_dev.brightness_set_blocking = lp8860_brightness_set;
0409 
0410     mutex_init(&led->lock);
0411 
0412     i2c_set_clientdata(client, led);
0413 
0414     led->regmap = devm_regmap_init_i2c(client, &lp8860_regmap_config);
0415     if (IS_ERR(led->regmap)) {
0416         ret = PTR_ERR(led->regmap);
0417         dev_err(&client->dev, "Failed to allocate register map: %d\n",
0418             ret);
0419         return ret;
0420     }
0421 
0422     led->eeprom_regmap = devm_regmap_init_i2c(client, &lp8860_eeprom_regmap_config);
0423     if (IS_ERR(led->eeprom_regmap)) {
0424         ret = PTR_ERR(led->eeprom_regmap);
0425         dev_err(&client->dev, "Failed to allocate register map: %d\n",
0426             ret);
0427         return ret;
0428     }
0429 
0430     ret = lp8860_init(led);
0431     if (ret)
0432         return ret;
0433 
0434     init_data.fwnode = of_fwnode_handle(child_node);
0435     init_data.devicename = LP8860_NAME;
0436     init_data.default_label = ":display_cluster";
0437 
0438     ret = devm_led_classdev_register_ext(&client->dev, &led->led_dev,
0439                          &init_data);
0440     if (ret) {
0441         dev_err(&client->dev, "led register err: %d\n", ret);
0442         return ret;
0443     }
0444 
0445     return 0;
0446 }
0447 
0448 static int lp8860_remove(struct i2c_client *client)
0449 {
0450     struct lp8860_led *led = i2c_get_clientdata(client);
0451     int ret;
0452 
0453     if (led->enable_gpio)
0454         gpiod_direction_output(led->enable_gpio, 0);
0455 
0456     if (led->regulator) {
0457         ret = regulator_disable(led->regulator);
0458         if (ret)
0459             dev_err(&led->client->dev,
0460                 "Failed to disable regulator\n");
0461     }
0462 
0463     mutex_destroy(&led->lock);
0464 
0465     return 0;
0466 }
0467 
0468 static const struct i2c_device_id lp8860_id[] = {
0469     { "lp8860", 0 },
0470     { }
0471 };
0472 MODULE_DEVICE_TABLE(i2c, lp8860_id);
0473 
0474 static const struct of_device_id of_lp8860_leds_match[] = {
0475     { .compatible = "ti,lp8860", },
0476     {},
0477 };
0478 MODULE_DEVICE_TABLE(of, of_lp8860_leds_match);
0479 
0480 static struct i2c_driver lp8860_driver = {
0481     .driver = {
0482         .name   = "lp8860",
0483         .of_match_table = of_lp8860_leds_match,
0484     },
0485     .probe      = lp8860_probe,
0486     .remove     = lp8860_remove,
0487     .id_table   = lp8860_id,
0488 };
0489 module_i2c_driver(lp8860_driver);
0490 
0491 MODULE_DESCRIPTION("Texas Instruments LP8860 LED driver");
0492 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
0493 MODULE_LICENSE("GPL v2");