Merge branch 'modsplit-Oct31_2011' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / leds / leds-lm3530.c
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 <shreshthakumar.sahu@stericsson.com>
10  * based on leds-lm3530.c by Dan Murphy <D.Murphy@motorola.com>
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>
20 #include <linux/regulator/consumer.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_ZONE_REG             0x40
30 #define LM3530_ALS_IMP_SELECT           0x41
31 #define LM3530_BRT_CTRL_REG             0xA0
32 #define LM3530_ALS_ZB0_REG              0x60
33 #define LM3530_ALS_ZB1_REG              0x61
34 #define LM3530_ALS_ZB2_REG              0x62
35 #define LM3530_ALS_ZB3_REG              0x63
36 #define LM3530_ALS_Z0T_REG              0x70
37 #define LM3530_ALS_Z1T_REG              0x71
38 #define LM3530_ALS_Z2T_REG              0x72
39 #define LM3530_ALS_Z3T_REG              0x73
40 #define LM3530_ALS_Z4T_REG              0x74
41 #define LM3530_REG_MAX                  15
42
43 /* General Control Register */
44 #define LM3530_EN_I2C_SHIFT             (0)
45 #define LM3530_RAMP_LAW_SHIFT           (1)
46 #define LM3530_MAX_CURR_SHIFT           (2)
47 #define LM3530_EN_PWM_SHIFT             (5)
48 #define LM3530_PWM_POL_SHIFT            (6)
49 #define LM3530_EN_PWM_SIMPLE_SHIFT      (7)
50
51 #define LM3530_ENABLE_I2C               (1 << LM3530_EN_I2C_SHIFT)
52 #define LM3530_ENABLE_PWM               (1 << LM3530_EN_PWM_SHIFT)
53 #define LM3530_POL_LOW                  (1 << LM3530_PWM_POL_SHIFT)
54 #define LM3530_ENABLE_PWM_SIMPLE        (1 << LM3530_EN_PWM_SIMPLE_SHIFT)
55
56 /* ALS Config Register Options */
57 #define LM3530_ALS_AVG_TIME_SHIFT       (0)
58 #define LM3530_EN_ALS_SHIFT             (3)
59 #define LM3530_ALS_SEL_SHIFT            (5)
60
61 #define LM3530_ENABLE_ALS               (3 << LM3530_EN_ALS_SHIFT)
62
63 /* Brightness Ramp Rate Register */
64 #define LM3530_BRT_RAMP_FALL_SHIFT      (0)
65 #define LM3530_BRT_RAMP_RISE_SHIFT      (3)
66
67 /* ALS Resistor Select */
68 #define LM3530_ALS1_IMP_SHIFT           (0)
69 #define LM3530_ALS2_IMP_SHIFT           (4)
70
71 /* Zone Boundary Register defaults */
72 #define LM3530_ALS_ZB_MAX               (4)
73 #define LM3530_ALS_WINDOW_mV            (1000)
74 #define LM3530_ALS_OFFSET_mV            (4)
75
76 /* Zone Target Register defaults */
77 #define LM3530_DEF_ZT_0                 (0x7F)
78 #define LM3530_DEF_ZT_1                 (0x66)
79 #define LM3530_DEF_ZT_2                 (0x4C)
80 #define LM3530_DEF_ZT_3                 (0x33)
81 #define LM3530_DEF_ZT_4                 (0x19)
82
83 struct lm3530_mode_map {
84         const char *mode;
85         enum lm3530_mode mode_val;
86 };
87
88 static struct lm3530_mode_map mode_map[] = {
89         { "man", LM3530_BL_MODE_MANUAL },
90         { "als", LM3530_BL_MODE_ALS },
91         { "pwm", LM3530_BL_MODE_PWM },
92 };
93
94 /**
95  * struct lm3530_data
96  * @led_dev: led class device
97  * @client: i2c client
98  * @pdata: LM3530 platform data
99  * @mode: mode of operation - manual, ALS, PWM
100  * @regulator: regulator
101  * @brighness: previous brightness value
102  * @enable: regulator is enabled
103  */
104 struct lm3530_data {
105         struct led_classdev led_dev;
106         struct i2c_client *client;
107         struct lm3530_platform_data *pdata;
108         enum lm3530_mode mode;
109         struct regulator *regulator;
110         enum led_brightness brightness;
111         bool enable;
112 };
113
114 static const u8 lm3530_reg[LM3530_REG_MAX] = {
115         LM3530_GEN_CONFIG,
116         LM3530_ALS_CONFIG,
117         LM3530_BRT_RAMP_RATE,
118         LM3530_ALS_ZONE_REG,
119         LM3530_ALS_IMP_SELECT,
120         LM3530_BRT_CTRL_REG,
121         LM3530_ALS_ZB0_REG,
122         LM3530_ALS_ZB1_REG,
123         LM3530_ALS_ZB2_REG,
124         LM3530_ALS_ZB3_REG,
125         LM3530_ALS_Z0T_REG,
126         LM3530_ALS_Z1T_REG,
127         LM3530_ALS_Z2T_REG,
128         LM3530_ALS_Z3T_REG,
129         LM3530_ALS_Z4T_REG,
130 };
131
132 static int lm3530_get_mode_from_str(const char *str)
133 {
134         int i;
135
136         for (i = 0; i < ARRAY_SIZE(mode_map); i++)
137                 if (sysfs_streq(str, mode_map[i].mode))
138                         return mode_map[i].mode_val;
139
140         return -1;
141 }
142
143 static int lm3530_init_registers(struct lm3530_data *drvdata)
144 {
145         int ret = 0;
146         int i;
147         u8 gen_config;
148         u8 als_config = 0;
149         u8 brt_ramp;
150         u8 als_imp_sel = 0;
151         u8 brightness;
152         u8 reg_val[LM3530_REG_MAX];
153         u8 zones[LM3530_ALS_ZB_MAX];
154         u32 als_vmin, als_vmax, als_vstep;
155         struct lm3530_platform_data *pltfm = drvdata->pdata;
156         struct i2c_client *client = drvdata->client;
157
158         gen_config = (pltfm->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
159                         ((pltfm->max_current & 7) << LM3530_MAX_CURR_SHIFT);
160
161         if (drvdata->mode == LM3530_BL_MODE_MANUAL ||
162             drvdata->mode == LM3530_BL_MODE_ALS)
163                 gen_config |= (LM3530_ENABLE_I2C);
164
165         if (drvdata->mode == LM3530_BL_MODE_ALS) {
166                 if (pltfm->als_vmax == 0) {
167                         pltfm->als_vmin = als_vmin = 0;
168                         pltfm->als_vmin = als_vmax = LM3530_ALS_WINDOW_mV;
169                 }
170
171                 als_vmin = pltfm->als_vmin;
172                 als_vmax = pltfm->als_vmax;
173
174                 if ((als_vmax - als_vmin) > LM3530_ALS_WINDOW_mV)
175                         pltfm->als_vmax = als_vmax =
176                                 als_vmin + LM3530_ALS_WINDOW_mV;
177
178                 /* n zone boundary makes n+1 zones */
179                 als_vstep = (als_vmax - als_vmin) / (LM3530_ALS_ZB_MAX + 1);
180
181                 for (i = 0; i < LM3530_ALS_ZB_MAX; i++)
182                         zones[i] = (((als_vmin + LM3530_ALS_OFFSET_mV) +
183                                         als_vstep + (i * als_vstep)) * LED_FULL)
184                                         / 1000;
185
186                 als_config =
187                         (pltfm->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
188                         (LM3530_ENABLE_ALS) |
189                         (pltfm->als_input_mode << LM3530_ALS_SEL_SHIFT);
190
191                 als_imp_sel =
192                         (pltfm->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
193                         (pltfm->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
194
195         }
196
197         if (drvdata->mode == LM3530_BL_MODE_PWM)
198                 gen_config |= (LM3530_ENABLE_PWM) |
199                                 (pltfm->pwm_pol_hi << LM3530_PWM_POL_SHIFT) |
200                                 (LM3530_ENABLE_PWM_SIMPLE);
201
202         brt_ramp = (pltfm->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
203                         (pltfm->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
204
205         if (drvdata->brightness)
206                 brightness = drvdata->brightness;
207         else
208                 brightness = drvdata->brightness = pltfm->brt_val;
209
210         reg_val[0] = gen_config;        /* LM3530_GEN_CONFIG */
211         reg_val[1] = als_config;        /* LM3530_ALS_CONFIG */
212         reg_val[2] = brt_ramp;          /* LM3530_BRT_RAMP_RATE */
213         reg_val[3] = 0x00;              /* LM3530_ALS_ZONE_REG */
214         reg_val[4] = als_imp_sel;       /* LM3530_ALS_IMP_SELECT */
215         reg_val[5] = brightness;        /* LM3530_BRT_CTRL_REG */
216         reg_val[6] = zones[0];          /* LM3530_ALS_ZB0_REG */
217         reg_val[7] = zones[1];          /* LM3530_ALS_ZB1_REG */
218         reg_val[8] = zones[2];          /* LM3530_ALS_ZB2_REG */
219         reg_val[9] = zones[3];          /* LM3530_ALS_ZB3_REG */
220         reg_val[10] = LM3530_DEF_ZT_0;  /* LM3530_ALS_Z0T_REG */
221         reg_val[11] = LM3530_DEF_ZT_1;  /* LM3530_ALS_Z1T_REG */
222         reg_val[12] = LM3530_DEF_ZT_2;  /* LM3530_ALS_Z2T_REG */
223         reg_val[13] = LM3530_DEF_ZT_3;  /* LM3530_ALS_Z3T_REG */
224         reg_val[14] = LM3530_DEF_ZT_4;  /* LM3530_ALS_Z4T_REG */
225
226         if (!drvdata->enable) {
227                 ret = regulator_enable(drvdata->regulator);
228                 if (ret) {
229                         dev_err(&drvdata->client->dev,
230                                         "Enable regulator failed\n");
231                         return ret;
232                 }
233                 drvdata->enable = true;
234         }
235
236         for (i = 0; i < LM3530_REG_MAX; i++) {
237                 ret = i2c_smbus_write_byte_data(client,
238                                 lm3530_reg[i], reg_val[i]);
239                 if (ret)
240                         break;
241         }
242
243         return ret;
244 }
245
246 static void lm3530_brightness_set(struct led_classdev *led_cdev,
247                                      enum led_brightness brt_val)
248 {
249         int err;
250         struct lm3530_data *drvdata =
251             container_of(led_cdev, struct lm3530_data, led_dev);
252
253         switch (drvdata->mode) {
254         case LM3530_BL_MODE_MANUAL:
255
256                 if (!drvdata->enable) {
257                         err = lm3530_init_registers(drvdata);
258                         if (err) {
259                                 dev_err(&drvdata->client->dev,
260                                         "Register Init failed: %d\n", err);
261                                 break;
262                         }
263                 }
264
265                 /* set the brightness in brightness control register*/
266                 err = i2c_smbus_write_byte_data(drvdata->client,
267                                 LM3530_BRT_CTRL_REG, brt_val / 2);
268                 if (err)
269                         dev_err(&drvdata->client->dev,
270                                 "Unable to set brightness: %d\n", err);
271                 else
272                         drvdata->brightness = brt_val / 2;
273
274                 if (brt_val == 0) {
275                         err = regulator_disable(drvdata->regulator);
276                         if (err)
277                                 dev_err(&drvdata->client->dev,
278                                         "Disable regulator failed\n");
279                         drvdata->enable = false;
280                 }
281                 break;
282         case LM3530_BL_MODE_ALS:
283                 break;
284         case LM3530_BL_MODE_PWM:
285                 break;
286         default:
287                 break;
288         }
289 }
290
291 static ssize_t lm3530_mode_get(struct device *dev,
292                 struct device_attribute *attr, char *buf)
293 {
294         struct i2c_client *client = container_of(
295                                         dev->parent, struct i2c_client, dev);
296         struct lm3530_data *drvdata = i2c_get_clientdata(client);
297         int i, len = 0;
298
299         for (i = 0; i < ARRAY_SIZE(mode_map); i++)
300                 if (drvdata->mode == mode_map[i].mode_val)
301                         len += sprintf(buf + len, "[%s] ", mode_map[i].mode);
302                 else
303                         len += sprintf(buf + len, "%s ", mode_map[i].mode);
304
305         len += sprintf(buf + len, "\n");
306
307         return len;
308 }
309
310 static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
311                                    *attr, const char *buf, size_t size)
312 {
313         int err;
314         struct i2c_client *client = container_of(
315                                         dev->parent, struct i2c_client, dev);
316         struct lm3530_data *drvdata = i2c_get_clientdata(client);
317         int mode;
318
319         mode = lm3530_get_mode_from_str(buf);
320         if (mode < 0) {
321                 dev_err(dev, "Invalid mode\n");
322                 return -EINVAL;
323         }
324
325         if (mode == LM3530_BL_MODE_MANUAL)
326                 drvdata->mode = LM3530_BL_MODE_MANUAL;
327         else if (mode == LM3530_BL_MODE_ALS)
328                 drvdata->mode = LM3530_BL_MODE_ALS;
329         else if (mode == LM3530_BL_MODE_PWM) {
330                 dev_err(dev, "PWM mode not supported\n");
331                 return -EINVAL;
332         }
333
334         err = lm3530_init_registers(drvdata);
335         if (err) {
336                 dev_err(dev, "Setting %s Mode failed :%d\n", buf, err);
337                 return err;
338         }
339
340         return sizeof(drvdata->mode);
341 }
342 static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set);
343
344 static int __devinit lm3530_probe(struct i2c_client *client,
345                            const struct i2c_device_id *id)
346 {
347         struct lm3530_platform_data *pdata = client->dev.platform_data;
348         struct lm3530_data *drvdata;
349         int err = 0;
350
351         if (pdata == NULL) {
352                 dev_err(&client->dev, "platform data required\n");
353                 err = -ENODEV;
354                 goto err_out;
355         }
356
357         /* BL mode */
358         if (pdata->mode > LM3530_BL_MODE_PWM) {
359                 dev_err(&client->dev, "Illegal Mode request\n");
360                 err = -EINVAL;
361                 goto err_out;
362         }
363
364         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
365                 dev_err(&client->dev, "I2C_FUNC_I2C not supported\n");
366                 err = -EIO;
367                 goto err_out;
368         }
369
370         drvdata = kzalloc(sizeof(struct lm3530_data), GFP_KERNEL);
371         if (drvdata == NULL) {
372                 err = -ENOMEM;
373                 goto err_out;
374         }
375
376         drvdata->mode = pdata->mode;
377         drvdata->client = client;
378         drvdata->pdata = pdata;
379         drvdata->brightness = LED_OFF;
380         drvdata->enable = false;
381         drvdata->led_dev.name = LM3530_LED_DEV;
382         drvdata->led_dev.brightness_set = lm3530_brightness_set;
383
384         i2c_set_clientdata(client, drvdata);
385
386         drvdata->regulator = regulator_get(&client->dev, "vin");
387         if (IS_ERR(drvdata->regulator)) {
388                 dev_err(&client->dev, "regulator get failed\n");
389                 err = PTR_ERR(drvdata->regulator);
390                 drvdata->regulator = NULL;
391                 goto err_regulator_get;
392         }
393
394         if (drvdata->pdata->brt_val) {
395                 err = lm3530_init_registers(drvdata);
396                 if (err < 0) {
397                         dev_err(&client->dev,
398                                 "Register Init failed: %d\n", err);
399                         err = -ENODEV;
400                         goto err_reg_init;
401                 }
402         }
403         err = led_classdev_register(&client->dev, &drvdata->led_dev);
404         if (err < 0) {
405                 dev_err(&client->dev, "Register led class failed: %d\n", err);
406                 err = -ENODEV;
407                 goto err_class_register;
408         }
409
410         err = device_create_file(drvdata->led_dev.dev, &dev_attr_mode);
411         if (err < 0) {
412                 dev_err(&client->dev, "File device creation failed: %d\n", err);
413                 err = -ENODEV;
414                 goto err_create_file;
415         }
416
417         return 0;
418
419 err_create_file:
420         led_classdev_unregister(&drvdata->led_dev);
421 err_class_register:
422 err_reg_init:
423         regulator_put(drvdata->regulator);
424 err_regulator_get:
425         kfree(drvdata);
426 err_out:
427         return err;
428 }
429
430 static int __devexit lm3530_remove(struct i2c_client *client)
431 {
432         struct lm3530_data *drvdata = i2c_get_clientdata(client);
433
434         device_remove_file(drvdata->led_dev.dev, &dev_attr_mode);
435
436         if (drvdata->enable)
437                 regulator_disable(drvdata->regulator);
438         regulator_put(drvdata->regulator);
439         led_classdev_unregister(&drvdata->led_dev);
440         kfree(drvdata);
441         return 0;
442 }
443
444 static const struct i2c_device_id lm3530_id[] = {
445         {LM3530_NAME, 0},
446         {}
447 };
448 MODULE_DEVICE_TABLE(i2c, lm3530_id);
449
450 static struct i2c_driver lm3530_i2c_driver = {
451         .probe = lm3530_probe,
452         .remove = __devexit_p(lm3530_remove),
453         .id_table = lm3530_id,
454         .driver = {
455                 .name = LM3530_NAME,
456                 .owner = THIS_MODULE,
457         },
458 };
459
460 static int __init lm3530_init(void)
461 {
462         return i2c_add_driver(&lm3530_i2c_driver);
463 }
464
465 static void __exit lm3530_exit(void)
466 {
467         i2c_del_driver(&lm3530_i2c_driver);
468 }
469
470 module_init(lm3530_init);
471 module_exit(lm3530_exit);
472
473 MODULE_DESCRIPTION("Back Light driver for LM3530");
474 MODULE_LICENSE("GPL v2");
475 MODULE_AUTHOR("Shreshtha Kumar SAHU <shreshthakumar.sahu@stericsson.com>");