2 * Simple driver for Texas Instruments LM3630 Backlight driver chip
3 * Copyright (C) 2012 Texas Instruments
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.
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>
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
32 #define INT_DEBOUNCE_MSEC 10
40 static 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 */
46 struct lm3630_chip_data
{
48 struct delayed_work work
;
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
;
58 static int lm3630_chip_init(struct lm3630_chip_data
*pchip
)
62 struct lm3630_platform_data
*pdata
= pchip
->pdata
;
65 reg_val
= ((pdata
->pwm_active
& 0x01) << 2) | (pdata
->pwm_ctrl
& 0x03);
66 ret
= regmap_update_bits(pchip
->regmap
, REG_CONFIG
, 0x07, reg_val
);
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
);
77 ret
= regmap_update_bits(pchip
->regmap
, REG_CTRL
, 0x80, 0x00);
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
);
89 if (pdata
->bank_b_ctrl
!= BANK_B_CTRL_DISABLE
) {
90 ret
= regmap_write(pchip
->regmap
,
91 REG_BRT_B
, pdata
->init_brt_led2
);
98 dev_err(pchip
->dev
, "i2c failed to access register\n");
102 /* interrupt handling */
103 static void lm3630_delayed_func(struct work_struct
*work
)
106 unsigned int reg_val
;
107 struct lm3630_chip_data
*pchip
;
109 pchip
= container_of(work
, struct lm3630_chip_data
, work
.work
);
111 ret
= regmap_read(pchip
->regmap
, REG_INT_STATUS
, ®_val
);
114 "i2c failed to access REG_INT_STATUS Register\n");
118 dev_info(pchip
->dev
, "REG_INT_STATUS Register is 0x%x\n", reg_val
);
121 static irqreturn_t
lm3630_isr_func(int irq
, void *chip
)
124 struct lm3630_chip_data
*pchip
= chip
;
125 unsigned long delay
= msecs_to_jiffies(INT_DEBOUNCE_MSEC
);
127 queue_delayed_work(pchip
->irqthread
, &pchip
->work
, delay
);
129 ret
= regmap_update_bits(pchip
->regmap
, REG_CTRL
, 0x80, 0x00);
135 dev_err(pchip
->dev
, "i2c failed to access register\n");
139 static int lm3630_intr_config(struct lm3630_chip_data
*pchip
)
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");
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");
157 set_intensity(struct backlight_device
*bl
, struct lm3630_chip_data
*pchip
)
159 if (!pchip
->pdata
->pwm_set_intensity
)
161 pchip
->pdata
->pwm_set_intensity(bl
->props
.brightness
- 1,
162 pchip
->pdata
->pwm_period
);
166 /* update and get brightness */
167 static int lm3630_bank_a_update_status(struct backlight_device
*bl
)
170 struct lm3630_chip_data
*pchip
= bl_get_data(bl
);
171 enum lm3630_pwm_ctrl pwm_ctrl
= pchip
->pdata
->pwm_ctrl
;
173 /* brightness 0 means disable */
174 if (!bl
->props
.brightness
) {
175 ret
= regmap_update_bits(pchip
->regmap
, REG_CTRL
, 0x04, 0x00);
178 return bl
->props
.brightness
;
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");
188 ret
= regmap_update_bits(pchip
->regmap
, REG_CTRL
, 0x80, 0x00);
192 ret
= regmap_write(pchip
->regmap
,
193 REG_BRT_A
, bl
->props
.brightness
- 1);
197 return bl
->props
.brightness
;
199 dev_err(pchip
->dev
, "i2c failed to access REG_CTRL\n");
200 return bl
->props
.brightness
;
203 static int lm3630_bank_a_get_brightness(struct backlight_device
*bl
)
205 unsigned int reg_val
;
207 struct lm3630_chip_data
*pchip
= bl_get_data(bl
);
208 enum lm3630_pwm_ctrl pwm_ctrl
= pchip
->pdata
->pwm_ctrl
;
210 if (pwm_ctrl
== PWM_CTRL_BANK_A
|| pwm_ctrl
== PWM_CTRL_BANK_ALL
) {
211 ret
= regmap_read(pchip
->regmap
, REG_PWM_OUTHIGH
, ®_val
);
214 brightness
= reg_val
& 0x01;
215 ret
= regmap_read(pchip
->regmap
, REG_PWM_OUTLOW
, ®_val
);
218 brightness
= ((brightness
<< 8) | reg_val
) + 1;
220 ret
= regmap_update_bits(pchip
->regmap
, REG_CTRL
, 0x80, 0x00);
224 ret
= regmap_read(pchip
->regmap
, REG_BRT_A
, ®_val
);
227 brightness
= reg_val
+ 1;
229 bl
->props
.brightness
= brightness
;
230 return bl
->props
.brightness
;
232 dev_err(pchip
->dev
, "i2c failed to access register\n");
236 static 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
,
242 static int lm3630_bank_b_update_status(struct backlight_device
*bl
)
245 struct lm3630_chip_data
*pchip
= bl_get_data(bl
);
246 enum lm3630_pwm_ctrl pwm_ctrl
= pchip
->pdata
->pwm_ctrl
;
248 if (pwm_ctrl
== PWM_CTRL_BANK_B
|| pwm_ctrl
== PWM_CTRL_BANK_ALL
) {
249 if (!set_intensity(bl
, pchip
))
251 "no pwm control func. in plat-data\n");
253 ret
= regmap_update_bits(pchip
->regmap
, REG_CTRL
, 0x80, 0x00);
257 ret
= regmap_write(pchip
->regmap
,
258 REG_BRT_B
, bl
->props
.brightness
- 1);
260 return bl
->props
.brightness
;
262 dev_err(pchip
->dev
, "i2c failed to access register\n");
263 return bl
->props
.brightness
;
266 static int lm3630_bank_b_get_brightness(struct backlight_device
*bl
)
268 unsigned int reg_val
;
270 struct lm3630_chip_data
*pchip
= bl_get_data(bl
);
271 enum lm3630_pwm_ctrl pwm_ctrl
= pchip
->pdata
->pwm_ctrl
;
273 if (pwm_ctrl
== PWM_CTRL_BANK_B
|| pwm_ctrl
== PWM_CTRL_BANK_ALL
) {
274 ret
= regmap_read(pchip
->regmap
, REG_PWM_OUTHIGH
, ®_val
);
277 brightness
= reg_val
& 0x01;
278 ret
= regmap_read(pchip
->regmap
, REG_PWM_OUTLOW
, ®_val
);
281 brightness
= ((brightness
<< 8) | reg_val
) + 1;
283 ret
= regmap_update_bits(pchip
->regmap
, REG_CTRL
, 0x80, 0x00);
287 ret
= regmap_read(pchip
->regmap
, REG_BRT_B
, ®_val
);
290 brightness
= reg_val
+ 1;
292 bl
->props
.brightness
= brightness
;
294 return bl
->props
.brightness
;
296 dev_err(pchip
->dev
, "i2c failed to access register\n");
297 return bl
->props
.brightness
;
300 static 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
,
306 static int lm3630_backlight_register(struct lm3630_chip_data
*pchip
,
307 enum lm3630_leds ledno
)
309 const char *name
= bled_name
[ledno
];
310 struct backlight_properties props
;
311 struct lm3630_platform_data
*pdata
= pchip
->pdata
;
313 props
.type
= BACKLIGHT_RAW
;
317 props
.brightness
= pdata
->init_brt_led1
;
318 props
.max_brightness
= pdata
->max_brt_led1
;
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
);
326 props
.brightness
= pdata
->init_brt_led2
;
327 props
.max_brightness
= pdata
->max_brt_led2
;
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
);
338 static void lm3630_backlight_unregister(struct lm3630_chip_data
*pchip
)
341 backlight_device_unregister(pchip
->bled1
);
343 backlight_device_unregister(pchip
->bled2
);
346 static const struct regmap_config lm3630_regmap
= {
349 .max_register
= REG_MAX
,
352 static int lm3630_probe(struct i2c_client
*client
,
353 const struct i2c_device_id
*id
)
355 struct lm3630_platform_data
*pdata
= client
->dev
.platform_data
;
356 struct lm3630_chip_data
*pchip
;
359 if (!i2c_check_functionality(client
->adapter
, I2C_FUNC_I2C
)) {
360 dev_err(&client
->dev
, "fail : i2c functionality check...\n");
365 dev_err(&client
->dev
, "fail : no platform data.\n");
369 pchip
= devm_kzalloc(&client
->dev
, sizeof(struct lm3630_chip_data
),
373 pchip
->pdata
= pdata
;
374 pchip
->dev
= &client
->dev
;
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",
383 i2c_set_clientdata(client
, pchip
);
385 /* chip initialize */
386 ret
= lm3630_chip_init(pchip
);
388 dev_err(&client
->dev
, "fail : init chip\n");
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
;
397 case BANK_A_CTRL_LED1
:
398 ret
= lm3630_backlight_register(pchip
, BLED_1
);
400 case BANK_A_CTRL_LED2
:
401 ret
= lm3630_backlight_register(pchip
, BLED_2
);
402 pdata
->bank_b_ctrl
= BANK_B_CTRL_DISABLE
;
411 if (pdata
->bank_b_ctrl
&& pchip
->bled2
== NULL
) {
412 ret
= lm3630_backlight_register(pchip
, BLED_2
);
417 /* interrupt enable : irq 0 is not allowed for lm3630 */
418 pchip
->irq
= client
->irq
;
420 lm3630_intr_config(pchip
);
422 dev_info(&client
->dev
, "LM3630 backlight register OK.\n");
426 dev_err(&client
->dev
, "fail : backlight register.\n");
427 lm3630_backlight_unregister(pchip
);
432 static int lm3630_remove(struct i2c_client
*client
)
435 struct lm3630_chip_data
*pchip
= i2c_get_clientdata(client
);
437 ret
= regmap_write(pchip
->regmap
, REG_BRT_A
, 0);
439 dev_err(pchip
->dev
, "i2c failed to access register\n");
441 ret
= regmap_write(pchip
->regmap
, REG_BRT_B
, 0);
443 dev_err(pchip
->dev
, "i2c failed to access register\n");
445 lm3630_backlight_unregister(pchip
);
447 free_irq(pchip
->irq
, pchip
);
448 flush_workqueue(pchip
->irqthread
);
449 destroy_workqueue(pchip
->irqthread
);
454 static const struct i2c_device_id lm3630_id
[] = {
459 MODULE_DEVICE_TABLE(i2c
, lm3630_id
);
461 static struct i2c_driver lm3630_i2c_driver
= {
465 .probe
= lm3630_probe
,
466 .remove
= lm3630_remove
,
467 .id_table
= lm3630_id
,
470 module_i2c_driver(lm3630_i2c_driver
);
472 MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630");
473 MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
474 MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
475 MODULE_LICENSE("GPL v2");