Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lm3630_bl.c
Go to the documentation of this file.
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>
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 
35  BLED_ALL = 0,
38 };
39 
40 static const char *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 
47  struct device *dev;
49  int irq;
54  struct regmap *regmap;
55 };
56 
57 /* initialize chip */
58 static int __devinit 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 
97 out:
98  dev_err(pchip->dev, "i2c failed to access register\n");
99  return ret;
100 }
101 
102 /* interrupt handling */
103 static 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 
121 static 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;
134 out:
135  dev_err(pchip->dev, "i2c failed to access register\n");
136  return IRQ_HANDLED;
137 }
138 
139 static 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  }
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 
156 static bool
157 set_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 */
167 static 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;
198 out:
199  dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
200  return bl->props.brightness;
201 }
202 
203 static 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;
231 out:
232  dev_err(pchip->dev, "i2c failed to access register\n");
233  return 0;
234 }
235 
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,
240 };
241 
242 static 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;
261 out:
262  dev_err(pchip->dev, "i2c failed to access register\n");
263  return bl->props.brightness;
264 }
265 
266 static 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;
295 out:
296  dev_err(pchip->dev, "i2c failed to access register\n");
297  return bl->props.brightness;
298 }
299 
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,
304 };
305 
306 static 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 -EIO;
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 -EIO;
333  break;
334  }
335  return 0;
336 }
337 
338 static void lm3630_backlight_unregister(struct lm3630_chip_data *pchip)
339 {
340  if (pchip->bled1)
342  if (pchip->bled2)
344 }
345 
346 static const struct regmap_config lm3630_regmap = {
347  .reg_bits = 8,
348  .val_bits = 8,
349  .max_register = REG_MAX,
350 };
351 
352 static int __devinit 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);
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);
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 
425 err_bl_reg:
426  dev_err(&client->dev, "fail : backlight register.\n");
427  lm3630_backlight_unregister(pchip);
428 err_chip_init:
429  return ret;
430 }
431 
432 static int __devexit 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);
450  }
451  return 0;
452 }
453 
454 static const struct i2c_device_id lm3630_id[] = {
455  {LM3630_NAME, 0},
456  {}
457 };
458 
459 MODULE_DEVICE_TABLE(i2c, lm3630_id);
460 
461 static struct i2c_driver lm3630_i2c_driver = {
462  .driver = {
463  .name = LM3630_NAME,
464  },
465  .probe = lm3630_probe,
466  .remove = __devexit_p(lm3630_remove),
467  .id_table = lm3630_id,
468 };
469 
470 module_i2c_driver(lm3630_i2c_driver);
471 
472 MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630");
473 MODULE_AUTHOR("G.Shark Jeong <[email protected]>");
474 MODULE_AUTHOR("Daniel Jeong <[email protected]>");
475 MODULE_LICENSE("GPL v2");