c98bdbfdc697202a7bd584619d42f93dfb141361
[linux-2.6-block.git] / drivers / video / backlight / lp855x_bl.c
1 /*
2  * TI LP855x Backlight Driver
3  *
4  *                      Copyright (C) 2011 Texas Instruments
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  */
11
12 #include <linux/module.h>
13 #include <linux/slab.h>
14 #include <linux/i2c.h>
15 #include <linux/backlight.h>
16 #include <linux/err.h>
17 #include <linux/platform_data/lp855x.h>
18 #include <linux/pwm.h>
19
20 /* LP8550/1/2/3/6 Registers */
21 #define LP855X_BRIGHTNESS_CTRL          0x00
22 #define LP855X_DEVICE_CTRL              0x01
23 #define LP855X_EEPROM_START             0xA0
24 #define LP855X_EEPROM_END               0xA7
25 #define LP8556_EPROM_START              0xA0
26 #define LP8556_EPROM_END                0xAF
27
28 /* LP8557 Registers */
29 #define LP8557_BL_CMD                   0x00
30 #define LP8557_BL_MASK                  0x01
31 #define LP8557_BL_ON                    0x01
32 #define LP8557_BL_OFF                   0x00
33 #define LP8557_BRIGHTNESS_CTRL          0x04
34 #define LP8557_CONFIG                   0x10
35 #define LP8557_EPROM_START              0x10
36 #define LP8557_EPROM_END                0x1E
37
38 #define DEFAULT_BL_NAME         "lcd-backlight"
39 #define MAX_BRIGHTNESS          255
40
41 struct lp855x;
42
43 /*
44  * struct lp855x_device_config
45  * @pre_init_device: init device function call before updating the brightness
46  * @reg_brightness: register address for brigthenss control
47  * @reg_devicectrl: register address for device control
48  * @post_init_device: late init device function call
49  */
50 struct lp855x_device_config {
51         int (*pre_init_device)(struct lp855x *);
52         u8 reg_brightness;
53         u8 reg_devicectrl;
54         int (*post_init_device)(struct lp855x *);
55 };
56
57 struct lp855x {
58         const char *chipname;
59         enum lp855x_chip_id chip_id;
60         struct lp855x_device_config *cfg;
61         struct i2c_client *client;
62         struct backlight_device *bl;
63         struct device *dev;
64         struct lp855x_platform_data *pdata;
65         struct pwm_device *pwm;
66 };
67
68 static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data)
69 {
70         return i2c_smbus_write_byte_data(lp->client, reg, data);
71 }
72
73 static int lp855x_update_bit(struct lp855x *lp, u8 reg, u8 mask, u8 data)
74 {
75         int ret;
76         u8 tmp;
77
78         ret = i2c_smbus_read_byte_data(lp->client, reg);
79         if (ret < 0) {
80                 dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
81                 return ret;
82         }
83
84         tmp = (u8)ret;
85         tmp &= ~mask;
86         tmp |= data & mask;
87
88         return lp855x_write_byte(lp, reg, tmp);
89 }
90
91 static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
92 {
93         u8 start, end;
94
95         switch (lp->chip_id) {
96         case LP8550:
97         case LP8551:
98         case LP8552:
99         case LP8553:
100                 start = LP855X_EEPROM_START;
101                 end = LP855X_EEPROM_END;
102                 break;
103         case LP8556:
104                 start = LP8556_EPROM_START;
105                 end = LP8556_EPROM_END;
106                 break;
107         case LP8557:
108                 start = LP8557_EPROM_START;
109                 end = LP8557_EPROM_END;
110                 break;
111         default:
112                 return false;
113         }
114
115         return (addr >= start && addr <= end);
116 }
117
118 static int lp8557_bl_off(struct lp855x *lp)
119 {
120         /* BL_ON = 0 before updating EPROM settings */
121         return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
122                                 LP8557_BL_OFF);
123 }
124
125 static int lp8557_bl_on(struct lp855x *lp)
126 {
127         /* BL_ON = 1 after updating EPROM settings */
128         return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
129                                 LP8557_BL_ON);
130 }
131
132 static struct lp855x_device_config lp855x_dev_cfg = {
133         .reg_brightness = LP855X_BRIGHTNESS_CTRL,
134         .reg_devicectrl = LP855X_DEVICE_CTRL,
135 };
136
137 static struct lp855x_device_config lp8557_dev_cfg = {
138         .reg_brightness = LP8557_BRIGHTNESS_CTRL,
139         .reg_devicectrl = LP8557_CONFIG,
140         .pre_init_device = lp8557_bl_off,
141         .post_init_device = lp8557_bl_on,
142 };
143
144 /*
145  * Device specific configuration flow
146  *
147  *    a) pre_init_device(optional)
148  *    b) update the brightness register
149  *    c) update device control register
150  *    d) update ROM area(optional)
151  *    e) post_init_device(optional)
152  *
153  */
154 static int lp855x_configure(struct lp855x *lp)
155 {
156         u8 val, addr;
157         int i, ret;
158         struct lp855x_platform_data *pd = lp->pdata;
159
160         switch (lp->chip_id) {
161         case LP8550 ... LP8556:
162                 lp->cfg = &lp855x_dev_cfg;
163                 break;
164         case LP8557:
165                 lp->cfg = &lp8557_dev_cfg;
166                 break;
167         default:
168                 return -EINVAL;
169         }
170
171         if (lp->cfg->pre_init_device) {
172                 ret = lp->cfg->pre_init_device(lp);
173                 if (ret) {
174                         dev_err(lp->dev, "pre init device err: %d\n", ret);
175                         goto err;
176                 }
177         }
178
179         val = pd->initial_brightness;
180         ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
181         if (ret)
182                 goto err;
183
184         val = pd->device_control;
185         ret = lp855x_write_byte(lp, lp->cfg->reg_devicectrl, val);
186         if (ret)
187                 goto err;
188
189         if (pd->load_new_rom_data && pd->size_program) {
190                 for (i = 0; i < pd->size_program; i++) {
191                         addr = pd->rom_data[i].addr;
192                         val = pd->rom_data[i].val;
193                         if (!lp855x_is_valid_rom_area(lp, addr))
194                                 continue;
195
196                         ret = lp855x_write_byte(lp, addr, val);
197                         if (ret)
198                                 goto err;
199                 }
200         }
201
202         if (lp->cfg->post_init_device) {
203                 ret = lp->cfg->post_init_device(lp);
204                 if (ret) {
205                         dev_err(lp->dev, "post init device err: %d\n", ret);
206                         goto err;
207                 }
208         }
209
210         return 0;
211
212 err:
213         return ret;
214 }
215
216 static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br)
217 {
218         unsigned int period = lp->pdata->period_ns;
219         unsigned int duty = br * period / max_br;
220         struct pwm_device *pwm;
221
222         /* request pwm device with the consumer name */
223         if (!lp->pwm) {
224                 pwm = devm_pwm_get(lp->dev, lp->chipname);
225                 if (IS_ERR(pwm))
226                         return;
227
228                 lp->pwm = pwm;
229         }
230
231         pwm_config(lp->pwm, duty, period);
232         if (duty)
233                 pwm_enable(lp->pwm);
234         else
235                 pwm_disable(lp->pwm);
236 }
237
238 static int lp855x_bl_update_status(struct backlight_device *bl)
239 {
240         struct lp855x *lp = bl_get_data(bl);
241         enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
242
243         if (bl->props.state & BL_CORE_SUSPENDED)
244                 bl->props.brightness = 0;
245
246         if (mode == PWM_BASED) {
247                 int br = bl->props.brightness;
248                 int max_br = bl->props.max_brightness;
249
250                 lp855x_pwm_ctrl(lp, br, max_br);
251
252         } else if (mode == REGISTER_BASED) {
253                 u8 val = bl->props.brightness;
254                 lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
255         }
256
257         return 0;
258 }
259
260 static int lp855x_bl_get_brightness(struct backlight_device *bl)
261 {
262         return bl->props.brightness;
263 }
264
265 static const struct backlight_ops lp855x_bl_ops = {
266         .options = BL_CORE_SUSPENDRESUME,
267         .update_status = lp855x_bl_update_status,
268         .get_brightness = lp855x_bl_get_brightness,
269 };
270
271 static int lp855x_backlight_register(struct lp855x *lp)
272 {
273         struct backlight_device *bl;
274         struct backlight_properties props;
275         struct lp855x_platform_data *pdata = lp->pdata;
276         char *name = pdata->name ? : DEFAULT_BL_NAME;
277
278         props.type = BACKLIGHT_PLATFORM;
279         props.max_brightness = MAX_BRIGHTNESS;
280
281         if (pdata->initial_brightness > props.max_brightness)
282                 pdata->initial_brightness = props.max_brightness;
283
284         props.brightness = pdata->initial_brightness;
285
286         bl = backlight_device_register(name, lp->dev, lp,
287                                        &lp855x_bl_ops, &props);
288         if (IS_ERR(bl))
289                 return PTR_ERR(bl);
290
291         lp->bl = bl;
292
293         return 0;
294 }
295
296 static void lp855x_backlight_unregister(struct lp855x *lp)
297 {
298         if (lp->bl)
299                 backlight_device_unregister(lp->bl);
300 }
301
302 static ssize_t lp855x_get_chip_id(struct device *dev,
303                                 struct device_attribute *attr, char *buf)
304 {
305         struct lp855x *lp = dev_get_drvdata(dev);
306         return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
307 }
308
309 static ssize_t lp855x_get_bl_ctl_mode(struct device *dev,
310                                      struct device_attribute *attr, char *buf)
311 {
312         struct lp855x *lp = dev_get_drvdata(dev);
313         enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
314         char *strmode = NULL;
315
316         if (mode == PWM_BASED)
317                 strmode = "pwm based";
318         else if (mode == REGISTER_BASED)
319                 strmode = "register based";
320
321         return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
322 }
323
324 static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL);
325 static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp855x_get_bl_ctl_mode, NULL);
326
327 static struct attribute *lp855x_attributes[] = {
328         &dev_attr_chip_id.attr,
329         &dev_attr_bl_ctl_mode.attr,
330         NULL,
331 };
332
333 static const struct attribute_group lp855x_attr_group = {
334         .attrs = lp855x_attributes,
335 };
336
337 static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
338 {
339         struct lp855x *lp;
340         struct lp855x_platform_data *pdata = cl->dev.platform_data;
341         int ret;
342
343         if (!pdata) {
344                 dev_err(&cl->dev, "no platform data supplied\n");
345                 return -EINVAL;
346         }
347
348         if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
349                 return -EIO;
350
351         lp = devm_kzalloc(&cl->dev, sizeof(struct lp855x), GFP_KERNEL);
352         if (!lp)
353                 return -ENOMEM;
354
355         lp->client = cl;
356         lp->dev = &cl->dev;
357         lp->pdata = pdata;
358         lp->chipname = id->name;
359         lp->chip_id = id->driver_data;
360         i2c_set_clientdata(cl, lp);
361
362         ret = lp855x_configure(lp);
363         if (ret) {
364                 dev_err(lp->dev, "device config err: %d", ret);
365                 goto err_dev;
366         }
367
368         ret = lp855x_backlight_register(lp);
369         if (ret) {
370                 dev_err(lp->dev,
371                         "failed to register backlight. err: %d\n", ret);
372                 goto err_dev;
373         }
374
375         ret = sysfs_create_group(&lp->dev->kobj, &lp855x_attr_group);
376         if (ret) {
377                 dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret);
378                 goto err_sysfs;
379         }
380
381         backlight_update_status(lp->bl);
382         return 0;
383
384 err_sysfs:
385         lp855x_backlight_unregister(lp);
386 err_dev:
387         return ret;
388 }
389
390 static int lp855x_remove(struct i2c_client *cl)
391 {
392         struct lp855x *lp = i2c_get_clientdata(cl);
393
394         lp->bl->props.brightness = 0;
395         backlight_update_status(lp->bl);
396         sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);
397         lp855x_backlight_unregister(lp);
398
399         return 0;
400 }
401
402 static const struct i2c_device_id lp855x_ids[] = {
403         {"lp8550", LP8550},
404         {"lp8551", LP8551},
405         {"lp8552", LP8552},
406         {"lp8553", LP8553},
407         {"lp8556", LP8556},
408         {"lp8557", LP8557},
409         { }
410 };
411 MODULE_DEVICE_TABLE(i2c, lp855x_ids);
412
413 static struct i2c_driver lp855x_driver = {
414         .driver = {
415                    .name = "lp855x",
416                    },
417         .probe = lp855x_probe,
418         .remove = lp855x_remove,
419         .id_table = lp855x_ids,
420 };
421
422 module_i2c_driver(lp855x_driver);
423
424 MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
425 MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
426 MODULE_LICENSE("GPL");