0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/delay.h>
0011 #include <linux/firmware.h>
0012 #include <linux/i2c.h>
0013 #include <linux/leds.h>
0014 #include <linux/module.h>
0015 #include <linux/mutex.h>
0016 #include <linux/of.h>
0017 #include <linux/platform_data/leds-lp55xx.h>
0018 #include <linux/slab.h>
0019
0020 #include "leds-lp55xx-common.h"
0021
0022 #define LP5562_PROGRAM_LENGTH 32
0023 #define LP5562_MAX_LEDS 4
0024
0025
0026 #define LP5562_REG_ENABLE 0x00
0027 #define LP5562_EXEC_ENG1_M 0x30
0028 #define LP5562_EXEC_ENG2_M 0x0C
0029 #define LP5562_EXEC_ENG3_M 0x03
0030 #define LP5562_EXEC_M 0x3F
0031 #define LP5562_MASTER_ENABLE 0x40
0032 #define LP5562_LOGARITHMIC_PWM 0x80
0033 #define LP5562_EXEC_RUN 0x2A
0034 #define LP5562_ENABLE_DEFAULT \
0035 (LP5562_MASTER_ENABLE | LP5562_LOGARITHMIC_PWM)
0036 #define LP5562_ENABLE_RUN_PROGRAM \
0037 (LP5562_ENABLE_DEFAULT | LP5562_EXEC_RUN)
0038
0039
0040 #define LP5562_REG_OP_MODE 0x01
0041 #define LP5562_MODE_ENG1_M 0x30
0042 #define LP5562_MODE_ENG2_M 0x0C
0043 #define LP5562_MODE_ENG3_M 0x03
0044 #define LP5562_LOAD_ENG1 0x10
0045 #define LP5562_LOAD_ENG2 0x04
0046 #define LP5562_LOAD_ENG3 0x01
0047 #define LP5562_RUN_ENG1 0x20
0048 #define LP5562_RUN_ENG2 0x08
0049 #define LP5562_RUN_ENG3 0x02
0050 #define LP5562_ENG1_IS_LOADING(mode) \
0051 ((mode & LP5562_MODE_ENG1_M) == LP5562_LOAD_ENG1)
0052 #define LP5562_ENG2_IS_LOADING(mode) \
0053 ((mode & LP5562_MODE_ENG2_M) == LP5562_LOAD_ENG2)
0054 #define LP5562_ENG3_IS_LOADING(mode) \
0055 ((mode & LP5562_MODE_ENG3_M) == LP5562_LOAD_ENG3)
0056
0057
0058 #define LP5562_REG_R_PWM 0x04
0059 #define LP5562_REG_G_PWM 0x03
0060 #define LP5562_REG_B_PWM 0x02
0061 #define LP5562_REG_W_PWM 0x0E
0062
0063
0064 #define LP5562_REG_R_CURRENT 0x07
0065 #define LP5562_REG_G_CURRENT 0x06
0066 #define LP5562_REG_B_CURRENT 0x05
0067 #define LP5562_REG_W_CURRENT 0x0F
0068
0069
0070 #define LP5562_REG_CONFIG 0x08
0071 #define LP5562_PWM_HF 0x40
0072 #define LP5562_PWRSAVE_EN 0x20
0073 #define LP5562_CLK_INT 0x01
0074 #define LP5562_DEFAULT_CFG (LP5562_PWM_HF | LP5562_PWRSAVE_EN)
0075
0076
0077 #define LP5562_REG_RESET 0x0D
0078 #define LP5562_RESET 0xFF
0079
0080
0081 #define LP5562_REG_PROG_MEM_ENG1 0x10
0082 #define LP5562_REG_PROG_MEM_ENG2 0x30
0083 #define LP5562_REG_PROG_MEM_ENG3 0x50
0084
0085
0086 #define LP5562_REG_ENG_SEL 0x70
0087 #define LP5562_ENG_SEL_PWM 0
0088 #define LP5562_ENG_FOR_RGB_M 0x3F
0089 #define LP5562_ENG_SEL_RGB 0x1B
0090 #define LP5562_ENG_FOR_W_M 0xC0
0091 #define LP5562_ENG1_FOR_W 0x40
0092 #define LP5562_ENG2_FOR_W 0x80
0093 #define LP5562_ENG3_FOR_W 0xC0
0094
0095
0096 #define LP5562_CMD_DISABLE 0x00
0097 #define LP5562_CMD_LOAD 0x15
0098 #define LP5562_CMD_RUN 0x2A
0099 #define LP5562_CMD_DIRECT 0x3F
0100 #define LP5562_PATTERN_OFF 0
0101
0102 static inline void lp5562_wait_opmode_done(void)
0103 {
0104
0105 usleep_range(200, 300);
0106 }
0107
0108 static inline void lp5562_wait_enable_done(void)
0109 {
0110
0111 usleep_range(500, 600);
0112 }
0113
0114 static void lp5562_set_led_current(struct lp55xx_led *led, u8 led_current)
0115 {
0116 static const u8 addr[] = {
0117 LP5562_REG_R_CURRENT,
0118 LP5562_REG_G_CURRENT,
0119 LP5562_REG_B_CURRENT,
0120 LP5562_REG_W_CURRENT,
0121 };
0122
0123 led->led_current = led_current;
0124 lp55xx_write(led->chip, addr[led->chan_nr], led_current);
0125 }
0126
0127 static void lp5562_load_engine(struct lp55xx_chip *chip)
0128 {
0129 enum lp55xx_engine_index idx = chip->engine_idx;
0130 static const u8 mask[] = {
0131 [LP55XX_ENGINE_1] = LP5562_MODE_ENG1_M,
0132 [LP55XX_ENGINE_2] = LP5562_MODE_ENG2_M,
0133 [LP55XX_ENGINE_3] = LP5562_MODE_ENG3_M,
0134 };
0135
0136 static const u8 val[] = {
0137 [LP55XX_ENGINE_1] = LP5562_LOAD_ENG1,
0138 [LP55XX_ENGINE_2] = LP5562_LOAD_ENG2,
0139 [LP55XX_ENGINE_3] = LP5562_LOAD_ENG3,
0140 };
0141
0142 lp55xx_update_bits(chip, LP5562_REG_OP_MODE, mask[idx], val[idx]);
0143
0144 lp5562_wait_opmode_done();
0145 }
0146
0147 static void lp5562_stop_engine(struct lp55xx_chip *chip)
0148 {
0149 lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DISABLE);
0150 lp5562_wait_opmode_done();
0151 }
0152
0153 static void lp5562_run_engine(struct lp55xx_chip *chip, bool start)
0154 {
0155 int ret;
0156 u8 mode;
0157 u8 exec;
0158
0159
0160 if (!start) {
0161 lp55xx_write(chip, LP5562_REG_ENABLE, LP5562_ENABLE_DEFAULT);
0162 lp5562_wait_enable_done();
0163 lp5562_stop_engine(chip);
0164 lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_PWM);
0165 lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DIRECT);
0166 lp5562_wait_opmode_done();
0167 return;
0168 }
0169
0170
0171
0172
0173
0174
0175 ret = lp55xx_read(chip, LP5562_REG_OP_MODE, &mode);
0176 if (ret)
0177 return;
0178
0179 ret = lp55xx_read(chip, LP5562_REG_ENABLE, &exec);
0180 if (ret)
0181 return;
0182
0183
0184 if (LP5562_ENG1_IS_LOADING(mode)) {
0185 mode = (mode & ~LP5562_MODE_ENG1_M) | LP5562_RUN_ENG1;
0186 exec = (exec & ~LP5562_EXEC_ENG1_M) | LP5562_RUN_ENG1;
0187 }
0188
0189 if (LP5562_ENG2_IS_LOADING(mode)) {
0190 mode = (mode & ~LP5562_MODE_ENG2_M) | LP5562_RUN_ENG2;
0191 exec = (exec & ~LP5562_EXEC_ENG2_M) | LP5562_RUN_ENG2;
0192 }
0193
0194 if (LP5562_ENG3_IS_LOADING(mode)) {
0195 mode = (mode & ~LP5562_MODE_ENG3_M) | LP5562_RUN_ENG3;
0196 exec = (exec & ~LP5562_EXEC_ENG3_M) | LP5562_RUN_ENG3;
0197 }
0198
0199 lp55xx_write(chip, LP5562_REG_OP_MODE, mode);
0200 lp5562_wait_opmode_done();
0201
0202 lp55xx_update_bits(chip, LP5562_REG_ENABLE, LP5562_EXEC_M, exec);
0203 lp5562_wait_enable_done();
0204 }
0205
0206 static int lp5562_update_firmware(struct lp55xx_chip *chip,
0207 const u8 *data, size_t size)
0208 {
0209 enum lp55xx_engine_index idx = chip->engine_idx;
0210 u8 pattern[LP5562_PROGRAM_LENGTH] = {0};
0211 static const u8 addr[] = {
0212 [LP55XX_ENGINE_1] = LP5562_REG_PROG_MEM_ENG1,
0213 [LP55XX_ENGINE_2] = LP5562_REG_PROG_MEM_ENG2,
0214 [LP55XX_ENGINE_3] = LP5562_REG_PROG_MEM_ENG3,
0215 };
0216 unsigned cmd;
0217 char c[3];
0218 int program_size;
0219 int nrchars;
0220 int offset = 0;
0221 int ret;
0222 int i;
0223
0224
0225 for (i = 0; i < LP5562_PROGRAM_LENGTH; i++)
0226 lp55xx_write(chip, addr[idx] + i, 0);
0227
0228 i = 0;
0229 while ((offset < size - 1) && (i < LP5562_PROGRAM_LENGTH)) {
0230
0231 ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
0232 if (ret != 1)
0233 goto err;
0234
0235 ret = sscanf(c, "%2x", &cmd);
0236 if (ret != 1)
0237 goto err;
0238
0239 pattern[i] = (u8)cmd;
0240 offset += nrchars;
0241 i++;
0242 }
0243
0244
0245 if (i % 2)
0246 goto err;
0247
0248 program_size = i;
0249 for (i = 0; i < program_size; i++)
0250 lp55xx_write(chip, addr[idx] + i, pattern[i]);
0251
0252 return 0;
0253
0254 err:
0255 dev_err(&chip->cl->dev, "wrong pattern format\n");
0256 return -EINVAL;
0257 }
0258
0259 static void lp5562_firmware_loaded(struct lp55xx_chip *chip)
0260 {
0261 const struct firmware *fw = chip->fw;
0262
0263
0264
0265
0266
0267 if (fw->size > (LP5562_PROGRAM_LENGTH * 2)) {
0268 dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
0269 fw->size);
0270 return;
0271 }
0272
0273
0274
0275
0276
0277
0278
0279 lp5562_load_engine(chip);
0280 lp5562_update_firmware(chip, fw->data, fw->size);
0281 }
0282
0283 static int lp5562_post_init_device(struct lp55xx_chip *chip)
0284 {
0285 int ret;
0286 u8 cfg = LP5562_DEFAULT_CFG;
0287
0288
0289 ret = lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DIRECT);
0290 if (ret)
0291 return ret;
0292
0293 lp5562_wait_opmode_done();
0294
0295
0296 if (!lp55xx_is_extclk_used(chip))
0297 cfg |= LP5562_CLK_INT;
0298
0299 ret = lp55xx_write(chip, LP5562_REG_CONFIG, cfg);
0300 if (ret)
0301 return ret;
0302
0303
0304 lp55xx_write(chip, LP5562_REG_R_PWM, 0);
0305 lp55xx_write(chip, LP5562_REG_G_PWM, 0);
0306 lp55xx_write(chip, LP5562_REG_B_PWM, 0);
0307 lp55xx_write(chip, LP5562_REG_W_PWM, 0);
0308
0309
0310 lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_PWM);
0311
0312 return 0;
0313 }
0314
0315 static int lp5562_led_brightness(struct lp55xx_led *led)
0316 {
0317 struct lp55xx_chip *chip = led->chip;
0318 static const u8 addr[] = {
0319 LP5562_REG_R_PWM,
0320 LP5562_REG_G_PWM,
0321 LP5562_REG_B_PWM,
0322 LP5562_REG_W_PWM,
0323 };
0324 int ret;
0325
0326 mutex_lock(&chip->lock);
0327 ret = lp55xx_write(chip, addr[led->chan_nr], led->brightness);
0328 mutex_unlock(&chip->lock);
0329
0330 return ret;
0331 }
0332
0333 static void lp5562_write_program_memory(struct lp55xx_chip *chip,
0334 u8 base, const u8 *rgb, int size)
0335 {
0336 int i;
0337
0338 if (!rgb || size <= 0)
0339 return;
0340
0341 for (i = 0; i < size; i++)
0342 lp55xx_write(chip, base + i, *(rgb + i));
0343
0344 lp55xx_write(chip, base + i, 0);
0345 lp55xx_write(chip, base + i + 1, 0);
0346 }
0347
0348
0349 static inline bool _is_pc_overflow(struct lp55xx_predef_pattern *ptn)
0350 {
0351 return ptn->size_r >= LP5562_PROGRAM_LENGTH ||
0352 ptn->size_g >= LP5562_PROGRAM_LENGTH ||
0353 ptn->size_b >= LP5562_PROGRAM_LENGTH;
0354 }
0355
0356 static int lp5562_run_predef_led_pattern(struct lp55xx_chip *chip, int mode)
0357 {
0358 struct lp55xx_predef_pattern *ptn;
0359 int i;
0360
0361 if (mode == LP5562_PATTERN_OFF) {
0362 lp5562_run_engine(chip, false);
0363 return 0;
0364 }
0365
0366 ptn = chip->pdata->patterns + (mode - 1);
0367 if (!ptn || _is_pc_overflow(ptn)) {
0368 dev_err(&chip->cl->dev, "invalid pattern data\n");
0369 return -EINVAL;
0370 }
0371
0372 lp5562_stop_engine(chip);
0373
0374
0375 lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_RGB);
0376
0377
0378 for (i = LP55XX_ENGINE_1; i <= LP55XX_ENGINE_3; i++) {
0379 chip->engine_idx = i;
0380 lp5562_load_engine(chip);
0381 }
0382
0383
0384 lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG1, 0);
0385 lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG1 + 1, 0);
0386 lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG2, 0);
0387 lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG2 + 1, 0);
0388 lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG3, 0);
0389 lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG3 + 1, 0);
0390
0391
0392 lp5562_write_program_memory(chip, LP5562_REG_PROG_MEM_ENG1,
0393 ptn->r, ptn->size_r);
0394 lp5562_write_program_memory(chip, LP5562_REG_PROG_MEM_ENG2,
0395 ptn->g, ptn->size_g);
0396 lp5562_write_program_memory(chip, LP5562_REG_PROG_MEM_ENG3,
0397 ptn->b, ptn->size_b);
0398
0399
0400 lp5562_run_engine(chip, true);
0401
0402 return 0;
0403 }
0404
0405 static ssize_t lp5562_store_pattern(struct device *dev,
0406 struct device_attribute *attr,
0407 const char *buf, size_t len)
0408 {
0409 struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
0410 struct lp55xx_chip *chip = led->chip;
0411 struct lp55xx_predef_pattern *ptn = chip->pdata->patterns;
0412 int num_patterns = chip->pdata->num_patterns;
0413 unsigned long mode;
0414 int ret;
0415
0416 ret = kstrtoul(buf, 0, &mode);
0417 if (ret)
0418 return ret;
0419
0420 if (mode > num_patterns || !ptn)
0421 return -EINVAL;
0422
0423 mutex_lock(&chip->lock);
0424 ret = lp5562_run_predef_led_pattern(chip, mode);
0425 mutex_unlock(&chip->lock);
0426
0427 if (ret)
0428 return ret;
0429
0430 return len;
0431 }
0432
0433 static ssize_t lp5562_store_engine_mux(struct device *dev,
0434 struct device_attribute *attr,
0435 const char *buf, size_t len)
0436 {
0437 struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
0438 struct lp55xx_chip *chip = led->chip;
0439 u8 mask;
0440 u8 val;
0441
0442
0443
0444
0445
0446
0447
0448
0449 if (sysfs_streq(buf, "RGB")) {
0450 mask = LP5562_ENG_FOR_RGB_M;
0451 val = LP5562_ENG_SEL_RGB;
0452 } else if (sysfs_streq(buf, "W")) {
0453 enum lp55xx_engine_index idx = chip->engine_idx;
0454
0455 mask = LP5562_ENG_FOR_W_M;
0456 switch (idx) {
0457 case LP55XX_ENGINE_1:
0458 val = LP5562_ENG1_FOR_W;
0459 break;
0460 case LP55XX_ENGINE_2:
0461 val = LP5562_ENG2_FOR_W;
0462 break;
0463 case LP55XX_ENGINE_3:
0464 val = LP5562_ENG3_FOR_W;
0465 break;
0466 default:
0467 return -EINVAL;
0468 }
0469
0470 } else {
0471 dev_err(dev, "choose RGB or W\n");
0472 return -EINVAL;
0473 }
0474
0475 mutex_lock(&chip->lock);
0476 lp55xx_update_bits(chip, LP5562_REG_ENG_SEL, mask, val);
0477 mutex_unlock(&chip->lock);
0478
0479 return len;
0480 }
0481
0482 static LP55XX_DEV_ATTR_WO(led_pattern, lp5562_store_pattern);
0483 static LP55XX_DEV_ATTR_WO(engine_mux, lp5562_store_engine_mux);
0484
0485 static struct attribute *lp5562_attributes[] = {
0486 &dev_attr_led_pattern.attr,
0487 &dev_attr_engine_mux.attr,
0488 NULL,
0489 };
0490
0491 static const struct attribute_group lp5562_group = {
0492 .attrs = lp5562_attributes,
0493 };
0494
0495
0496 static struct lp55xx_device_config lp5562_cfg = {
0497 .max_channel = LP5562_MAX_LEDS,
0498 .reset = {
0499 .addr = LP5562_REG_RESET,
0500 .val = LP5562_RESET,
0501 },
0502 .enable = {
0503 .addr = LP5562_REG_ENABLE,
0504 .val = LP5562_ENABLE_DEFAULT,
0505 },
0506 .post_init_device = lp5562_post_init_device,
0507 .set_led_current = lp5562_set_led_current,
0508 .brightness_fn = lp5562_led_brightness,
0509 .run_engine = lp5562_run_engine,
0510 .firmware_cb = lp5562_firmware_loaded,
0511 .dev_attr_group = &lp5562_group,
0512 };
0513
0514 static int lp5562_probe(struct i2c_client *client,
0515 const struct i2c_device_id *id)
0516 {
0517 int ret;
0518 struct lp55xx_chip *chip;
0519 struct lp55xx_led *led;
0520 struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
0521 struct device_node *np = dev_of_node(&client->dev);
0522
0523 chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
0524 if (!chip)
0525 return -ENOMEM;
0526
0527 chip->cfg = &lp5562_cfg;
0528
0529 if (!pdata) {
0530 if (np) {
0531 pdata = lp55xx_of_populate_pdata(&client->dev, np,
0532 chip);
0533 if (IS_ERR(pdata))
0534 return PTR_ERR(pdata);
0535 } else {
0536 dev_err(&client->dev, "no platform data\n");
0537 return -EINVAL;
0538 }
0539 }
0540
0541
0542 led = devm_kcalloc(&client->dev,
0543 pdata->num_channels, sizeof(*led), GFP_KERNEL);
0544 if (!led)
0545 return -ENOMEM;
0546
0547 chip->cl = client;
0548 chip->pdata = pdata;
0549
0550 mutex_init(&chip->lock);
0551
0552 i2c_set_clientdata(client, led);
0553
0554 ret = lp55xx_init_device(chip);
0555 if (ret)
0556 goto err_init;
0557
0558 ret = lp55xx_register_leds(led, chip);
0559 if (ret)
0560 goto err_out;
0561
0562 ret = lp55xx_register_sysfs(chip);
0563 if (ret) {
0564 dev_err(&client->dev, "registering sysfs failed\n");
0565 goto err_out;
0566 }
0567
0568 return 0;
0569
0570 err_out:
0571 lp55xx_deinit_device(chip);
0572 err_init:
0573 return ret;
0574 }
0575
0576 static int lp5562_remove(struct i2c_client *client)
0577 {
0578 struct lp55xx_led *led = i2c_get_clientdata(client);
0579 struct lp55xx_chip *chip = led->chip;
0580
0581 lp5562_stop_engine(chip);
0582
0583 lp55xx_unregister_sysfs(chip);
0584 lp55xx_deinit_device(chip);
0585
0586 return 0;
0587 }
0588
0589 static const struct i2c_device_id lp5562_id[] = {
0590 { "lp5562", 0 },
0591 { }
0592 };
0593 MODULE_DEVICE_TABLE(i2c, lp5562_id);
0594
0595 #ifdef CONFIG_OF
0596 static const struct of_device_id of_lp5562_leds_match[] = {
0597 { .compatible = "ti,lp5562", },
0598 {},
0599 };
0600
0601 MODULE_DEVICE_TABLE(of, of_lp5562_leds_match);
0602 #endif
0603
0604 static struct i2c_driver lp5562_driver = {
0605 .driver = {
0606 .name = "lp5562",
0607 .of_match_table = of_match_ptr(of_lp5562_leds_match),
0608 },
0609 .probe = lp5562_probe,
0610 .remove = lp5562_remove,
0611 .id_table = lp5562_id,
0612 };
0613
0614 module_i2c_driver(lp5562_driver);
0615
0616 MODULE_DESCRIPTION("Texas Instruments LP5562 LED Driver");
0617 MODULE_AUTHOR("Milo Kim");
0618 MODULE_LICENSE("GPL");