blob: edd2041b1527703de5346981f8a95de800ecde29 [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
38#define BUF_SIZE 20
39#define DEFAULT_BL_NAME "lcd-backlight"
40#define MAX_BRIGHTNESS 255
41
Kim, Milo68853bc2013-02-21 16:44:05 -080042struct lp855x;
43
44/*
45 * struct lp855x_device_config
46 * @pre_init_device: init device function call before updating the brightness
47 * @reg_brightness: register address for brigthenss control
48 * @reg_devicectrl: register address for device control
49 * @post_init_device: late init device function call
50 */
51struct lp855x_device_config {
52 int (*pre_init_device)(struct lp855x *);
53 u8 reg_brightness;
54 u8 reg_devicectrl;
55 int (*post_init_device)(struct lp855x *);
56};
57
Kim, Milo7be865a2012-03-23 15:02:01 -070058struct lp855x {
59 const char *chipname;
60 enum lp855x_chip_id chip_id;
Kim, Milo68853bc2013-02-21 16:44:05 -080061 struct lp855x_device_config *cfg;
Kim, Milo7be865a2012-03-23 15:02:01 -070062 struct i2c_client *client;
63 struct backlight_device *bl;
64 struct device *dev;
Kim, Milo7be865a2012-03-23 15:02:01 -070065 struct lp855x_platform_data *pdata;
Kim, Milo8cc97642012-12-17 16:00:43 -080066 struct pwm_device *pwm;
Kim, Milo7be865a2012-03-23 15:02:01 -070067};
68
69static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data)
70{
71 int ret;
72
Kim, Milo7be865a2012-03-23 15:02:01 -070073 ret = i2c_smbus_read_byte_data(lp->client, reg);
74 if (ret < 0) {
Kim, Milo7be865a2012-03-23 15:02:01 -070075 dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
76 return ret;
77 }
Kim, Milo7be865a2012-03-23 15:02:01 -070078
79 *data = (u8)ret;
80 return 0;
81}
82
83static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data)
84{
Kim, Miloeaa4d022012-12-17 16:00:45 -080085 return i2c_smbus_write_byte_data(lp->client, reg, data);
Kim, Milo7be865a2012-03-23 15:02:01 -070086}
87
Kim, Milo26e8ccc2013-02-21 16:44:06 -080088static int lp855x_update_bit(struct lp855x *lp, u8 reg, u8 mask, u8 data)
89{
90 int ret;
91 u8 tmp;
92
93 ret = i2c_smbus_read_byte_data(lp->client, reg);
94 if (ret < 0) {
95 dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
96 return ret;
97 }
98
99 tmp = (u8)ret;
100 tmp &= ~mask;
101 tmp |= data & mask;
102
103 return lp855x_write_byte(lp, reg, tmp);
104}
105
Kim, Milo7be865a2012-03-23 15:02:01 -0700106static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
107{
108 u8 start, end;
109
110 switch (lp->chip_id) {
111 case LP8550:
112 case LP8551:
113 case LP8552:
114 case LP8553:
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800115 start = LP855X_EEPROM_START;
116 end = LP855X_EEPROM_END;
Kim, Milo7be865a2012-03-23 15:02:01 -0700117 break;
118 case LP8556:
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800119 start = LP8556_EPROM_START;
120 end = LP8556_EPROM_END;
121 break;
122 case LP8557:
123 start = LP8557_EPROM_START;
124 end = LP8557_EPROM_END;
Kim, Milo7be865a2012-03-23 15:02:01 -0700125 break;
126 default:
127 return false;
128 }
129
130 return (addr >= start && addr <= end);
131}
132
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800133static int lp8557_bl_off(struct lp855x *lp)
134{
135 /* BL_ON = 0 before updating EPROM settings */
136 return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
137 LP8557_BL_OFF);
138}
139
140static int lp8557_bl_on(struct lp855x *lp)
141{
142 /* BL_ON = 1 after updating EPROM settings */
143 return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
144 LP8557_BL_ON);
145}
146
Kim, Milo68853bc2013-02-21 16:44:05 -0800147static struct lp855x_device_config lp855x_dev_cfg = {
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800148 .reg_brightness = LP855X_BRIGHTNESS_CTRL,
149 .reg_devicectrl = LP855X_DEVICE_CTRL,
150};
151
152static struct lp855x_device_config lp8557_dev_cfg = {
153 .reg_brightness = LP8557_BRIGHTNESS_CTRL,
154 .reg_devicectrl = LP8557_CONFIG,
155 .pre_init_device = lp8557_bl_off,
156 .post_init_device = lp8557_bl_on,
Kim, Milo68853bc2013-02-21 16:44:05 -0800157};
158
159/*
160 * Device specific configuration flow
161 *
162 * a) pre_init_device(optional)
163 * b) update the brightness register
164 * c) update device control register
165 * d) update ROM area(optional)
166 * e) post_init_device(optional)
167 *
168 */
169static int lp855x_configure(struct lp855x *lp)
Kim, Milo7be865a2012-03-23 15:02:01 -0700170{
171 u8 val, addr;
172 int i, ret;
173 struct lp855x_platform_data *pd = lp->pdata;
174
Kim, Milo68853bc2013-02-21 16:44:05 -0800175 switch (lp->chip_id) {
176 case LP8550 ... LP8556:
177 lp->cfg = &lp855x_dev_cfg;
178 break;
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800179 case LP8557:
180 lp->cfg = &lp8557_dev_cfg;
181 break;
Kim, Milo68853bc2013-02-21 16:44:05 -0800182 default:
183 return -EINVAL;
184 }
185
186 if (lp->cfg->pre_init_device) {
187 ret = lp->cfg->pre_init_device(lp);
188 if (ret) {
189 dev_err(lp->dev, "pre init device err: %d\n", ret);
190 goto err;
191 }
192 }
193
Kim, Milo7be865a2012-03-23 15:02:01 -0700194 val = pd->initial_brightness;
Kim, Milo68853bc2013-02-21 16:44:05 -0800195 ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
Kim, Milo7be865a2012-03-23 15:02:01 -0700196 if (ret)
Kim, Milo68853bc2013-02-21 16:44:05 -0800197 goto err;
Kim, Milo7be865a2012-03-23 15:02:01 -0700198
199 val = pd->device_control;
Kim, Milo68853bc2013-02-21 16:44:05 -0800200 ret = lp855x_write_byte(lp, lp->cfg->reg_devicectrl, val);
Kim, Milo7be865a2012-03-23 15:02:01 -0700201 if (ret)
Kim, Milo68853bc2013-02-21 16:44:05 -0800202 goto err;
Kim, Milo7be865a2012-03-23 15:02:01 -0700203
204 if (pd->load_new_rom_data && pd->size_program) {
205 for (i = 0; i < pd->size_program; i++) {
206 addr = pd->rom_data[i].addr;
207 val = pd->rom_data[i].val;
208 if (!lp855x_is_valid_rom_area(lp, addr))
209 continue;
210
211 ret = lp855x_write_byte(lp, addr, val);
212 if (ret)
Kim, Milo68853bc2013-02-21 16:44:05 -0800213 goto err;
Kim, Milo7be865a2012-03-23 15:02:01 -0700214 }
215 }
216
Kim, Milo68853bc2013-02-21 16:44:05 -0800217 if (lp->cfg->post_init_device) {
218 ret = lp->cfg->post_init_device(lp);
219 if (ret) {
220 dev_err(lp->dev, "post init device err: %d\n", ret);
221 goto err;
222 }
223 }
224
225 return 0;
226
227err:
Kim, Milo7be865a2012-03-23 15:02:01 -0700228 return ret;
229}
230
Kim, Milo8cc97642012-12-17 16:00:43 -0800231static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br)
232{
233 unsigned int period = lp->pdata->period_ns;
234 unsigned int duty = br * period / max_br;
235 struct pwm_device *pwm;
236
237 /* request pwm device with the consumer name */
238 if (!lp->pwm) {
239 pwm = devm_pwm_get(lp->dev, lp->chipname);
240 if (IS_ERR(pwm))
241 return;
242
243 lp->pwm = pwm;
244 }
245
246 pwm_config(lp->pwm, duty, period);
247 if (duty)
248 pwm_enable(lp->pwm);
249 else
250 pwm_disable(lp->pwm);
251}
252
Kim, Milo7be865a2012-03-23 15:02:01 -0700253static int lp855x_bl_update_status(struct backlight_device *bl)
254{
255 struct lp855x *lp = bl_get_data(bl);
256 enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
257
258 if (bl->props.state & BL_CORE_SUSPENDED)
259 bl->props.brightness = 0;
260
261 if (mode == PWM_BASED) {
Kim, Milo7be865a2012-03-23 15:02:01 -0700262 int br = bl->props.brightness;
263 int max_br = bl->props.max_brightness;
264
Kim, Milo8cc97642012-12-17 16:00:43 -0800265 lp855x_pwm_ctrl(lp, br, max_br);
Kim, Milo7be865a2012-03-23 15:02:01 -0700266
267 } else if (mode == REGISTER_BASED) {
268 u8 val = bl->props.brightness;
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800269 lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
Kim, Milo7be865a2012-03-23 15:02:01 -0700270 }
271
272 return 0;
273}
274
275static int lp855x_bl_get_brightness(struct backlight_device *bl)
276{
277 struct lp855x *lp = bl_get_data(bl);
278 enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
279
Kim, Milo8cc97642012-12-17 16:00:43 -0800280 if (mode == REGISTER_BASED) {
Kim, Milo7be865a2012-03-23 15:02:01 -0700281 u8 val = 0;
282
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800283 lp855x_read_byte(lp, lp->cfg->reg_brightness, &val);
Kim, Milo7be865a2012-03-23 15:02:01 -0700284 bl->props.brightness = val;
285 }
286
287 return bl->props.brightness;
288}
289
290static const struct backlight_ops lp855x_bl_ops = {
291 .options = BL_CORE_SUSPENDRESUME,
292 .update_status = lp855x_bl_update_status,
293 .get_brightness = lp855x_bl_get_brightness,
294};
295
296static int lp855x_backlight_register(struct lp855x *lp)
297{
298 struct backlight_device *bl;
299 struct backlight_properties props;
300 struct lp855x_platform_data *pdata = lp->pdata;
301 char *name = pdata->name ? : DEFAULT_BL_NAME;
302
303 props.type = BACKLIGHT_PLATFORM;
304 props.max_brightness = MAX_BRIGHTNESS;
305
306 if (pdata->initial_brightness > props.max_brightness)
307 pdata->initial_brightness = props.max_brightness;
308
309 props.brightness = pdata->initial_brightness;
310
311 bl = backlight_device_register(name, lp->dev, lp,
312 &lp855x_bl_ops, &props);
313 if (IS_ERR(bl))
314 return PTR_ERR(bl);
315
316 lp->bl = bl;
317
318 return 0;
319}
320
321static void lp855x_backlight_unregister(struct lp855x *lp)
322{
323 if (lp->bl)
324 backlight_device_unregister(lp->bl);
325}
326
327static ssize_t lp855x_get_chip_id(struct device *dev,
328 struct device_attribute *attr, char *buf)
329{
330 struct lp855x *lp = dev_get_drvdata(dev);
331 return scnprintf(buf, BUF_SIZE, "%s\n", lp->chipname);
332}
333
334static ssize_t lp855x_get_bl_ctl_mode(struct device *dev,
335 struct device_attribute *attr, char *buf)
336{
337 struct lp855x *lp = dev_get_drvdata(dev);
338 enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
339 char *strmode = NULL;
340
341 if (mode == PWM_BASED)
342 strmode = "pwm based";
343 else if (mode == REGISTER_BASED)
344 strmode = "register based";
345
346 return scnprintf(buf, BUF_SIZE, "%s\n", strmode);
347}
348
349static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL);
350static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp855x_get_bl_ctl_mode, NULL);
351
352static struct attribute *lp855x_attributes[] = {
353 &dev_attr_chip_id.attr,
354 &dev_attr_bl_ctl_mode.attr,
355 NULL,
356};
357
358static const struct attribute_group lp855x_attr_group = {
359 .attrs = lp855x_attributes,
360};
361
362static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
363{
364 struct lp855x *lp;
365 struct lp855x_platform_data *pdata = cl->dev.platform_data;
366 enum lp855x_brightness_ctrl_mode mode;
367 int ret;
368
369 if (!pdata) {
370 dev_err(&cl->dev, "no platform data supplied\n");
371 return -EINVAL;
372 }
373
374 if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
375 return -EIO;
376
377 lp = devm_kzalloc(&cl->dev, sizeof(struct lp855x), GFP_KERNEL);
378 if (!lp)
379 return -ENOMEM;
380
381 mode = pdata->mode;
382 lp->client = cl;
383 lp->dev = &cl->dev;
384 lp->pdata = pdata;
385 lp->chipname = id->name;
386 lp->chip_id = id->driver_data;
387 i2c_set_clientdata(cl, lp);
388
Kim, Milo68853bc2013-02-21 16:44:05 -0800389 ret = lp855x_configure(lp);
Kim, Milo7be865a2012-03-23 15:02:01 -0700390 if (ret) {
Kim, Milo68853bc2013-02-21 16:44:05 -0800391 dev_err(lp->dev, "device config err: %d", ret);
392 goto err_dev;
Kim, Milo7be865a2012-03-23 15:02:01 -0700393 }
394
395 ret = lp855x_backlight_register(lp);
396 if (ret) {
397 dev_err(lp->dev,
398 "failed to register backlight. err: %d\n", ret);
399 goto err_dev;
400 }
401
402 ret = sysfs_create_group(&lp->dev->kobj, &lp855x_attr_group);
403 if (ret) {
404 dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret);
405 goto err_sysfs;
406 }
407
408 backlight_update_status(lp->bl);
409 return 0;
410
411err_sysfs:
412 lp855x_backlight_unregister(lp);
413err_dev:
414 return ret;
415}
416
Bill Pemberton7e4b9d02012-11-19 13:26:34 -0500417static int lp855x_remove(struct i2c_client *cl)
Kim, Milo7be865a2012-03-23 15:02:01 -0700418{
419 struct lp855x *lp = i2c_get_clientdata(cl);
420
421 lp->bl->props.brightness = 0;
422 backlight_update_status(lp->bl);
423 sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);
424 lp855x_backlight_unregister(lp);
425
426 return 0;
427}
428
429static const struct i2c_device_id lp855x_ids[] = {
430 {"lp8550", LP8550},
431 {"lp8551", LP8551},
432 {"lp8552", LP8552},
433 {"lp8553", LP8553},
434 {"lp8556", LP8556},
Kim, Milo26e8ccc2013-02-21 16:44:06 -0800435 {"lp8557", LP8557},
Kim, Milo7be865a2012-03-23 15:02:01 -0700436 { }
437};
438MODULE_DEVICE_TABLE(i2c, lp855x_ids);
439
440static struct i2c_driver lp855x_driver = {
441 .driver = {
442 .name = "lp855x",
443 },
444 .probe = lp855x_probe,
Bill Pembertond1723fa2012-11-19 13:21:09 -0500445 .remove = lp855x_remove,
Kim, Milo7be865a2012-03-23 15:02:01 -0700446 .id_table = lp855x_ids,
447};
448
449module_i2c_driver(lp855x_driver);
450
451MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
452MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
453MODULE_LICENSE("GPL");