summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel jeong2014-05-02 05:50:07 -0500
committerDaniel jeong2014-05-02 05:50:07 -0500
commitc5e82cede1b4e649dc7bc42486f3959df935aaca (patch)
tree274c3d214df3e26cd78146d36db17610c529d68e /drivers
parent91ddf54ee4f018514af93cac252e3170ad635fa3 (diff)
downloadkernel-c5e82cede1b4e649dc7bc42486f3959df935aaca.tar.gz
kernel-c5e82cede1b4e649dc7bc42486f3959df935aaca.tar.xz
kernel-c5e82cede1b4e649dc7bc42486f3959df935aaca.zip
Add LP8860 Device Driver - working with Android Test Applicationv0.1.LP8860.V0
Signed-off-by: Daniel jeong <daniel.jeong@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/backlight/Kconfig7
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/lp8860_bl.c650
3 files changed, 658 insertions, 0 deletions
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 5a3eb2e..908048f 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -397,6 +397,13 @@ config BACKLIGHT_LP8788
397 help 397 help
398 This supports TI LP8788 backlight driver. 398 This supports TI LP8788 backlight driver.
399 399
400config BACKLIGHT_LP8860
401 tristate "Backlight Driver for LP8860"
402 depends on BACKLIGHT_CLASS_DEVICE && I2C
403 select REGMAP_I2C
404 help
405 This supports TI LP8860 Backlight Driver
406
400config BACKLIGHT_OT200 407config BACKLIGHT_OT200
401 tristate "Backlight driver for ot200 visualisation device" 408 tristate "Backlight driver for ot200 visualisation device"
402 depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535 409 depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index bb82002..cbc5ac3 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
42obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o 42obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
43obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o 43obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
44obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o 44obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o
45obj-$(CONFIG_BACKLIGHT_LP8860) += lp8860_bl.o
45obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o 46obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o
46obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o 47obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o
47obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o 48obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
diff --git a/drivers/video/backlight/lp8860_bl.c b/drivers/video/backlight/lp8860_bl.c
new file mode 100644
index 0000000..7a5017e
--- /dev/null
+++ b/drivers/video/backlight/lp8860_bl.c
@@ -0,0 +1,650 @@
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>
22
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
27
28#define REG_CL1_BRT_H 0x04
29#define REG_CL1_BRT_L 0x05
30#define REG_CL1_I 0x06
31
32#define REG_CL2_BRT_H 0x07
33#define REG_CL2_BRT_L 0x08
34#define REG_CL2_I 0x09
35
36#define REG_CL3_BRT_H 0x0a
37#define REG_CL3_BRT_L 0x0b
38#define REG_CL3_I 0x0c
39
40#define REG_CONF 0x0d
41#define REG_STATUS 0x0e
42#define REG_ID 0x12
43
44#define REG_ROM_CTRL 0x19
45#define REG_ROM_ULOCK 0x1a
46#define REG_ROM_START 0x60
47#define REG_ROM_END 0x78
48
49#define REG_EEPROM_START 0x60
50#define REG_EEPROM_END 0x78
51#define REG_MAX 0xFF
52
53#define ULCODE0 0x08
54#define ULCODE1 0xba
55#define ULCODE2 0xef
56#define LCODE 0x00
57
58struct lp8860_chip {
59 struct device *dev;
60
61 struct lp8860_platform_data *pdata;
62 struct backlight_device *bled[LP8860_LED_MAX];
63 struct regmap *regmap;
64
65 /* mlp test interface */
66 unsigned int reg;
67 unsigned int reg_data;
68};
69
70/* brightness control */
71static 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);
76
77 if (pchip->pdata->mode)
78 return 0;
79
80 if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
81 bl->props.brightness = 0;
82
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;
118
119 return ret;
120}
121
122static 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;
128
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}
156
157static int lp8860_update_status_bled0(struct backlight_device *bl)
158{
159 return lp8860_bled_update_status(bl, LP8860_LED0);
160}
161
162static int lp8860_get_brightness_bled0(struct backlight_device *bl)
163{
164 return lp8860_bled_get_brightness(bl, LP8860_LED0);
165}
166
167static int lp8860_update_status_bled1(struct backlight_device *bl)
168{
169 return lp8860_bled_update_status(bl, LP8860_LED1);
170}
171
172static int lp8860_get_brightness_bled1(struct backlight_device *bl)
173{
174 return lp8860_bled_get_brightness(bl, LP8860_LED1);
175}
176
177static int lp8860_update_status_bled2(struct backlight_device *bl)
178{
179 return lp8860_bled_update_status(bl, LP8860_LED2);
180}
181
182static int lp8860_get_brightness_bled2(struct backlight_device *bl)
183{
184 return lp8860_bled_get_brightness(bl, LP8860_LED2);
185}
186
187static int lp8860_update_status_bled3(struct backlight_device *bl)
188{
189 return lp8860_bled_update_status(bl, LP8860_LED3);
190}
191
192static int lp8860_get_brightness_bled3(struct backlight_device *bl)
193{
194 return lp8860_bled_get_brightness(bl, LP8860_LED3);
195}
196
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}
203
204static 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};
210
211/* current control */
212static 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;
218
219 ret = kstrtouint(buf, 10, &ival);
220 if (ret)
221 return ret;
222
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");
246
247 return ret;
248}
249
250static 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;
255
256 ret = lp8860_set_current(dev, buf, LP8860_LED0);
257 if (ret < 0)
258 return ret;
259 return size;
260}
261
262static 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;
267
268 ret = lp8860_set_current(dev, buf, LP8860_LED1);
269 if (ret < 0)
270 return ret;
271 return size;
272}
273
274static 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;
279
280 ret = lp8860_set_current(dev, buf, LP8860_LED2);
281 if (ret < 0)
282 return ret;
283 return size;
284}
285
286static 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;
291
292 ret = lp8860_set_current(dev, buf, LP8860_LED3);
293 if (ret < 0)
294 return ret;
295 return size;
296}
297
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}
307
308static 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};
318
319/* get argument from input buffer */
320static 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;
326
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;
340
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;
350
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 }
364err_out:
365 return -EINVAL;
366}
367
368/* register access */
369static 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);
373
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}
378
379static 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;
387
388 ret = token_store_data((char *)buf, &cmd, &reg, &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;
406
407err_i2c:
408 dev_err(pchip->dev, "fail : i2c access error\n");
409 return size;
410
411err_input:
412 dev_err(pchip->dev, "failed : input fail\n");
413 return size;
414}
415
416static DEVICE_ATTR(registers, S_IWUSR | S_IRUSR,
417 lp8860_register_show, lp8860_register_store);
418
419/*
420 * Input data
421 * 0 : read from eeprom to eeprom registers.
422 * 1 : eeprom unlock before writing
423 * 2 : brun and lock
424 */
425static 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;
432
433 ret = kstrtouint(buf, 10, &ival);
434 if (ret)
435 goto err_input;
436
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 }
491
492 return size;
493
494err_i2c:
495 dev_err(pchip->dev, "fail : i2c access error.\n");
496 return ret;
497
498err_input:
499 dev_err(pchip->dev, "fail : input fail.\n");
500 return -EINVAL;
501}
502
503static DEVICE_ATTR(eeprom, S_IWUSR, NULL, lp8860_eeprom_store);
504
505/* backlight register and remove */
506static char *lp8860_bled_name[LP8860_LED_MAX] = {
507 [LP8860_LED0] = "bled0",
508 [LP8860_LED1] = "bled1",
509 [LP8860_LED2] = "bled2",
510 [LP8860_LED3] = "bled3",
511};
512
513static int lp8860_backlight_remove(struct lp8860_chip *pchip)
514{
515 int icnt;
516
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}
528
529static 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;
534
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 }
547
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;
570
571err_out:
572 lp8860_backlight_remove(pchip);
573 return ret;
574}
575
576static const struct regmap_config lp8860_regmap = {
577 .reg_bits = 8,
578 .val_bits = 8,
579 .max_register = REG_MAX,
580};
581
582static 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;
588
589 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
590 dev_err(&client->dev, "fail : i2c functionality check.\n");
591 return -EOPNOTSUPP;
592 }
593
594 pchip = devm_kzalloc(&client->dev,
595 sizeof(struct lp8860_chip), GFP_KERNEL);
596 if (!pchip)
597 return -ENOMEM;
598 pchip->dev = &client->dev;
599
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 }
606
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}
624
625static int lp8860_remove(struct i2c_client *client)
626{
627 return lp8860_backlight_remove(i2c_get_clientdata(client));
628}
629
630static const struct i2c_device_id lp8860_id[] = {
631 {LP8860_NAME, 0},
632 {}
633};
634
635MODULE_DEVICE_TABLE(i2c, lp8860_id);
636static 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};
644
645module_i2c_driver(lp8860_i2c_driver);
646
647MODULE_DESCRIPTION("Texas Instruments LP8860 Backlight Driver");
648MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
649MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
650MODULE_LICENSE("GPL v2");