1
2
3
4
5
6
7
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_FILTER_STRENGTH 0x50
35#define REG_MAX 0x50
36
37#define INT_DEBOUNCE_MSEC 10
38struct lm3630a_chip {
39 struct device *dev;
40 struct delayed_work work;
41
42 int irq;
43 struct workqueue_struct *irqthread;
44 struct lm3630a_platform_data *pdata;
45 struct backlight_device *bleda;
46 struct backlight_device *bledb;
47 struct regmap *regmap;
48 struct pwm_device *pwmd;
49};
50
51
52static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg)
53{
54 int rval;
55 unsigned int reg_val;
56
57 rval = regmap_read(pchip->regmap, reg, ®_val);
58 if (rval < 0)
59 return rval;
60 return reg_val & 0xFF;
61}
62
63static int lm3630a_write(struct lm3630a_chip *pchip,
64 unsigned int reg, unsigned int data)
65{
66 return regmap_write(pchip->regmap, reg, data);
67}
68
69static int lm3630a_update(struct lm3630a_chip *pchip,
70 unsigned int reg, unsigned int mask,
71 unsigned int data)
72{
73 return regmap_update_bits(pchip->regmap, reg, mask, data);
74}
75
76
77static int lm3630a_chip_init(struct lm3630a_chip *pchip)
78{
79 int rval;
80 struct lm3630a_platform_data *pdata = pchip->pdata;
81
82 usleep_range(1000, 2000);
83
84 rval = lm3630a_write(pchip, REG_FILTER_STRENGTH, 0x03);
85
86 rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl);
87
88 rval |= lm3630a_write(pchip, REG_BOOST, 0x38);
89
90 rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F);
91
92 rval |= lm3630a_write(pchip, REG_I_B, 0x1F);
93
94 rval |= lm3630a_update(pchip, REG_CTRL, 0x14, pdata->leda_ctrl);
95 rval |= lm3630a_update(pchip, REG_CTRL, 0x0B, pdata->ledb_ctrl);
96 usleep_range(1000, 2000);
97
98 rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt);
99 rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt);
100
101 if (rval < 0)
102 dev_err(pchip->dev, "i2c failed to access register\n");
103 return rval;
104}
105
106
107static void lm3630a_delayed_func(struct work_struct *work)
108{
109 int rval;
110 struct lm3630a_chip *pchip;
111
112 pchip = container_of(work, struct lm3630a_chip, work.work);
113
114 rval = lm3630a_read(pchip, REG_INT_STATUS);
115 if (rval < 0) {
116 dev_err(pchip->dev,
117 "i2c failed to access REG_INT_STATUS Register\n");
118 return;
119 }
120
121 dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval);
122}
123
124static irqreturn_t lm3630a_isr_func(int irq, void *chip)
125{
126 int rval;
127 struct lm3630a_chip *pchip = chip;
128 unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC);
129
130 queue_delayed_work(pchip->irqthread, &pchip->work, delay);
131
132 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
133 if (rval < 0) {
134 dev_err(pchip->dev, "i2c failed to access register\n");
135 return IRQ_NONE;
136 }
137 return IRQ_HANDLED;
138}
139
140static int lm3630a_intr_config(struct lm3630a_chip *pchip)
141{
142 int rval;
143
144 rval = lm3630a_write(pchip, REG_INT_EN, 0x87);
145 if (rval < 0)
146 return rval;
147
148 INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func);
149 pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd");
150 if (!pchip->irqthread) {
151 dev_err(pchip->dev, "create irq thread fail\n");
152 return -ENOMEM;
153 }
154 if (request_threaded_irq
155 (pchip->irq, NULL, lm3630a_isr_func,
156 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) {
157 dev_err(pchip->dev, "request threaded irq fail\n");
158 destroy_workqueue(pchip->irqthread);
159 return -ENOMEM;
160 }
161 return rval;
162}
163
164static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
165{
166 unsigned int period = pchip->pdata->pwm_period;
167 unsigned int duty = br * period / br_max;
168
169 pwm_config(pchip->pwmd, duty, period);
170 if (duty)
171 pwm_enable(pchip->pwmd);
172 else
173 pwm_disable(pchip->pwmd);
174}
175
176
177static int lm3630a_bank_a_update_status(struct backlight_device *bl)
178{
179 int ret;
180 struct lm3630a_chip *pchip = bl_get_data(bl);
181 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
182
183
184 if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
185 lm3630a_pwm_ctrl(pchip, bl->props.brightness,
186 bl->props.max_brightness);
187 return bl->props.brightness;
188 }
189
190
191 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
192 if (ret < 0)
193 goto out_i2c_err;
194 usleep_range(1000, 2000);
195
196 ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness);
197 if (bl->props.brightness < 0x4)
198 ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0);
199 else
200 ret |= lm3630a_update(pchip, REG_CTRL,
201 LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE);
202 if (ret < 0)
203 goto out_i2c_err;
204 return bl->props.brightness;
205
206out_i2c_err:
207 dev_err(pchip->dev, "i2c failed to access\n");
208 return bl->props.brightness;
209}
210
211static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
212{
213 int brightness, rval;
214 struct lm3630a_chip *pchip = bl_get_data(bl);
215 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
216
217 if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
218 rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);
219 if (rval < 0)
220 goto out_i2c_err;
221 brightness = (rval & 0x01) << 8;
222 rval = lm3630a_read(pchip, REG_PWM_OUTLOW);
223 if (rval < 0)
224 goto out_i2c_err;
225 brightness |= rval;
226 goto out;
227 }
228
229
230 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
231 if (rval < 0)
232 goto out_i2c_err;
233 usleep_range(1000, 2000);
234 rval = lm3630a_read(pchip, REG_BRT_A);
235 if (rval < 0)
236 goto out_i2c_err;
237 brightness = rval;
238
239out:
240 bl->props.brightness = brightness;
241 return bl->props.brightness;
242out_i2c_err:
243 dev_err(pchip->dev, "i2c failed to access register\n");
244 return 0;
245}
246
247static const struct backlight_ops lm3630a_bank_a_ops = {
248 .options = BL_CORE_SUSPENDRESUME,
249 .update_status = lm3630a_bank_a_update_status,
250 .get_brightness = lm3630a_bank_a_get_brightness,
251};
252
253
254static int lm3630a_bank_b_update_status(struct backlight_device *bl)
255{
256 int ret;
257 struct lm3630a_chip *pchip = bl_get_data(bl);
258 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
259
260
261 if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
262 lm3630a_pwm_ctrl(pchip, bl->props.brightness,
263 bl->props.max_brightness);
264 return bl->props.brightness;
265 }
266
267
268 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
269 if (ret < 0)
270 goto out_i2c_err;
271 usleep_range(1000, 2000);
272
273 ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness);
274 if (bl->props.brightness < 0x4)
275 ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0);
276 else
277 ret |= lm3630a_update(pchip, REG_CTRL,
278 LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE);
279 if (ret < 0)
280 goto out_i2c_err;
281 return bl->props.brightness;
282
283out_i2c_err:
284 dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
285 return bl->props.brightness;
286}
287
288static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
289{
290 int brightness, rval;
291 struct lm3630a_chip *pchip = bl_get_data(bl);
292 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
293
294 if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
295 rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);
296 if (rval < 0)
297 goto out_i2c_err;
298 brightness = (rval & 0x01) << 8;
299 rval = lm3630a_read(pchip, REG_PWM_OUTLOW);
300 if (rval < 0)
301 goto out_i2c_err;
302 brightness |= rval;
303 goto out;
304 }
305
306
307 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
308 if (rval < 0)
309 goto out_i2c_err;
310 usleep_range(1000, 2000);
311 rval = lm3630a_read(pchip, REG_BRT_B);
312 if (rval < 0)
313 goto out_i2c_err;
314 brightness = rval;
315
316out:
317 bl->props.brightness = brightness;
318 return bl->props.brightness;
319out_i2c_err:
320 dev_err(pchip->dev, "i2c failed to access register\n");
321 return 0;
322}
323
324static const struct backlight_ops lm3630a_bank_b_ops = {
325 .options = BL_CORE_SUSPENDRESUME,
326 .update_status = lm3630a_bank_b_update_status,
327 .get_brightness = lm3630a_bank_b_get_brightness,
328};
329
330static int lm3630a_backlight_register(struct lm3630a_chip *pchip)
331{
332 struct backlight_properties props;
333 struct lm3630a_platform_data *pdata = pchip->pdata;
334
335 props.type = BACKLIGHT_RAW;
336 if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) {
337 props.brightness = pdata->leda_init_brt;
338 props.max_brightness = pdata->leda_max_brt;
339 pchip->bleda =
340 devm_backlight_device_register(pchip->dev, "lm3630a_leda",
341 pchip->dev, pchip,
342 &lm3630a_bank_a_ops, &props);
343 if (IS_ERR(pchip->bleda))
344 return PTR_ERR(pchip->bleda);
345 }
346
347 if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) &&
348 (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) {
349 props.brightness = pdata->ledb_init_brt;
350 props.max_brightness = pdata->ledb_max_brt;
351 pchip->bledb =
352 devm_backlight_device_register(pchip->dev, "lm3630a_ledb",
353 pchip->dev, pchip,
354 &lm3630a_bank_b_ops, &props);
355 if (IS_ERR(pchip->bledb))
356 return PTR_ERR(pchip->bledb);
357 }
358 return 0;
359}
360
361static const struct regmap_config lm3630a_regmap = {
362 .reg_bits = 8,
363 .val_bits = 8,
364 .max_register = REG_MAX,
365};
366
367static int lm3630a_probe(struct i2c_client *client,
368 const struct i2c_device_id *id)
369{
370 struct lm3630a_platform_data *pdata = dev_get_platdata(&client->dev);
371 struct lm3630a_chip *pchip;
372 int rval;
373
374 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
375 dev_err(&client->dev, "fail : i2c functionality check\n");
376 return -EOPNOTSUPP;
377 }
378
379 pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip),
380 GFP_KERNEL);
381 if (!pchip)
382 return -ENOMEM;
383 pchip->dev = &client->dev;
384
385 pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap);
386 if (IS_ERR(pchip->regmap)) {
387 rval = PTR_ERR(pchip->regmap);
388 dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval);
389 return rval;
390 }
391
392 i2c_set_clientdata(client, pchip);
393 if (pdata == NULL) {
394 pdata = devm_kzalloc(pchip->dev,
395 sizeof(struct lm3630a_platform_data),
396 GFP_KERNEL);
397 if (pdata == NULL)
398 return -ENOMEM;
399
400 pdata->leda_ctrl = LM3630A_LEDA_ENABLE;
401 pdata->ledb_ctrl = LM3630A_LEDB_ENABLE;
402 pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS;
403 pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS;
404 pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS;
405 pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS;
406 }
407 pchip->pdata = pdata;
408
409
410 rval = lm3630a_chip_init(pchip);
411 if (rval < 0) {
412 dev_err(&client->dev, "fail : init chip\n");
413 return rval;
414 }
415
416 rval = lm3630a_backlight_register(pchip);
417 if (rval < 0) {
418 dev_err(&client->dev, "fail : backlight register.\n");
419 return rval;
420 }
421
422 if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) {
423 pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm");
424 if (IS_ERR(pchip->pwmd)) {
425 dev_err(&client->dev, "fail : get pwm device\n");
426 return PTR_ERR(pchip->pwmd);
427 }
428
429
430
431
432
433 pwm_apply_args(pchip->pwmd);
434 }
435
436
437 pchip->irq = client->irq;
438 if (pchip->irq) {
439 rval = lm3630a_intr_config(pchip);
440 if (rval < 0)
441 return rval;
442 }
443 dev_info(&client->dev, "LM3630A backlight register OK.\n");
444 return 0;
445}
446
447static int lm3630a_remove(struct i2c_client *client)
448{
449 int rval;
450 struct lm3630a_chip *pchip = i2c_get_clientdata(client);
451
452 rval = lm3630a_write(pchip, REG_BRT_A, 0);
453 if (rval < 0)
454 dev_err(pchip->dev, "i2c failed to access register\n");
455
456 rval = lm3630a_write(pchip, REG_BRT_B, 0);
457 if (rval < 0)
458 dev_err(pchip->dev, "i2c failed to access register\n");
459
460 if (pchip->irq) {
461 free_irq(pchip->irq, pchip);
462 flush_workqueue(pchip->irqthread);
463 destroy_workqueue(pchip->irqthread);
464 }
465 return 0;
466}
467
468static const struct i2c_device_id lm3630a_id[] = {
469 {LM3630A_NAME, 0},
470 {}
471};
472
473MODULE_DEVICE_TABLE(i2c, lm3630a_id);
474
475static struct i2c_driver lm3630a_i2c_driver = {
476 .driver = {
477 .name = LM3630A_NAME,
478 },
479 .probe = lm3630a_probe,
480 .remove = lm3630a_remove,
481 .id_table = lm3630a_id,
482};
483
484module_i2c_driver(lm3630a_i2c_driver);
485
486MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A");
487MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
488MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>");
489MODULE_LICENSE("GPL v2");
490