aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */