Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
leds-lm3530.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 ST-Ericsson SA.
3  * Copyright (C) 2009 Motorola, Inc.
4  *
5  * License Terms: GNU General Public License v2
6  *
7  * Simple driver for National Semiconductor LM3530 Backlight driver chip
8  *
9  * Author: Shreshtha Kumar SAHU <[email protected]>
10  * based on leds-lm3530.c by Dan Murphy <[email protected]>
11  */
12 
13 #include <linux/i2c.h>
14 #include <linux/leds.h>
15 #include <linux/slab.h>
16 #include <linux/platform_device.h>
17 #include <linux/input.h>
18 #include <linux/led-lm3530.h>
19 #include <linux/types.h>
21 #include <linux/module.h>
22 
23 #define LM3530_LED_DEV "lcd-backlight"
24 #define LM3530_NAME "lm3530-led"
25 
26 #define LM3530_GEN_CONFIG 0x10
27 #define LM3530_ALS_CONFIG 0x20
28 #define LM3530_BRT_RAMP_RATE 0x30
29 #define LM3530_ALS_IMP_SELECT 0x41
30 #define LM3530_BRT_CTRL_REG 0xA0
31 #define LM3530_ALS_ZB0_REG 0x60
32 #define LM3530_ALS_ZB1_REG 0x61
33 #define LM3530_ALS_ZB2_REG 0x62
34 #define LM3530_ALS_ZB3_REG 0x63
35 #define LM3530_ALS_Z0T_REG 0x70
36 #define LM3530_ALS_Z1T_REG 0x71
37 #define LM3530_ALS_Z2T_REG 0x72
38 #define LM3530_ALS_Z3T_REG 0x73
39 #define LM3530_ALS_Z4T_REG 0x74
40 #define LM3530_REG_MAX 14
41 
42 /* General Control Register */
43 #define LM3530_EN_I2C_SHIFT (0)
44 #define LM3530_RAMP_LAW_SHIFT (1)
45 #define LM3530_MAX_CURR_SHIFT (2)
46 #define LM3530_EN_PWM_SHIFT (5)
47 #define LM3530_PWM_POL_SHIFT (6)
48 #define LM3530_EN_PWM_SIMPLE_SHIFT (7)
49 
50 #define LM3530_ENABLE_I2C (1 << LM3530_EN_I2C_SHIFT)
51 #define LM3530_ENABLE_PWM (1 << LM3530_EN_PWM_SHIFT)
52 #define LM3530_POL_LOW (1 << LM3530_PWM_POL_SHIFT)
53 #define LM3530_ENABLE_PWM_SIMPLE (1 << LM3530_EN_PWM_SIMPLE_SHIFT)
54 
55 /* ALS Config Register Options */
56 #define LM3530_ALS_AVG_TIME_SHIFT (0)
57 #define LM3530_EN_ALS_SHIFT (3)
58 #define LM3530_ALS_SEL_SHIFT (5)
59 
60 #define LM3530_ENABLE_ALS (3 << LM3530_EN_ALS_SHIFT)
61 
62 /* Brightness Ramp Rate Register */
63 #define LM3530_BRT_RAMP_FALL_SHIFT (0)
64 #define LM3530_BRT_RAMP_RISE_SHIFT (3)
65 
66 /* ALS Resistor Select */
67 #define LM3530_ALS1_IMP_SHIFT (0)
68 #define LM3530_ALS2_IMP_SHIFT (4)
69 
70 /* Zone Boundary Register defaults */
71 #define LM3530_ALS_ZB_MAX (4)
72 #define LM3530_ALS_WINDOW_mV (1000)
73 #define LM3530_ALS_OFFSET_mV (4)
74 
75 /* Zone Target Register defaults */
76 #define LM3530_DEF_ZT_0 (0x7F)
77 #define LM3530_DEF_ZT_1 (0x66)
78 #define LM3530_DEF_ZT_2 (0x4C)
79 #define LM3530_DEF_ZT_3 (0x33)
80 #define LM3530_DEF_ZT_4 (0x19)
81 
82 /* 7 bits are used for the brightness : LM3530_BRT_CTRL_REG */
83 #define MAX_BRIGHTNESS (127)
84 
86  const char *mode;
88 };
89 
90 static struct lm3530_mode_map mode_map[] = {
91  { "man", LM3530_BL_MODE_MANUAL },
92  { "als", LM3530_BL_MODE_ALS },
93  { "pwm", LM3530_BL_MODE_PWM },
94 };
95 
106 struct lm3530_data {
113  bool enable;
114 };
115 
116 /*
117  * struct lm3530_als_data
118  * @config : value of ALS configuration register
119  * @imp_sel : value of ALS resistor select register
120  * @zone : values of ALS ZB(Zone Boundary) registers
121  */
126 };
127 
128 static const u8 lm3530_reg[LM3530_REG_MAX] = {
143 };
144 
145 static int lm3530_get_mode_from_str(const char *str)
146 {
147  int i;
148 
149  for (i = 0; i < ARRAY_SIZE(mode_map); i++)
150  if (sysfs_streq(str, mode_map[i].mode))
151  return mode_map[i].mode_val;
152 
153  return -EINVAL;
154 }
155 
156 static void lm3530_als_configure(struct lm3530_platform_data *pdata,
157  struct lm3530_als_data *als)
158 {
159  int i;
160  u32 als_vmin, als_vmax, als_vstep;
161 
162  if (pdata->als_vmax == 0) {
163  pdata->als_vmin = 0;
165  }
166 
167  als_vmin = pdata->als_vmin;
168  als_vmax = pdata->als_vmax;
169 
170  if ((als_vmax - als_vmin) > LM3530_ALS_WINDOW_mV)
171  pdata->als_vmax = als_vmax = als_vmin + LM3530_ALS_WINDOW_mV;
172 
173  /* n zone boundary makes n+1 zones */
174  als_vstep = (als_vmax - als_vmin) / (LM3530_ALS_ZB_MAX + 1);
175 
176  for (i = 0; i < LM3530_ALS_ZB_MAX; i++)
177  als->zones[i] = (((als_vmin + LM3530_ALS_OFFSET_mV) +
178  als_vstep + (i * als_vstep)) * LED_FULL) / 1000;
179 
180  als->config =
184 
185  als->imp_sel =
188 }
189 
190 static int lm3530_init_registers(struct lm3530_data *drvdata)
191 {
192  int ret = 0;
193  int i;
194  u8 gen_config;
195  u8 brt_ramp;
196  u8 brightness;
198  struct lm3530_platform_data *pdata = drvdata->pdata;
199  struct i2c_client *client = drvdata->client;
200  struct lm3530_pwm_data *pwm = &pdata->pwm_data;
201  struct lm3530_als_data als;
202 
203  memset(&als, 0, sizeof(struct lm3530_als_data));
204 
205  gen_config = (pdata->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
206  ((pdata->max_current & 7) << LM3530_MAX_CURR_SHIFT);
207 
208  switch (drvdata->mode) {
210  gen_config |= LM3530_ENABLE_I2C;
211  break;
212  case LM3530_BL_MODE_ALS:
213  gen_config |= LM3530_ENABLE_I2C;
214  lm3530_als_configure(pdata, &als);
215  break;
216  case LM3530_BL_MODE_PWM:
218  (pdata->pwm_pol_hi << LM3530_PWM_POL_SHIFT);
219  break;
220  }
221 
222  brt_ramp = (pdata->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
224 
225  if (drvdata->brightness)
226  brightness = drvdata->brightness;
227  else
228  brightness = drvdata->brightness = pdata->brt_val;
229 
230  if (brightness > drvdata->led_dev.max_brightness)
231  brightness = drvdata->led_dev.max_brightness;
232 
233  reg_val[0] = gen_config; /* LM3530_GEN_CONFIG */
234  reg_val[1] = als.config; /* LM3530_ALS_CONFIG */
235  reg_val[2] = brt_ramp; /* LM3530_BRT_RAMP_RATE */
236  reg_val[3] = als.imp_sel; /* LM3530_ALS_IMP_SELECT */
237  reg_val[4] = brightness; /* LM3530_BRT_CTRL_REG */
238  reg_val[5] = als.zones[0]; /* LM3530_ALS_ZB0_REG */
239  reg_val[6] = als.zones[1]; /* LM3530_ALS_ZB1_REG */
240  reg_val[7] = als.zones[2]; /* LM3530_ALS_ZB2_REG */
241  reg_val[8] = als.zones[3]; /* LM3530_ALS_ZB3_REG */
242  reg_val[9] = LM3530_DEF_ZT_0; /* LM3530_ALS_Z0T_REG */
243  reg_val[10] = LM3530_DEF_ZT_1; /* LM3530_ALS_Z1T_REG */
244  reg_val[11] = LM3530_DEF_ZT_2; /* LM3530_ALS_Z2T_REG */
245  reg_val[12] = LM3530_DEF_ZT_3; /* LM3530_ALS_Z3T_REG */
246  reg_val[13] = LM3530_DEF_ZT_4; /* LM3530_ALS_Z4T_REG */
247 
248  if (!drvdata->enable) {
249  ret = regulator_enable(drvdata->regulator);
250  if (ret) {
251  dev_err(&drvdata->client->dev,
252  "Enable regulator failed\n");
253  return ret;
254  }
255  drvdata->enable = true;
256  }
257 
258  for (i = 0; i < LM3530_REG_MAX; i++) {
259  /* do not update brightness register when pwm mode */
260  if (lm3530_reg[i] == LM3530_BRT_CTRL_REG &&
261  drvdata->mode == LM3530_BL_MODE_PWM) {
262  if (pwm->pwm_set_intensity)
263  pwm->pwm_set_intensity(reg_val[i],
264  drvdata->led_dev.max_brightness);
265  continue;
266  }
267 
268  ret = i2c_smbus_write_byte_data(client,
269  lm3530_reg[i], reg_val[i]);
270  if (ret)
271  break;
272  }
273 
274  return ret;
275 }
276 
277 static void lm3530_brightness_set(struct led_classdev *led_cdev,
278  enum led_brightness brt_val)
279 {
280  int err;
281  struct lm3530_data *drvdata =
282  container_of(led_cdev, struct lm3530_data, led_dev);
283  struct lm3530_platform_data *pdata = drvdata->pdata;
284  struct lm3530_pwm_data *pwm = &pdata->pwm_data;
285  u8 max_brightness = led_cdev->max_brightness;
286 
287  switch (drvdata->mode) {
289 
290  if (!drvdata->enable) {
291  err = lm3530_init_registers(drvdata);
292  if (err) {
293  dev_err(&drvdata->client->dev,
294  "Register Init failed: %d\n", err);
295  break;
296  }
297  }
298 
299  /* set the brightness in brightness control register*/
300  err = i2c_smbus_write_byte_data(drvdata->client,
301  LM3530_BRT_CTRL_REG, brt_val);
302  if (err)
303  dev_err(&drvdata->client->dev,
304  "Unable to set brightness: %d\n", err);
305  else
306  drvdata->brightness = brt_val;
307 
308  if (brt_val == 0) {
309  err = regulator_disable(drvdata->regulator);
310  if (err)
311  dev_err(&drvdata->client->dev,
312  "Disable regulator failed\n");
313  drvdata->enable = false;
314  }
315  break;
316  case LM3530_BL_MODE_ALS:
317  break;
318  case LM3530_BL_MODE_PWM:
319  if (pwm->pwm_set_intensity)
320  pwm->pwm_set_intensity(brt_val, max_brightness);
321  break;
322  default:
323  break;
324  }
325 }
326 
327 static ssize_t lm3530_mode_get(struct device *dev,
328  struct device_attribute *attr, char *buf)
329 {
330  struct led_classdev *led_cdev = dev_get_drvdata(dev);
331  struct lm3530_data *drvdata;
332  int i, len = 0;
333 
334  drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
335  for (i = 0; i < ARRAY_SIZE(mode_map); i++)
336  if (drvdata->mode == mode_map[i].mode_val)
337  len += sprintf(buf + len, "[%s] ", mode_map[i].mode);
338  else
339  len += sprintf(buf + len, "%s ", mode_map[i].mode);
340 
341  len += sprintf(buf + len, "\n");
342 
343  return len;
344 }
345 
346 static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
347  *attr, const char *buf, size_t size)
348 {
349  struct led_classdev *led_cdev = dev_get_drvdata(dev);
350  struct lm3530_data *drvdata;
351  struct lm3530_pwm_data *pwm;
352  u8 max_brightness;
353  int mode, err;
354 
355  drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
356  pwm = &drvdata->pdata->pwm_data;
357  max_brightness = led_cdev->max_brightness;
358  mode = lm3530_get_mode_from_str(buf);
359  if (mode < 0) {
360  dev_err(dev, "Invalid mode\n");
361  return mode;
362  }
363 
364  drvdata->mode = mode;
365 
366  /* set pwm to low if unnecessary */
367  if (mode != LM3530_BL_MODE_PWM && pwm->pwm_set_intensity)
368  pwm->pwm_set_intensity(0, max_brightness);
369 
370  err = lm3530_init_registers(drvdata);
371  if (err) {
372  dev_err(dev, "Setting %s Mode failed :%d\n", buf, err);
373  return err;
374  }
375 
376  return sizeof(drvdata->mode);
377 }
378 static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set);
379 
380 static int __devinit lm3530_probe(struct i2c_client *client,
381  const struct i2c_device_id *id)
382 {
383  struct lm3530_platform_data *pdata = client->dev.platform_data;
384  struct lm3530_data *drvdata;
385  int err = 0;
386 
387  if (pdata == NULL) {
388  dev_err(&client->dev, "platform data required\n");
389  return -ENODEV;
390  }
391 
392  /* BL mode */
393  if (pdata->mode > LM3530_BL_MODE_PWM) {
394  dev_err(&client->dev, "Illegal Mode request\n");
395  return -EINVAL;
396  }
397 
398  if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
399  dev_err(&client->dev, "I2C_FUNC_I2C not supported\n");
400  return -EIO;
401  }
402 
403  drvdata = devm_kzalloc(&client->dev, sizeof(struct lm3530_data),
404  GFP_KERNEL);
405  if (drvdata == NULL)
406  return -ENOMEM;
407 
408  drvdata->mode = pdata->mode;
409  drvdata->client = client;
410  drvdata->pdata = pdata;
411  drvdata->brightness = LED_OFF;
412  drvdata->enable = false;
413  drvdata->led_dev.name = LM3530_LED_DEV;
414  drvdata->led_dev.brightness_set = lm3530_brightness_set;
415  drvdata->led_dev.max_brightness = MAX_BRIGHTNESS;
416 
417  i2c_set_clientdata(client, drvdata);
418 
419  drvdata->regulator = devm_regulator_get(&client->dev, "vin");
420  if (IS_ERR(drvdata->regulator)) {
421  dev_err(&client->dev, "regulator get failed\n");
422  err = PTR_ERR(drvdata->regulator);
423  drvdata->regulator = NULL;
424  return err;
425  }
426 
427  if (drvdata->pdata->brt_val) {
428  err = lm3530_init_registers(drvdata);
429  if (err < 0) {
430  dev_err(&client->dev,
431  "Register Init failed: %d\n", err);
432  return err;
433  }
434  }
435  err = led_classdev_register(&client->dev, &drvdata->led_dev);
436  if (err < 0) {
437  dev_err(&client->dev, "Register led class failed: %d\n", err);
438  return err;
439  }
440 
441  err = device_create_file(drvdata->led_dev.dev, &dev_attr_mode);
442  if (err < 0) {
443  dev_err(&client->dev, "File device creation failed: %d\n", err);
444  err = -ENODEV;
445  goto err_create_file;
446  }
447 
448  return 0;
449 
450 err_create_file:
451  led_classdev_unregister(&drvdata->led_dev);
452  return err;
453 }
454 
455 static int __devexit lm3530_remove(struct i2c_client *client)
456 {
457  struct lm3530_data *drvdata = i2c_get_clientdata(client);
458 
459  device_remove_file(drvdata->led_dev.dev, &dev_attr_mode);
460 
461  if (drvdata->enable)
462  regulator_disable(drvdata->regulator);
463  led_classdev_unregister(&drvdata->led_dev);
464  return 0;
465 }
466 
467 static const struct i2c_device_id lm3530_id[] = {
468  {LM3530_NAME, 0},
469  {}
470 };
471 MODULE_DEVICE_TABLE(i2c, lm3530_id);
472 
473 static struct i2c_driver lm3530_i2c_driver = {
474  .probe = lm3530_probe,
475  .remove = __devexit_p(lm3530_remove),
476  .id_table = lm3530_id,
477  .driver = {
478  .name = LM3530_NAME,
479  .owner = THIS_MODULE,
480  },
481 };
482 
483 module_i2c_driver(lm3530_i2c_driver);
484 
485 MODULE_DESCRIPTION("Back Light driver for LM3530");
486 MODULE_LICENSE("GPL v2");
487 MODULE_AUTHOR("Shreshtha Kumar SAHU <[email protected]>");