aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Jeong <gshark.jeong@gmail.com>2013-11-12 18:08:58 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-12 22:09:15 -0500
commit28e64a68a2ef1c48f30e8b6803725199929069fc (patch)
treefd10ccee7c2758f37d6dd3c99a0701b29dec42cd
parent5812c13a4e636da4bd7f7cabbbbc59d9dbf3c86c (diff)
backlight: lm3630: apply chip revision
The LM3630 chip was revised by TI and chip name was also changed to LM3630A. And register map, default values and initial sequences are changed. The files, lm3630_bl.{c,h} are replaced by lm3630a_bl.{c,h} You can find more information about LM3630A(datasheet, evm etc) at http://www.ti.com/product/lm3630a Signed-off-by: Daniel Jeong <gshark.jeong@gmail.com> Signed-off-by: Jingoo Han <jg1.han@samsung.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/video/backlight/Kconfig6
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/lm3630_bl.c475
-rw-r--r--drivers/video/backlight/lm3630a_bl.c483
-rw-r--r--include/linux/platform_data/lm3630_bl.h57
-rw-r--r--include/linux/platform_data/lm3630a_bl.h65
6 files changed, 552 insertions, 536 deletions
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index a65dd063ecad..5a3eb2ecb525 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -368,12 +368,12 @@ config BACKLIGHT_AAT2870
368 If you have a AnalogicTech AAT2870 say Y to enable the 368 If you have a AnalogicTech AAT2870 say Y to enable the
369 backlight driver. 369 backlight driver.
370 370
371config BACKLIGHT_LM3630 371config BACKLIGHT_LM3630A
372 tristate "Backlight Driver for LM3630" 372 tristate "Backlight Driver for LM3630A"
373 depends on BACKLIGHT_CLASS_DEVICE && I2C 373 depends on BACKLIGHT_CLASS_DEVICE && I2C
374 select REGMAP_I2C 374 select REGMAP_I2C
375 help 375 help
376 This supports TI LM3630 Backlight Driver 376 This supports TI LM3630A Backlight Driver
377 377
378config BACKLIGHT_LM3639 378config BACKLIGHT_LM3639
379 tristate "Backlight Driver for LM3639" 379 tristate "Backlight Driver for LM3639"
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 38e1babb1946..bb820024f346 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -37,7 +37,7 @@ obj-$(CONFIG_BACKLIGHT_GPIO) += gpio_backlight.o
37obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o 37obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
38obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o 38obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
39obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o 39obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
40obj-$(CONFIG_BACKLIGHT_LM3630) += lm3630_bl.o 40obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
41obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o 41obj-$(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
diff --git a/drivers/video/backlight/lm3630_bl.c b/drivers/video/backlight/lm3630_bl.c
deleted file mode 100644
index 76a62e978fc3..000000000000
--- a/drivers/video/backlight/lm3630_bl.c
+++ /dev/null
@@ -1,475 +0,0 @@
1/*
2* Simple driver for Texas Instruments LM3630 Backlight driver chip
3* Copyright (C) 2012 Texas Instruments
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License version 2 as
7* published by the Free Software Foundation.
8*
9*/
10#include <linux/module.h>
11#include <linux/slab.h>
12#include <linux/i2c.h>
13#include <linux/backlight.h>
14#include <linux/err.h>
15#include <linux/delay.h>
16#include <linux/uaccess.h>
17#include <linux/interrupt.h>
18#include <linux/regmap.h>
19#include <linux/platform_data/lm3630_bl.h>
20
21#define REG_CTRL 0x00
22#define REG_CONFIG 0x01
23#define REG_BRT_A 0x03
24#define REG_BRT_B 0x04
25#define REG_INT_STATUS 0x09
26#define REG_INT_EN 0x0A
27#define REG_FAULT 0x0B
28#define REG_PWM_OUTLOW 0x12
29#define REG_PWM_OUTHIGH 0x13
30#define REG_MAX 0x1F
31
32#define INT_DEBOUNCE_MSEC 10
33
34enum lm3630_leds {
35 BLED_ALL = 0,
36 BLED_1,
37 BLED_2
38};
39
40static const char * const bled_name[] = {
41 [BLED_ALL] = "lm3630_bled", /*Bank1 controls all string */
42 [BLED_1] = "lm3630_bled1", /*Bank1 controls bled1 */
43 [BLED_2] = "lm3630_bled2", /*Bank1 or 2 controls bled2 */
44};
45
46struct lm3630_chip_data {
47 struct device *dev;
48 struct delayed_work work;
49 int irq;
50 struct workqueue_struct *irqthread;
51 struct lm3630_platform_data *pdata;
52 struct backlight_device *bled1;
53 struct backlight_device *bled2;
54 struct regmap *regmap;
55};
56
57/* initialize chip */
58static int lm3630_chip_init(struct lm3630_chip_data *pchip)
59{
60 int ret;
61 unsigned int reg_val;
62 struct lm3630_platform_data *pdata = pchip->pdata;
63
64 /*pwm control */
65 reg_val = ((pdata->pwm_active & 0x01) << 2) | (pdata->pwm_ctrl & 0x03);
66 ret = regmap_update_bits(pchip->regmap, REG_CONFIG, 0x07, reg_val);
67 if (ret < 0)
68 goto out;
69
70 /* bank control */
71 reg_val = ((pdata->bank_b_ctrl & 0x01) << 1) |
72 (pdata->bank_a_ctrl & 0x07);
73 ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x07, reg_val);
74 if (ret < 0)
75 goto out;
76
77 ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
78 if (ret < 0)
79 goto out;
80
81 /* set initial brightness */
82 if (pdata->bank_a_ctrl != BANK_A_CTRL_DISABLE) {
83 ret = regmap_write(pchip->regmap,
84 REG_BRT_A, pdata->init_brt_led1);
85 if (ret < 0)
86 goto out;
87 }
88
89 if (pdata->bank_b_ctrl != BANK_B_CTRL_DISABLE) {
90 ret = regmap_write(pchip->regmap,
91 REG_BRT_B, pdata->init_brt_led2);
92 if (ret < 0)
93 goto out;
94 }
95 return ret;
96
97out:
98 dev_err(pchip->dev, "i2c failed to access register\n");
99 return ret;
100}
101
102/* interrupt handling */
103static void lm3630_delayed_func(struct work_struct *work)
104{
105 int ret;
106 unsigned int reg_val;
107 struct lm3630_chip_data *pchip;
108
109 pchip = container_of(work, struct lm3630_chip_data, work.work);
110
111 ret = regmap_read(pchip->regmap, REG_INT_STATUS, &reg_val);
112 if (ret < 0) {
113 dev_err(pchip->dev,
114 "i2c failed to access REG_INT_STATUS Register\n");
115 return;
116 }
117
118 dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", reg_val);
119}
120
121static irqreturn_t lm3630_isr_func(int irq, void *chip)
122{
123 int ret;
124 struct lm3630_chip_data *pchip = chip;
125 unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC);
126
127 queue_delayed_work(pchip->irqthread, &pchip->work, delay);
128
129 ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
130 if (ret < 0)
131 goto out;
132
133 return IRQ_HANDLED;
134out:
135 dev_err(pchip->dev, "i2c failed to access register\n");
136 return IRQ_HANDLED;
137}
138
139static int lm3630_intr_config(struct lm3630_chip_data *pchip)
140{
141 INIT_DELAYED_WORK(&pchip->work, lm3630_delayed_func);
142 pchip->irqthread = create_singlethread_workqueue("lm3630-irqthd");
143 if (!pchip->irqthread) {
144 dev_err(pchip->dev, "create irq thread fail...\n");
145 return -1;
146 }
147 if (request_threaded_irq
148 (pchip->irq, NULL, lm3630_isr_func,
149 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630_irq", pchip)) {
150 dev_err(pchip->dev, "request threaded irq fail..\n");
151 return -1;
152 }
153 return 0;
154}
155
156static bool
157set_intensity(struct backlight_device *bl, struct lm3630_chip_data *pchip)
158{
159 if (!pchip->pdata->pwm_set_intensity)
160 return false;
161 pchip->pdata->pwm_set_intensity(bl->props.brightness - 1,
162 pchip->pdata->pwm_period);
163 return true;
164}
165
166/* update and get brightness */
167static int lm3630_bank_a_update_status(struct backlight_device *bl)
168{
169 int ret;
170 struct lm3630_chip_data *pchip = bl_get_data(bl);
171 enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
172
173 /* brightness 0 means disable */
174 if (!bl->props.brightness) {
175 ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x04, 0x00);
176 if (ret < 0)
177 goto out;
178 return bl->props.brightness;
179 }
180
181 /* pwm control */
182 if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) {
183 if (!set_intensity(bl, pchip))
184 dev_err(pchip->dev, "No pwm control func. in plat-data\n");
185 } else {
186
187 /* i2c control */
188 ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
189 if (ret < 0)
190 goto out;
191 mdelay(1);
192 ret = regmap_write(pchip->regmap,
193 REG_BRT_A, bl->props.brightness - 1);
194 if (ret < 0)
195 goto out;
196 }
197 return bl->props.brightness;
198out:
199 dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
200 return bl->props.brightness;
201}
202
203static int lm3630_bank_a_get_brightness(struct backlight_device *bl)
204{
205 unsigned int reg_val;
206 int brightness, ret;
207 struct lm3630_chip_data *pchip = bl_get_data(bl);
208 enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
209
210 if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) {
211 ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, &reg_val);
212 if (ret < 0)
213 goto out;
214 brightness = reg_val & 0x01;
215 ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, &reg_val);
216 if (ret < 0)
217 goto out;
218 brightness = ((brightness << 8) | reg_val) + 1;
219 } else {
220 ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
221 if (ret < 0)
222 goto out;
223 mdelay(1);
224 ret = regmap_read(pchip->regmap, REG_BRT_A, &reg_val);
225 if (ret < 0)
226 goto out;
227 brightness = reg_val + 1;
228 }
229 bl->props.brightness = brightness;
230 return bl->props.brightness;
231out:
232 dev_err(pchip->dev, "i2c failed to access register\n");
233 return 0;
234}
235
236static const struct backlight_ops lm3630_bank_a_ops = {
237 .options = BL_CORE_SUSPENDRESUME,
238 .update_status = lm3630_bank_a_update_status,
239 .get_brightness = lm3630_bank_a_get_brightness,
240};
241
242static int lm3630_bank_b_update_status(struct backlight_device *bl)
243{
244 int ret;
245 struct lm3630_chip_data *pchip = bl_get_data(bl);
246 enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
247
248 if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) {
249 if (!set_intensity(bl, pchip))
250 dev_err(pchip->dev,
251 "no pwm control func. in plat-data\n");
252 } else {
253 ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
254 if (ret < 0)
255 goto out;
256 mdelay(1);
257 ret = regmap_write(pchip->regmap,
258 REG_BRT_B, bl->props.brightness - 1);
259 }
260 return bl->props.brightness;
261out:
262 dev_err(pchip->dev, "i2c failed to access register\n");
263 return bl->props.brightness;
264}
265
266static int lm3630_bank_b_get_brightness(struct backlight_device *bl)
267{
268 unsigned int reg_val;
269 int brightness, ret;
270 struct lm3630_chip_data *pchip = bl_get_data(bl);
271 enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
272
273 if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) {
274 ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, &reg_val);
275 if (ret < 0)
276 goto out;
277 brightness = reg_val & 0x01;
278 ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, &reg_val);
279 if (ret < 0)
280 goto out;
281 brightness = ((brightness << 8) | reg_val) + 1;
282 } else {
283 ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
284 if (ret < 0)
285 goto out;
286 mdelay(1);
287 ret = regmap_read(pchip->regmap, REG_BRT_B, &reg_val);
288 if (ret < 0)
289 goto out;
290 brightness = reg_val + 1;
291 }
292 bl->props.brightness = brightness;
293
294 return bl->props.brightness;
295out:
296 dev_err(pchip->dev, "i2c failed to access register\n");
297 return bl->props.brightness;
298}
299
300static const struct backlight_ops lm3630_bank_b_ops = {
301 .options = BL_CORE_SUSPENDRESUME,
302 .update_status = lm3630_bank_b_update_status,
303 .get_brightness = lm3630_bank_b_get_brightness,
304};
305
306static int lm3630_backlight_register(struct lm3630_chip_data *pchip,
307 enum lm3630_leds ledno)
308{
309 const char *name = bled_name[ledno];
310 struct backlight_properties props;
311 struct lm3630_platform_data *pdata = pchip->pdata;
312
313 props.type = BACKLIGHT_RAW;
314 switch (ledno) {
315 case BLED_1:
316 case BLED_ALL:
317 props.brightness = pdata->init_brt_led1;
318 props.max_brightness = pdata->max_brt_led1;
319 pchip->bled1 =
320 backlight_device_register(name, pchip->dev, pchip,
321 &lm3630_bank_a_ops, &props);
322 if (IS_ERR(pchip->bled1))
323 return PTR_ERR(pchip->bled1);
324 break;
325 case BLED_2:
326 props.brightness = pdata->init_brt_led2;
327 props.max_brightness = pdata->max_brt_led2;
328 pchip->bled2 =
329 backlight_device_register(name, pchip->dev, pchip,
330 &lm3630_bank_b_ops, &props);
331 if (IS_ERR(pchip->bled2))
332 return PTR_ERR(pchip->bled2);
333 break;
334 }
335 return 0;
336}
337
338static void lm3630_backlight_unregister(struct lm3630_chip_data *pchip)
339{
340 if (pchip->bled1)
341 backlight_device_unregister(pchip->bled1);
342 if (pchip->bled2)
343 backlight_device_unregister(pchip->bled2);
344}
345
346static const struct regmap_config lm3630_regmap = {
347 .reg_bits = 8,
348 .val_bits = 8,
349 .max_register = REG_MAX,
350};
351
352static int lm3630_probe(struct i2c_client *client,
353 const struct i2c_device_id *id)
354{
355 struct lm3630_platform_data *pdata = client->dev.platform_data;
356 struct lm3630_chip_data *pchip;
357 int ret;
358
359 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
360 dev_err(&client->dev, "fail : i2c functionality check...\n");
361 return -EOPNOTSUPP;
362 }
363
364 if (pdata == NULL) {
365 dev_err(&client->dev, "fail : no platform data.\n");
366 return -ENODATA;
367 }
368
369 pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630_chip_data),
370 GFP_KERNEL);
371 if (!pchip)
372 return -ENOMEM;
373 pchip->pdata = pdata;
374 pchip->dev = &client->dev;
375
376 pchip->regmap = devm_regmap_init_i2c(client, &lm3630_regmap);
377 if (IS_ERR(pchip->regmap)) {
378 ret = PTR_ERR(pchip->regmap);
379 dev_err(&client->dev, "fail : allocate register map: %d\n",
380 ret);
381 return ret;
382 }
383 i2c_set_clientdata(client, pchip);
384
385 /* chip initialize */
386 ret = lm3630_chip_init(pchip);
387 if (ret < 0) {
388 dev_err(&client->dev, "fail : init chip\n");
389 goto err_chip_init;
390 }
391
392 switch (pdata->bank_a_ctrl) {
393 case BANK_A_CTRL_ALL:
394 ret = lm3630_backlight_register(pchip, BLED_ALL);
395 pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE;
396 break;
397 case BANK_A_CTRL_LED1:
398 ret = lm3630_backlight_register(pchip, BLED_1);
399 break;
400 case BANK_A_CTRL_LED2:
401 ret = lm3630_backlight_register(pchip, BLED_2);
402 pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE;
403 break;
404 default:
405 break;
406 }
407
408 if (ret < 0)
409 goto err_bl_reg;
410
411 if (pdata->bank_b_ctrl && pchip->bled2 == NULL) {
412 ret = lm3630_backlight_register(pchip, BLED_2);
413 if (ret < 0)
414 goto err_bl_reg;
415 }
416
417 /* interrupt enable : irq 0 is not allowed for lm3630 */
418 pchip->irq = client->irq;
419 if (pchip->irq)
420 lm3630_intr_config(pchip);
421
422 dev_info(&client->dev, "LM3630 backlight register OK.\n");
423 return 0;
424
425err_bl_reg:
426 dev_err(&client->dev, "fail : backlight register.\n");
427 lm3630_backlight_unregister(pchip);
428err_chip_init:
429 return ret;
430}
431
432static int lm3630_remove(struct i2c_client *client)
433{
434 int ret;
435 struct lm3630_chip_data *pchip = i2c_get_clientdata(client);
436
437 ret = regmap_write(pchip->regmap, REG_BRT_A, 0);
438 if (ret < 0)
439 dev_err(pchip->dev, "i2c failed to access register\n");
440
441 ret = regmap_write(pchip->regmap, REG_BRT_B, 0);
442 if (ret < 0)
443 dev_err(pchip->dev, "i2c failed to access register\n");
444
445 lm3630_backlight_unregister(pchip);
446 if (pchip->irq) {
447 free_irq(pchip->irq, pchip);
448 flush_workqueue(pchip->irqthread);
449 destroy_workqueue(pchip->irqthread);
450 }
451 return 0;
452}
453
454static const struct i2c_device_id lm3630_id[] = {
455 {LM3630_NAME, 0},
456 {}
457};
458
459MODULE_DEVICE_TABLE(i2c, lm3630_id);
460
461static struct i2c_driver lm3630_i2c_driver = {
462 .driver = {
463 .name = LM3630_NAME,
464 },
465 .probe = lm3630_probe,
466 .remove = lm3630_remove,
467 .id_table = lm3630_id,
468};
469
470module_i2c_driver(lm3630_i2c_driver);
471
472MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630");
473MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
474MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
475MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c
new file mode 100644
index 000000000000..cf40cc8e662b
--- /dev/null
+++ b/drivers/video/backlight/lm3630a_bl.c
@@ -0,0 +1,483 @@
1/*
2* Simple driver for Texas Instruments LM3630A Backlight driver chip
3* Copyright (C) 2012 Texas Instruments
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License version 2 as
7* published by the Free Software Foundation.
8*
9*/
10#include <linux/module.h>
11#include <linux/slab.h>
12#include <linux/i2c.h>
13#include <linux/backlight.h>
14#include <linux/err.h>
15#include <linux/delay.h>
16#include <linux/uaccess.h>
17#include <linux/interrupt.h>
18#include <linux/regmap.h>
19#include <linux/pwm.h>
20#include <linux/platform_data/lm3630a_bl.h>
21
22#define REG_CTRL 0x00
23#define REG_BOOST 0x02
24#define REG_CONFIG 0x01
25#define REG_BRT_A 0x03
26#define REG_BRT_B 0x04
27#define REG_I_A 0x05
28#define REG_I_B 0x06
29#define REG_INT_STATUS 0x09
30#define REG_INT_EN 0x0A
31#define REG_FAULT 0x0B
32#define REG_PWM_OUTLOW 0x12
33#define REG_PWM_OUTHIGH 0x13
34#define REG_MAX 0x1F
35
36#define INT_DEBOUNCE_MSEC 10
37struct lm3630a_chip {
38 struct device *dev;
39 struct delayed_work work;
40
41 int irq;
42 struct workqueue_struct *irqthread;
43 struct lm3630a_platform_data *pdata;
44 struct backlight_device *bleda;
45 struct backlight_device *bledb;
46 struct regmap *regmap;
47 struct pwm_device *pwmd;
48};
49
50/* i2c access */
51static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg)
52{
53 int rval;
54 unsigned int reg_val;
55
56 rval = regmap_read(pchip->regmap, reg, &reg_val);
57 if (rval < 0)
58 return rval;
59 return reg_val & 0xFF;
60}
61
62static int lm3630a_write(struct lm3630a_chip *pchip,
63 unsigned int reg, unsigned int data)
64{
65 return regmap_write(pchip->regmap, reg, data);
66}
67
68static int lm3630a_update(struct lm3630a_chip *pchip,
69 unsigned int reg, unsigned int mask,
70 unsigned int data)
71{
72 return regmap_update_bits(pchip->regmap, reg, mask, data);
73}
74
75/* initialize chip */
76static int lm3630a_chip_init(struct lm3630a_chip *pchip)
77{
78 int rval;
79 struct lm3630a_platform_data *pdata = pchip->pdata;
80
81 usleep_range(1000, 2000);
82 /* set Filter Strength Register */
83 rval = lm3630a_write(pchip, 0x50, 0x03);
84 /* set Cofig. register */
85 rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl);
86 /* set boost control */
87 rval |= lm3630a_write(pchip, REG_BOOST, 0x38);
88 /* set current A */
89 rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F);
90 /* set current B */
91 rval |= lm3630a_write(pchip, REG_I_B, 0x1F);
92 /* set control */
93 rval |=
94 lm3630a_write(pchip, REG_CTRL, pdata->leda_ctrl | pdata->ledb_ctrl);
95 usleep_range(1000, 2000);
96 /* set brightness A and B */
97 rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt);
98 rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt);
99
100 if (rval < 0)
101 dev_err(pchip->dev, "i2c failed to access register\n");
102 return rval;
103}
104
105/* interrupt handling */
106static void lm3630a_delayed_func(struct work_struct *work)
107{
108 unsigned int rval;
109 struct lm3630a_chip *pchip;
110
111 pchip = container_of(work, struct lm3630a_chip, work.work);
112
113 rval = lm3630a_read(pchip, REG_INT_STATUS);
114 if (rval < 0) {
115 dev_err(pchip->dev,
116 "i2c failed to access REG_INT_STATUS Register\n");
117 return;
118 }
119
120 dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval);
121}
122
123static irqreturn_t lm3630a_isr_func(int irq, void *chip)
124{
125 int rval;
126 struct lm3630a_chip *pchip = chip;
127 unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC);
128
129 queue_delayed_work(pchip->irqthread, &pchip->work, delay);
130
131 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
132 if (rval < 0) {
133 dev_err(pchip->dev, "i2c failed to access register\n");
134 return IRQ_NONE;
135 }
136 return IRQ_HANDLED;
137}
138
139static int lm3630a_intr_config(struct lm3630a_chip *pchip)
140{
141 int rval;
142
143 rval = lm3630a_write(pchip, REG_INT_EN, 0x87);
144 if (rval < 0)
145 return rval;
146
147 INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func);
148 pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd");
149 if (!pchip->irqthread) {
150 dev_err(pchip->dev, "create irq thread fail\n");
151 return -ENOMEM;
152 }
153 if (request_threaded_irq
154 (pchip->irq, NULL, lm3630a_isr_func,
155 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) {
156 dev_err(pchip->dev, "request threaded irq fail\n");
157 return -ENOMEM;
158 }
159 return rval;
160}
161
162static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
163{
164 unsigned int period = pwm_get_period(pchip->pwmd);
165 unsigned int duty = br * period / br_max;
166
167 pwm_config(pchip->pwmd, duty, period);
168 if (duty)
169 pwm_enable(pchip->pwmd);
170 else
171 pwm_disable(pchip->pwmd);
172}
173
174/* update and get brightness */
175static int lm3630a_bank_a_update_status(struct backlight_device *bl)
176{
177 int ret;
178 struct lm3630a_chip *pchip = bl_get_data(bl);
179 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
180
181 /* pwm control */
182 if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
183 lm3630a_pwm_ctrl(pchip, bl->props.brightness,
184 bl->props.max_brightness);
185 return bl->props.brightness;
186 }
187
188 /* disable sleep */
189 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
190 if (ret < 0)
191 goto out_i2c_err;
192 usleep_range(1000, 2000);
193 /* minimum brightness is 0x04 */
194 ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness);
195 if (bl->props.brightness < 0x4)
196 ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0);
197 else
198 ret |= lm3630a_update(pchip, REG_CTRL,
199 LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE);
200 if (ret < 0)
201 goto out_i2c_err;
202 return bl->props.brightness;
203
204out_i2c_err:
205 dev_err(pchip->dev, "i2c failed to access\n");
206 return bl->props.brightness;
207}
208
209static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
210{
211 int brightness, rval;
212 struct lm3630a_chip *pchip = bl_get_data(bl);
213 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
214
215 if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
216 rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);
217 if (rval < 0)
218 goto out_i2c_err;
219 brightness = (rval & 0x01) << 8;
220 rval = lm3630a_read(pchip, REG_PWM_OUTLOW);
221 if (rval < 0)
222 goto out_i2c_err;
223 brightness |= rval;
224 goto out;
225 }
226
227 /* disable sleep */
228 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
229 if (rval < 0)
230 goto out_i2c_err;
231 usleep_range(1000, 2000);
232 rval = lm3630a_read(pchip, REG_BRT_A);
233 if (rval < 0)
234 goto out_i2c_err;
235 brightness = rval;
236
237out:
238 bl->props.brightness = brightness;
239 return bl->props.brightness;
240out_i2c_err:
241 dev_err(pchip->dev, "i2c failed to access register\n");
242 return 0;
243}
244
245static const struct backlight_ops lm3630a_bank_a_ops = {
246 .options = BL_CORE_SUSPENDRESUME,
247 .update_status = lm3630a_bank_a_update_status,
248 .get_brightness = lm3630a_bank_a_get_brightness,
249};
250
251/* update and get brightness */
252static int lm3630a_bank_b_update_status(struct backlight_device *bl)
253{
254 int ret;
255 struct lm3630a_chip *pchip = bl_get_data(bl);
256 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
257
258 /* pwm control */
259 if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
260 lm3630a_pwm_ctrl(pchip, bl->props.brightness,
261 bl->props.max_brightness);
262 return bl->props.brightness;
263 }
264
265 /* disable sleep */
266 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
267 if (ret < 0)
268 goto out_i2c_err;
269 usleep_range(1000, 2000);
270 /* minimum brightness is 0x04 */
271 ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness);
272 if (bl->props.brightness < 0x4)
273 ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0);
274 else
275 ret |= lm3630a_update(pchip, REG_CTRL,
276 LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE);
277 if (ret < 0)
278 goto out_i2c_err;
279 return bl->props.brightness;
280
281out_i2c_err:
282 dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
283 return bl->props.brightness;
284}
285
286static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
287{
288 int brightness, rval;
289 struct lm3630a_chip *pchip = bl_get_data(bl);
290 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
291
292 if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
293 rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);
294 if (rval < 0)
295 goto out_i2c_err;
296 brightness = (rval & 0x01) << 8;
297 rval = lm3630a_read(pchip, REG_PWM_OUTLOW);
298 if (rval < 0)
299 goto out_i2c_err;
300 brightness |= rval;
301 goto out;
302 }
303
304 /* disable sleep */
305 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
306 if (rval < 0)
307 goto out_i2c_err;
308 usleep_range(1000, 2000);
309 rval = lm3630a_read(pchip, REG_BRT_B);
310 if (rval < 0)
311 goto out_i2c_err;
312 brightness = rval;
313
314out:
315 bl->props.brightness = brightness;
316 return bl->props.brightness;
317out_i2c_err:
318 dev_err(pchip->dev, "i2c failed to access register\n");
319 return 0;
320}
321
322static const struct backlight_ops lm3630a_bank_b_ops = {
323 .options = BL_CORE_SUSPENDRESUME,
324 .update_status = lm3630a_bank_b_update_status,
325 .get_brightness = lm3630a_bank_b_get_brightness,
326};
327
328static int lm3630a_backlight_register(struct lm3630a_chip *pchip)
329{
330 struct backlight_properties props;
331 struct lm3630a_platform_data *pdata = pchip->pdata;
332
333 props.type = BACKLIGHT_RAW;
334 if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) {
335 props.brightness = pdata->leda_init_brt;
336 props.max_brightness = pdata->leda_max_brt;
337 pchip->bleda =
338 devm_backlight_device_register(pchip->dev, "lm3630a_leda",
339 pchip->dev, pchip,
340 &lm3630a_bank_a_ops, &props);
341 if (IS_ERR(pchip->bleda))
342 return PTR_ERR(pchip->bleda);
343 }
344
345 if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) &&
346 (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) {
347 props.brightness = pdata->ledb_init_brt;
348 props.max_brightness = pdata->ledb_max_brt;
349 pchip->bledb =
350 devm_backlight_device_register(pchip->dev, "lm3630a_ledb",
351 pchip->dev, pchip,
352 &lm3630a_bank_b_ops, &props);
353 if (IS_ERR(pchip->bledb))
354 return PTR_ERR(pchip->bledb);
355 }
356 return 0;
357}
358
359static const struct regmap_config lm3630a_regmap = {
360 .reg_bits = 8,
361 .val_bits = 8,
362 .max_register = REG_MAX,
363};
364
365static int lm3630a_probe(struct i2c_client *client,
366 const struct i2c_device_id *id)
367{
368 struct lm3630a_platform_data *pdata = client->dev.platform_data;
369 struct lm3630a_chip *pchip;
370 int rval;
371
372 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
373 dev_err(&client->dev, "fail : i2c functionality check\n");
374 return -EOPNOTSUPP;
375 }
376
377 pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip),
378 GFP_KERNEL);
379 if (!pchip)
380 return -ENOMEM;
381 pchip->dev = &client->dev;
382
383 pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap);
384 if (IS_ERR(pchip->regmap)) {
385 rval = PTR_ERR(pchip->regmap);
386 dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval);
387 return rval;
388 }
389
390 i2c_set_clientdata(client, pchip);
391 if (pdata == NULL) {
392 pchip->pdata = devm_kzalloc(pchip->dev,
393 sizeof(struct
394 lm3630a_platform_data),
395 GFP_KERNEL);
396 if (pchip->pdata == NULL)
397 return -ENOMEM;
398 /* default values */
399 pchip->pdata->leda_ctrl = LM3630A_LEDA_ENABLE;
400 pchip->pdata->ledb_ctrl = LM3630A_LEDB_ENABLE;
401 pchip->pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS;
402 pchip->pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS;
403 pchip->pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS;
404 pchip->pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS;
405 } else {
406 pchip->pdata = pdata;
407 }
408 /* chip initialize */
409 rval = lm3630a_chip_init(pchip);
410 if (rval < 0) {
411 dev_err(&client->dev, "fail : init chip\n");
412 return rval;
413 }
414 /* backlight register */
415 rval = lm3630a_backlight_register(pchip);
416 if (rval < 0) {
417 dev_err(&client->dev, "fail : backlight register.\n");
418 return rval;
419 }
420 /* pwm */
421 if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) {
422 pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm");
423 if (IS_ERR(pchip->pwmd)) {
424 dev_err(&client->dev, "fail : get pwm device\n");
425 return PTR_ERR(pchip->pwmd);
426 }
427 }
428 pchip->pwmd->period = pdata->pwm_period;
429
430 /* interrupt enable : irq 0 is not allowed */
431 pchip->irq = client->irq;
432 if (pchip->irq) {
433 rval = lm3630a_intr_config(pchip);
434 if (rval < 0)
435 return rval;
436 }
437 dev_info(&client->dev, "LM3630A backlight register OK.\n");
438 return 0;
439}
440
441static int lm3630a_remove(struct i2c_client *client)
442{
443 int rval;
444 struct lm3630a_chip *pchip = i2c_get_clientdata(client);
445
446 rval = lm3630a_write(pchip, REG_BRT_A, 0);
447 if (rval < 0)
448 dev_err(pchip->dev, "i2c failed to access register\n");
449
450 rval = lm3630a_write(pchip, REG_BRT_B, 0);
451 if (rval < 0)
452 dev_err(pchip->dev, "i2c failed to access register\n");
453
454 if (pchip->irq) {
455 free_irq(pchip->irq, pchip);
456 flush_workqueue(pchip->irqthread);
457 destroy_workqueue(pchip->irqthread);
458 }
459 return 0;
460}
461
462static const struct i2c_device_id lm3630a_id[] = {
463 {LM3630A_NAME, 0},
464 {}
465};
466
467MODULE_DEVICE_TABLE(i2c, lm3630a_id);
468
469static struct i2c_driver lm3630a_i2c_driver = {
470 .driver = {
471 .name = LM3630A_NAME,
472 },
473 .probe = lm3630a_probe,
474 .remove = lm3630a_remove,
475 .id_table = lm3630a_id,
476};
477
478module_i2c_driver(lm3630a_i2c_driver);
479
480MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A");
481MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
482MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>");
483MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/lm3630_bl.h b/include/linux/platform_data/lm3630_bl.h
deleted file mode 100644
index 9176dd3f2d63..000000000000
--- a/include/linux/platform_data/lm3630_bl.h
+++ /dev/null
@@ -1,57 +0,0 @@
1/*
2* Simple driver for Texas Instruments LM3630 LED Flash driver chip
3* Copyright (C) 2012 Texas Instruments
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License version 2 as
7* published by the Free Software Foundation.
8*
9*/
10
11#ifndef __LINUX_LM3630_H
12#define __LINUX_LM3630_H
13
14#define LM3630_NAME "lm3630_bl"
15
16enum lm3630_pwm_ctrl {
17 PWM_CTRL_DISABLE = 0,
18 PWM_CTRL_BANK_A,
19 PWM_CTRL_BANK_B,
20 PWM_CTRL_BANK_ALL,
21};
22
23enum lm3630_pwm_active {
24 PWM_ACTIVE_HIGH = 0,
25 PWM_ACTIVE_LOW,
26};
27
28enum lm3630_bank_a_ctrl {
29 BANK_A_CTRL_DISABLE = 0x0,
30 BANK_A_CTRL_LED1 = 0x4,
31 BANK_A_CTRL_LED2 = 0x1,
32 BANK_A_CTRL_ALL = 0x5,
33};
34
35enum lm3630_bank_b_ctrl {
36 BANK_B_CTRL_DISABLE = 0,
37 BANK_B_CTRL_LED2,
38};
39
40struct lm3630_platform_data {
41
42 /* maximum brightness */
43 int max_brt_led1;
44 int max_brt_led2;
45
46 /* initial on brightness */
47 int init_brt_led1;
48 int init_brt_led2;
49 enum lm3630_pwm_ctrl pwm_ctrl;
50 enum lm3630_pwm_active pwm_active;
51 enum lm3630_bank_a_ctrl bank_a_ctrl;
52 enum lm3630_bank_b_ctrl bank_b_ctrl;
53 unsigned int pwm_period;
54 void (*pwm_set_intensity) (int brightness, int max_brightness);
55};
56
57#endif /* __LINUX_LM3630_H */
diff --git a/include/linux/platform_data/lm3630a_bl.h b/include/linux/platform_data/lm3630a_bl.h
new file mode 100644
index 000000000000..7538e38e270b
--- /dev/null
+++ b/include/linux/platform_data/lm3630a_bl.h
@@ -0,0 +1,65 @@
1/*
2* Simple driver for Texas Instruments LM3630A LED Flash driver chip
3* Copyright (C) 2012 Texas Instruments
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License version 2 as
7* published by the Free Software Foundation.
8*
9*/
10
11#ifndef __LINUX_LM3630A_H
12#define __LINUX_LM3630A_H
13
14#define LM3630A_NAME "lm3630a_bl"
15
16enum lm3630a_pwm_ctrl {
17 LM3630A_PWM_DISABLE = 0x00,
18 LM3630A_PWM_BANK_A,
19 LM3630A_PWM_BANK_B,
20 LM3630A_PWM_BANK_ALL,
21 LM3630A_PWM_BANK_A_ACT_LOW = 0x05,
22 LM3630A_PWM_BANK_B_ACT_LOW,
23 LM3630A_PWM_BANK_ALL_ACT_LOW,
24};
25
26enum lm3630a_leda_ctrl {
27 LM3630A_LEDA_DISABLE = 0x00,
28 LM3630A_LEDA_ENABLE = 0x04,
29 LM3630A_LEDA_ENABLE_LINEAR = 0x14,
30};
31
32enum lm3630a_ledb_ctrl {
33 LM3630A_LEDB_DISABLE = 0x00,
34 LM3630A_LEDB_ON_A = 0x01,
35 LM3630A_LEDB_ENABLE = 0x02,
36 LM3630A_LEDB_ENABLE_LINEAR = 0x0A,
37};
38
39#define LM3630A_MAX_BRIGHTNESS 255
40/*
41 *@leda_init_brt : led a init brightness. 4~255
42 *@leda_max_brt : led a max brightness. 4~255
43 *@leda_ctrl : led a disable, enable linear, enable exponential
44 *@ledb_init_brt : led b init brightness. 4~255
45 *@ledb_max_brt : led b max brightness. 4~255
46 *@ledb_ctrl : led b disable, enable linear, enable exponential
47 *@pwm_period : pwm period
48 *@pwm_ctrl : pwm disable, bank a or b, active high or low
49 */
50struct lm3630a_platform_data {
51
52 /* led a config. */
53 int leda_init_brt;
54 int leda_max_brt;
55 enum lm3630a_leda_ctrl leda_ctrl;
56 /* led b config. */
57 int ledb_init_brt;
58 int ledb_max_brt;
59 enum lm3630a_ledb_ctrl ledb_ctrl;
60 /* pwm config. */
61 unsigned int pwm_period;
62 enum lm3630a_pwm_ctrl pwm_ctrl;
63};
64
65#endif /* __LINUX_LM3630A_H */