1 /*
2 * Simple driver for Texas Instruments lp8860 Backlight driver chip
3 *
4 * Copyright (C) 2014 Texas Instruments
5 * Author: Daniel Jeong <gshark.jeong@gmail.com>
6 * Ldd Mlp <ldd-mlp@list.ti.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13 #include <linux/module.h>
14 #include <linux/backlight.h>
15 #include <linux/delay.h>
16 #include <linux/err.h>
17 #include <linux/i2c.h>
18 #include <linux/platform_data/lp8860_bl.h>
19 #include <linux/regmap.h>
20 #include <linux/slab.h>
21 #include <linux/uaccess.h>
23 #define REG_CL0_BRT_H 0x00
24 #define REG_CL0_BRT_L 0x01
25 #define REG_CL0_I_H 0x02
26 #define REG_CL0_I_L 0x03
28 #define REG_CL1_BRT_H 0x04
29 #define REG_CL1_BRT_L 0x05
30 #define REG_CL1_I 0x06
32 #define REG_CL2_BRT_H 0x07
33 #define REG_CL2_BRT_L 0x08
34 #define REG_CL2_I 0x09
36 #define REG_CL3_BRT_H 0x0a
37 #define REG_CL3_BRT_L 0x0b
38 #define REG_CL3_I 0x0c
40 #define REG_CONF 0x0d
41 #define REG_STATUS 0x0e
42 #define REG_ID 0x12
44 #define REG_ROM_CTRL 0x19
45 #define REG_ROM_ULOCK 0x1a
46 #define REG_ROM_START 0x60
47 #define REG_ROM_END 0x78
49 #define REG_EEPROM_START 0x60
50 #define REG_EEPROM_END 0x78
51 #define REG_MAX 0xFF
53 #define ULCODE0 0x08
54 #define ULCODE1 0xba
55 #define ULCODE2 0xef
56 #define LCODE 0x00
58 struct lp8860_chip {
59 struct device *dev;
61 struct lp8860_platform_data *pdata;
62 struct backlight_device *bled[LP8860_LED_MAX];
63 struct regmap *regmap;
65 /* mlp test interface */
66 unsigned int reg;
67 unsigned int reg_data;
68 };
70 /* brightness control */
71 static int lp8860_bled_update_status(struct backlight_device *bl,
72 enum lp8860_leds nsr)
73 {
74 int ret = -EINVAL;
75 struct lp8860_chip *pchip = bl_get_data(bl);
77 if (pchip->pdata->mode)
78 return 0;
80 if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
81 bl->props.brightness = 0;
83 switch (nsr) {
84 case LP8860_LED0:
85 ret = regmap_write(pchip->regmap,
86 REG_CL0_BRT_H, bl->props.brightness >> 8);
87 ret |= regmap_write(pchip->regmap,
88 REG_CL0_BRT_L, bl->props.brightness & 0xff);
89 break;
90 case LP8860_LED1:
91 ret = regmap_write(pchip->regmap,
92 REG_CL1_BRT_H,
93 (bl->props.brightness >> 8) & 0x1f);
94 ret |= regmap_write(pchip->regmap, REG_CL1_BRT_L,
95 bl->props.brightness & 0xff);
96 break;
97 case LP8860_LED2:
98 ret = regmap_write(pchip->regmap,
99 REG_CL2_BRT_H,
100 (bl->props.brightness >> 8) & 0x1f);
101 ret |= regmap_write(pchip->regmap, REG_CL2_BRT_L,
102 bl->props.brightness & 0xff);
103 break;
104 case LP8860_LED3:
105 ret = regmap_write(pchip->regmap,
106 REG_CL3_BRT_H,
107 (bl->props.brightness >> 8) & 0x1f);
108 ret |= regmap_write(pchip->regmap, REG_CL3_BRT_L,
109 bl->props.brightness & 0xff);
110 break;
111 default:
112 BUG();
113 }
114 if (ret < 0)
115 dev_err(pchip->dev, "fail : i2c access to register.\n");
116 else
117 ret = bl->props.brightness;
119 return ret;
120 }
122 static int lp8860_bled_get_brightness(struct backlight_device *bl,
123 enum lp8860_leds nsr)
124 {
125 struct lp8860_chip *pchip = bl_get_data(bl);
126 unsigned int rval_h, rval_l;
127 int ret = -EINVAL;
129 switch (nsr) {
130 case LP8860_LED0:
131 ret = regmap_read(pchip->regmap, REG_CL0_BRT_H, &rval_h);
132 ret |= regmap_read(pchip->regmap, REG_CL0_BRT_L, &rval_l);
133 break;
134 case LP8860_LED1:
135 ret = regmap_read(pchip->regmap, REG_CL1_BRT_H, &rval_h);
136 ret |= regmap_read(pchip->regmap, REG_CL1_BRT_L, &rval_l);
137 break;
138 case LP8860_LED2:
139 ret = regmap_read(pchip->regmap, REG_CL2_BRT_H, &rval_h);
140 ret |= regmap_read(pchip->regmap, REG_CL2_BRT_L, &rval_l);
141 break;
142 case LP8860_LED3:
143 ret = regmap_read(pchip->regmap, REG_CL3_BRT_H, &rval_h);
144 ret |= regmap_read(pchip->regmap, REG_CL3_BRT_L, &rval_l);
145 break;
146 default:
147 BUG();
148 }
149 if (ret < 0) {
150 dev_err(pchip->dev, "fail : i2c access to register.\n");
151 return ret;
152 }
153 bl->props.brightness = (rval_h << 8) | rval_l;
154 return bl->props.brightness;
155 }
157 static int lp8860_update_status_bled0(struct backlight_device *bl)
158 {
159 return lp8860_bled_update_status(bl, LP8860_LED0);
160 }
162 static int lp8860_get_brightness_bled0(struct backlight_device *bl)
163 {
164 return lp8860_bled_get_brightness(bl, LP8860_LED0);
165 }
167 static int lp8860_update_status_bled1(struct backlight_device *bl)
168 {
169 return lp8860_bled_update_status(bl, LP8860_LED1);
170 }
172 static int lp8860_get_brightness_bled1(struct backlight_device *bl)
173 {
174 return lp8860_bled_get_brightness(bl, LP8860_LED1);
175 }
177 static int lp8860_update_status_bled2(struct backlight_device *bl)
178 {
179 return lp8860_bled_update_status(bl, LP8860_LED2);
180 }
182 static int lp8860_get_brightness_bled2(struct backlight_device *bl)
183 {
184 return lp8860_bled_get_brightness(bl, LP8860_LED2);
185 }
187 static int lp8860_update_status_bled3(struct backlight_device *bl)
188 {
189 return lp8860_bled_update_status(bl, LP8860_LED3);
190 }
192 static int lp8860_get_brightness_bled3(struct backlight_device *bl)
193 {
194 return lp8860_bled_get_brightness(bl, LP8860_LED3);
195 }
197 #define lp8860_bled_ops(_id)\
198 {\
199 .options = BL_CORE_SUSPENDRESUME,\
200 .update_status = lp8860_update_status_bled##_id,\
201 .get_brightness = lp8860_get_brightness_bled##_id,\
202 }
204 static const struct backlight_ops lp8860_bled_ops[LP8860_LED_MAX] = {
205 [LP8860_LED0] = lp8860_bled_ops(0),
206 [LP8860_LED1] = lp8860_bled_ops(1),
207 [LP8860_LED2] = lp8860_bled_ops(2),
208 [LP8860_LED3] = lp8860_bled_ops(3),
209 };
211 /* current control */
212 static int lp8860_set_current(struct device *dev,
213 const char *buf, enum lp8860_leds nsr)
214 {
215 struct lp8860_chip *pchip = dev_get_drvdata(dev);
216 unsigned int ival;
217 ssize_t ret;
219 ret = kstrtouint(buf, 10, &ival);
220 if (ret)
221 return ret;
223 switch (nsr) {
224 case LP8860_LED0:
225 ival = min_t(unsigned int, ival, LP8860_LED0_BR_MAX);
226 ret = regmap_write(pchip->regmap, REG_CL0_I_H, ival >> 8);
227 ret |= regmap_write(pchip->regmap, REG_CL0_I_L, ival & 0xff);
228 break;
229 case LP8860_LED1:
230 ival = min_t(unsigned int, ival, LP8860_LED1_BR_MAX);
231 ret = regmap_write(pchip->regmap, REG_CL1_I, ival & 0xff);
232 break;
233 case LP8860_LED2:
234 ival = min_t(unsigned int, ival, LP8860_LED2_BR_MAX);
235 ret = regmap_write(pchip->regmap, REG_CL2_I, ival & 0xff);
236 break;
237 case LP8860_LED3:
238 ival = min_t(unsigned int, ival, LP8860_LED3_BR_MAX);
239 ret = regmap_write(pchip->regmap, REG_CL3_I, ival & 0xff);
240 break;
241 default:
242 BUG();
243 }
244 if (ret < 0)
245 dev_err(pchip->dev, "fail : i2c access error.\n");
247 return ret;
248 }
250 static ssize_t lp8860_current_store_bled0(struct device *dev,
251 struct device_attribute *devAttr,
252 const char *buf, size_t size)
253 {
254 int ret;
256 ret = lp8860_set_current(dev, buf, LP8860_LED0);
257 if (ret < 0)
258 return ret;
259 return size;
260 }
262 static ssize_t lp8860_current_store_bled1(struct device *dev,
263 struct device_attribute *devAttr,
264 const char *buf, size_t size)
265 {
266 int ret;
268 ret = lp8860_set_current(dev, buf, LP8860_LED1);
269 if (ret < 0)
270 return ret;
271 return size;
272 }
274 static ssize_t lp8860_current_store_bled2(struct device *dev,
275 struct device_attribute *devAttr,
276 const char *buf, size_t size)
277 {
278 int ret;
280 ret = lp8860_set_current(dev, buf, LP8860_LED2);
281 if (ret < 0)
282 return ret;
283 return size;
284 }
286 static ssize_t lp8860_current_store_bled3(struct device *dev,
287 struct device_attribute *devAttr,
288 const char *buf, size_t size)
289 {
290 int ret;
292 ret = lp8860_set_current(dev, buf, LP8860_LED3);
293 if (ret < 0)
294 return ret;
295 return size;
296 }
298 #define lp8860_attr(_name, _show, _store)\
299 {\
300 .attr = {\
301 .name = _name,\
302 .mode = S_IWUSR|S_IRUSR,\
303 },\
304 .show = _show,\
305 .store = _store,\
306 }
308 static struct device_attribute lp8860_dev_attr[LP8860_LED_MAX] = {
309 [LP8860_LED0] = lp8860_attr("current", NULL,
310 lp8860_current_store_bled0),
311 [LP8860_LED1] = lp8860_attr("current", NULL,
312 lp8860_current_store_bled1),
313 [LP8860_LED2] = lp8860_attr("current", NULL,
314 lp8860_current_store_bled2),
315 [LP8860_LED3] = lp8860_attr("current", NULL,
316 lp8860_current_store_bled3),
317 };
319 /* get argument from input buffer */
320 static int token_store_data(char *buf, char *cmd, unsigned int *reg,
321 unsigned int *mask, unsigned int *data)
322 {
323 char *token;
324 char *desc = " >\t\n";
325 unsigned int tokenval;
327 /* command */
328 token = strsep(&buf, desc);
329 if (token == NULL)
330 goto err_out;
331 *cmd = *token;
332 if (*cmd == 'w' || *cmd == 'r') {
333 /* register no. to read/write */
334 token = strsep(&buf, desc);
335 if (token == NULL)
336 goto err_out;
337 if (kstrtouint((const char *)token, 16, &tokenval) < 0)
338 goto err_out;
339 *reg = tokenval;
341 /* write command */
342 if (*cmd == 'w') {
343 /* mask bit */
344 token = strsep(&buf, desc);
345 if (token == NULL)
346 goto err_out;
347 if (kstrtouint((const char *)token, 16, &tokenval) < 0)
348 goto err_out;
349 *mask = tokenval;
351 /* write data */
352 token = strsep(&buf, desc);
353 if (token == NULL)
354 goto err_out;
355 if (kstrtouint((const char *)token, 16, &tokenval) < 0)
356 goto err_out;
357 *data = tokenval;
358 } else {
359 *mask = 0;
360 *data = 0;
361 }
362 return 0;
363 }
364 err_out:
365 return -EINVAL;
366 }
368 /* register access */
369 static ssize_t lp8860_register_show(struct device *dev,
370 struct device_attribute *devAttr, char *buf)
371 {
372 struct lp8860_chip *pchip = dev_get_drvdata(dev);
374 if (pchip->reg < 0x0 || pchip->reg > 0xff)
375 return sprintf(buf, "Fail : invalid access %x\n", pchip->reg);
376 return sprintf(buf, "%x %x", pchip->reg, pchip->reg_data);
377 }
379 static ssize_t lp8860_register_store(struct device *dev,
380 struct device_attribute *devAttr,
381 const char *buf, size_t size)
382 {
383 struct lp8860_chip *pchip = dev_get_drvdata(dev);
384 int ret;
385 char cmd;
386 unsigned int reg, mask, data;
388 ret = token_store_data((char *)buf, &cmd, ®, &mask, &data);
389 if (ret < 0)
390 goto err_input;
391 pchip->reg = reg;
392 if (cmd == 'w' || cmd == 'W') {
393 ret = regmap_update_bits(pchip->regmap, reg, mask, data);
394 if (ret < 0) {
395 pchip->reg_data = ret;
396 goto err_i2c;
397 }
398 }
399 ret = regmap_read(pchip->regmap, reg, &data);
400 if (ret < 0) {
401 pchip->reg_data = ret;
402 goto err_i2c;
403 }
404 pchip->reg_data = data;
405 return size;
407 err_i2c:
408 dev_err(pchip->dev, "fail : i2c access error\n");
409 return size;
411 err_input:
412 dev_err(pchip->dev, "failed : input fail\n");
413 return size;
414 }
416 static DEVICE_ATTR(registers, S_IWUSR | S_IRUSR,
417 lp8860_register_show, lp8860_register_store);
419 /*
420 * Input data
421 * 0 : read from eeprom to eeprom registers.
422 * 1 : eeprom unlock before writing
423 * 2 : brun and lock
424 */
425 static ssize_t lp8860_eeprom_store(struct device *dev,
426 struct device_attribute *devAttr,
427 const char *buf, size_t size)
428 {
429 struct lp8860_chip *pchip = dev_get_drvdata(dev);
430 unsigned int ival;
431 int ret;
433 ret = kstrtouint(buf, 10, &ival);
434 if (ret)
435 goto err_input;
437 switch (ival) {
438 /*
439 * Read sequence
440 * 1. Unlock EEPROM by writing
441 * the unlock codes to register 1Ah(08, BA, EF)
442 * 2. Write EE_PROG to 1 in address 19h. (02h to address 19h)
443 * 3. Wait 100ms
444 * 4. Write EE_PROG to 0 in address 19h. (00h to address 19h)
445 * 5. Lock EEPROM by writing 0h to register 1Ah.
446 */
447 case 0:
448 ret = regmap_write(pchip->regmap, REG_ROM_ULOCK, ULCODE0);
449 ret |= regmap_write(pchip->regmap, REG_ROM_ULOCK, ULCODE1);
450 ret |= regmap_write(pchip->regmap, REG_ROM_ULOCK, ULCODE2);
451 ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x01);
452 msleep(100);
453 ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x00);
454 ret |= regmap_write(pchip->regmap, REG_ROM_ULOCK, LCODE);
455 if (ret < 0)
456 goto err_i2c;
457 dev_info(pchip->dev, "LP8860 EEPROM Read Done\n");
458 break;
459 /*
460 * Programming sequence
461 * (program data permanently from registers to NVM)
462 * 1. Unlock EEPROM by writing
463 * the unlock codes to register 1Ah(08, BA, EF)
464 * 2. Write data to EEPROM registers (address 60h...78h)
465 * (use registers device node)
466 * 3. Write EE_PROG to 1 in address 19h. (02h to address 19h)
467 * 4. Wait 100ms
468 * 5. Write EE_PROG to 0 in address 19h. (00h to address 19h)
469 * 6. Lock EEPROM by writing 0h to register 1Ah.
470 */
471 case 1:
472 ret = regmap_write(pchip->regmap, REG_ROM_ULOCK, ULCODE0);
473 ret |= regmap_write(pchip->regmap, REG_ROM_ULOCK, ULCODE1);
474 ret |= regmap_write(pchip->regmap, REG_ROM_ULOCK, ULCODE2);
475 if (ret < 0)
476 goto err_i2c;
477 dev_info(pchip->dev, "LP8860 EEPROM is Unlocked\n");
478 break;
479 case 2:
480 ret = regmap_write(pchip->regmap, REG_ROM_CTRL, 0x02);
481 msleep(100);
482 ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x00);
483 ret |= regmap_write(pchip->regmap, REG_ROM_ULOCK, LCODE);
484 if (ret < 0)
485 goto err_i2c;
486 dev_info(pchip->dev, "LP8860 EEPROM is Locked\n");
487 break;
488 default:
489 goto err_input;
490 }
492 return size;
494 err_i2c:
495 dev_err(pchip->dev, "fail : i2c access error.\n");
496 return ret;
498 err_input:
499 dev_err(pchip->dev, "fail : input fail.\n");
500 return -EINVAL;
501 }
503 static DEVICE_ATTR(eeprom, S_IWUSR, NULL, lp8860_eeprom_store);
505 /* backlight register and remove */
506 static char *lp8860_bled_name[LP8860_LED_MAX] = {
507 [LP8860_LED0] = "bled0",
508 [LP8860_LED1] = "bled1",
509 [LP8860_LED2] = "bled2",
510 [LP8860_LED3] = "bled3",
511 };
513 static int lp8860_backlight_remove(struct lp8860_chip *pchip)
514 {
515 int icnt;
517 device_remove_file(&(pchip->bled[0]->dev), &dev_attr_registers);
518 device_remove_file(&(pchip->bled[0]->dev), &dev_attr_eeprom);
519 for (icnt = LP8860_LED0; icnt < LP8860_LED_MAX; icnt++) {
520 if (pchip->bled[icnt]) {
521 backlight_device_unregister(pchip->bled[icnt]);
522 device_remove_file(&(pchip->bled[icnt]->dev),
523 &lp8860_dev_attr[icnt]);
524 }
525 }
526 return 0;
527 }
529 static int lp8860_backlight_registers(struct lp8860_chip *pchip)
530 {
531 struct backlight_properties props;
532 struct lp8860_platform_data *pdata = pchip->pdata;
533 int icnt, ret;
535 props.type = BACKLIGHT_RAW;
536 for (icnt = LP8860_LED0; icnt < LP8860_LED_MAX; icnt++) {
537 props.max_brightness = pdata->max_brt[icnt];
538 pchip->bled[icnt] =
539 backlight_device_register(lp8860_bled_name[icnt],
540 pchip->dev, pchip,
541 &lp8860_bled_ops[icnt], &props);
542 if (IS_ERR(pchip->bled[icnt])) {
543 dev_err(pchip->dev, "fail : backlight register.\n");
544 ret = PTR_ERR(pchip->bled);
545 goto err_out;
546 }
548 ret = device_create_file(&(pchip->bled[icnt]->dev),
549 &lp8860_dev_attr[icnt]);
550 if (ret < 0) {
551 dev_err(pchip->dev, "fail : to add sysfs entries.\n");
552 goto err_out;
553 }
554 }
555 /* to access eeprom */
556 ret = device_create_file(&(pchip->bled[LP8860_LED0]->dev),
557 &dev_attr_eeprom);
558 if (ret < 0) {
559 dev_err(pchip->dev, "fail : to add sysfs entries.\n");
560 goto err_out;
561 }
562 /* to access registers */
563 ret = device_create_file(&(pchip->bled[LP8860_LED0]->dev),
564 &dev_attr_registers);
565 if (ret < 0) {
566 dev_err(pchip->dev, "failed : add sysfs entries\n");
567 goto err_out;
568 }
569 return 0;
571 err_out:
572 lp8860_backlight_remove(pchip);
573 return ret;
574 }
576 static const struct regmap_config lp8860_regmap = {
577 .reg_bits = 8,
578 .val_bits = 8,
579 .max_register = REG_MAX,
580 };
582 static int lp8860_probe(struct i2c_client *client,
583 const struct i2c_device_id *id)
584 {
585 struct lp8860_chip *pchip;
586 struct lp8860_platform_data *pdata = dev_get_platdata(&client->dev);
587 int ret, icnt;
589 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
590 dev_err(&client->dev, "fail : i2c functionality check.\n");
591 return -EOPNOTSUPP;
592 }
594 pchip = devm_kzalloc(&client->dev,
595 sizeof(struct lp8860_chip), GFP_KERNEL);
596 if (!pchip)
597 return -ENOMEM;
598 pchip->dev = &client->dev;
600 pchip->regmap = devm_regmap_init_i2c(client, &lp8860_regmap);
601 if (IS_ERR(pchip->regmap)) {
602 ret = PTR_ERR(pchip->regmap);
603 dev_err(pchip->dev, "fail : allocate i2c register map.\n");
604 return ret;
605 }
607 if (pdata == NULL) {
608 pdata = devm_kzalloc(pchip->dev,
609 sizeof(struct lp8860_platform_data),
610 GFP_KERNEL);
611 if (pdata == NULL)
612 return -ENOMEM;
613 pdata->max_brt[LP8860_LED0] = LP8860_LED0_BR_MAX;
614 for (icnt = LP8860_LED1; icnt < LP8860_LED_MAX; icnt++)
615 pdata->max_brt[icnt] = LP8860_LED1_BR_MAX;
616 pchip->pdata = pdata;
617 } else {
618 pchip->pdata = pdata;
619 }
620 i2c_set_clientdata(client, pchip);
621 ret = lp8860_backlight_registers(pchip);
622 return ret;
623 }
625 static int lp8860_remove(struct i2c_client *client)
626 {
627 return lp8860_backlight_remove(i2c_get_clientdata(client));
628 }
630 static const struct i2c_device_id lp8860_id[] = {
631 {LP8860_NAME, 0},
632 {}
633 };
635 MODULE_DEVICE_TABLE(i2c, lp8860_id);
636 static struct i2c_driver lp8860_i2c_driver = {
637 .driver = {
638 .name = LP8860_NAME,
639 },
640 .probe = lp8860_probe,
641 .remove = lp8860_remove,
642 .id_table = lp8860_id,
643 };
645 module_i2c_driver(lp8860_i2c_driver);
647 MODULE_DESCRIPTION("Texas Instruments LP8860 Backlight Driver");
648 MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
649 MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
650 MODULE_LICENSE("GPL v2");