blob: c98bdbfdc697202a7bd584619d42f93dfb141361 [file] [log] [blame]
Kim, Milo7be865a2012-03-23 15:02:01 -07001/*
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>
Kim, Milof7f95052012-07-30 14:40:53 -070017#include <linux/platform_data/lp855x.h>
Kim, Milo8cc97642012-12-17 16:00:43 -080018#include <linux/pwm.h>
Kim, Milo7be865a2012-03-23 15:02:01 -070019
Kim, Milo26e8ccc2013-02-21 16:44:06 -080020/* 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
Kim, Milo7be865a2012-03-23 15:02:01 -070037
Kim, Milo7be865a2012-03-23 15:02:01 -070038#define DEFAULT_BL_NAME "lcd-backlight"
39#define MAX_BRIGHTNESS 255
40
Kim, Milo68853bc2013-02-21 16:44:05 -080041struct 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 */
50struct 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
Kim, Milo7be865a2012-03-23 15:02:01 -070057struct lp855x {
58 const char *chipname;
59 enum lp855x_chip_id chip_id;
Kim, Milo68853bc2013-02-21 16:44:05 -080060 struct lp855x_device_config *cfg;
Kim, Milo7be865a2012-03-23 15:02:01 -070061 struct i2c_client *client;
62 struct backlight_device *bl;
63 struct device *dev;
Kim, Milo7be865a2012-03-23 15:02:01 -070064 struct lp855x_platform_data *pdata;
Kim, Milo8cc97642012-12-17 16:00:43 -080065 struct pwm_device *pwm;
Kim, Milo7be865a2012-03-23 15:02:01 -070066};
67
Kim, Milo7be865a2012-03-23 15:02:01 -070068static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data)
69{
Kim, Miloeaa4d022012-12-17 16:00:45 -080070 return i2c_smbus_write_byte_data(lp->client, reg, data);
Kim, Milo7be865a2012-03-23 15:02:01 -070071}
72
Kim, Milo26e8ccc2013-02-21 16:44:06 -080073static 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
Kim, Milo7be865a2012-03-23 15:02:01 -070091static 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:
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800100 start = LP855X_EEPROM_START;
101 end = LP855X_EEPROM_END;
Kim, Milo7be865a2012-03-23 15:02:01 -0700102 break;
103 case LP8556:
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800104 start = LP8556_EPROM_START;
105 end = LP8556_EPROM_END;
106 break;
107 case LP8557:
108 start = LP8557_EPROM_START;
109 end = LP8557_EPROM_END;
Kim, Milo7be865a2012-03-23 15:02:01 -0700110 break;
111 default:
112 return false;
113 }
114
115 return (addr >= start && addr <= end);
116}
117
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800118static 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
125static 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
Kim, Milo68853bc2013-02-21 16:44:05 -0800132static struct lp855x_device_config lp855x_dev_cfg = {
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800133 .reg_brightness = LP855X_BRIGHTNESS_CTRL,
134 .reg_devicectrl = LP855X_DEVICE_CTRL,
135};
136
137static 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,
Kim, Milo68853bc2013-02-21 16:44:05 -0800142};
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 */
154static int lp855x_configure(struct lp855x *lp)
Kim, Milo7be865a2012-03-23 15:02:01 -0700155{
156 u8 val, addr;
157 int i, ret;
158 struct lp855x_platform_data *pd = lp->pdata;
159
Kim, Milo68853bc2013-02-21 16:44:05 -0800160 switch (lp->chip_id) {
161 case LP8550 ... LP8556:
162 lp->cfg = &lp855x_dev_cfg;
163 break;
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800164 case LP8557:
165 lp->cfg = &lp8557_dev_cfg;
166 break;
Kim, Milo68853bc2013-02-21 16:44:05 -0800167 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
Kim, Milo7be865a2012-03-23 15:02:01 -0700179 val = pd->initial_brightness;
Kim, Milo68853bc2013-02-21 16:44:05 -0800180 ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
Kim, Milo7be865a2012-03-23 15:02:01 -0700181 if (ret)
Kim, Milo68853bc2013-02-21 16:44:05 -0800182 goto err;
Kim, Milo7be865a2012-03-23 15:02:01 -0700183
184 val = pd->device_control;
Kim, Milo68853bc2013-02-21 16:44:05 -0800185 ret = lp855x_write_byte(lp, lp->cfg->reg_devicectrl, val);
Kim, Milo7be865a2012-03-23 15:02:01 -0700186 if (ret)
Kim, Milo68853bc2013-02-21 16:44:05 -0800187 goto err;
Kim, Milo7be865a2012-03-23 15:02:01 -0700188
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)
Kim, Milo68853bc2013-02-21 16:44:05 -0800198 goto err;
Kim, Milo7be865a2012-03-23 15:02:01 -0700199 }
200 }
201
Kim, Milo68853bc2013-02-21 16:44:05 -0800202 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
212err:
Kim, Milo7be865a2012-03-23 15:02:01 -0700213 return ret;
214}
215
Kim, Milo8cc97642012-12-17 16:00:43 -0800216static 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
Kim, Milo7be865a2012-03-23 15:02:01 -0700238static 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) {
Kim, Milo7be865a2012-03-23 15:02:01 -0700247 int br = bl->props.brightness;
248 int max_br = bl->props.max_brightness;
249
Kim, Milo8cc97642012-12-17 16:00:43 -0800250 lp855x_pwm_ctrl(lp, br, max_br);
Kim, Milo7be865a2012-03-23 15:02:01 -0700251
252 } else if (mode == REGISTER_BASED) {
253 u8 val = bl->props.brightness;
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800254 lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
Kim, Milo7be865a2012-03-23 15:02:01 -0700255 }
256
257 return 0;
258}
259
260static int lp855x_bl_get_brightness(struct backlight_device *bl)
261{
Kim, Milo7be865a2012-03-23 15:02:01 -0700262 return bl->props.brightness;
263}
264
265static 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
271static 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
296static void lp855x_backlight_unregister(struct lp855x *lp)
297{
298 if (lp->bl)
299 backlight_device_unregister(lp->bl);
300}
301
302static 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);
Kim, Milo6a7aeb12013-04-29 16:17:52 -0700306 return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
Kim, Milo7be865a2012-03-23 15:02:01 -0700307}
308
309static 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
Kim, Milo6a7aeb12013-04-29 16:17:52 -0700321 return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
Kim, Milo7be865a2012-03-23 15:02:01 -0700322}
323
324static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL);
325static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp855x_get_bl_ctl_mode, NULL);
326
327static struct attribute *lp855x_attributes[] = {
328 &dev_attr_chip_id.attr,
329 &dev_attr_bl_ctl_mode.attr,
330 NULL,
331};
332
333static const struct attribute_group lp855x_attr_group = {
334 .attrs = lp855x_attributes,
335};
336
337static 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;
Kim, Milo7be865a2012-03-23 15:02:01 -0700341 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
Kim, Milo7be865a2012-03-23 15:02:01 -0700355 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
Kim, Milo68853bc2013-02-21 16:44:05 -0800362 ret = lp855x_configure(lp);
Kim, Milo7be865a2012-03-23 15:02:01 -0700363 if (ret) {
Kim, Milo68853bc2013-02-21 16:44:05 -0800364 dev_err(lp->dev, "device config err: %d", ret);
365 goto err_dev;
Kim, Milo7be865a2012-03-23 15:02:01 -0700366 }
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
384err_sysfs:
385 lp855x_backlight_unregister(lp);
386err_dev:
387 return ret;
388}
389
Bill Pemberton7e4b9d02012-11-19 13:26:34 -0500390static int lp855x_remove(struct i2c_client *cl)
Kim, Milo7be865a2012-03-23 15:02:01 -0700391{
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
402static const struct i2c_device_id lp855x_ids[] = {
403 {"lp8550", LP8550},
404 {"lp8551", LP8551},
405 {"lp8552", LP8552},
406 {"lp8553", LP8553},
407 {"lp8556", LP8556},
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800408 {"lp8557", LP8557},
Kim, Milo7be865a2012-03-23 15:02:01 -0700409 { }
410};
411MODULE_DEVICE_TABLE(i2c, lp855x_ids);
412
413static struct i2c_driver lp855x_driver = {
414 .driver = {
415 .name = "lp855x",
416 },
417 .probe = lp855x_probe,
Bill Pembertond1723fa2012-11-19 13:21:09 -0500418 .remove = lp855x_remove,
Kim, Milo7be865a2012-03-23 15:02:01 -0700419 .id_table = lp855x_ids,
420};
421
422module_i2c_driver(lp855x_driver);
423
424MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
425MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
426MODULE_LICENSE("GPL");