Merge tag 'acpi-fixes-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / video / backlight / lm3630_bl.c
CommitLineData
0c2a665a
SJ
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
d7b6bdaa 40static const char * const bled_name[] = {
0c2a665a
SJ
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 */
1b9e450d 58static int lm3630_chip_init(struct lm3630_chip_data *pchip)
0c2a665a
SJ
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))
5a429bdd 323 return PTR_ERR(pchip->bled1);
0c2a665a
SJ
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))
5a429bdd 332 return PTR_ERR(pchip->bled2);
0c2a665a
SJ
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
1b9e450d 352static int lm3630_probe(struct i2c_client *client,
0c2a665a
SJ
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
7e4b9d0b 432static int lm3630_remove(struct i2c_client *client)
0c2a665a
SJ
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,
d1723fa2 466 .remove = lm3630_remove,
0c2a665a
SJ
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");