2 * TI LP855x Backlight Driver
4 * Copyright (C) 2011 Texas Instruments
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.
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>
20 #define BRIGHTNESS_CTRL 0x00
21 #define DEVICE_CTRL 0x01
22 #define EEPROM_START 0xA0
23 #define EEPROM_END 0xA7
24 #define EPROM_START 0xA0
25 #define EPROM_END 0xAF
28 #define DEFAULT_BL_NAME "lcd-backlight"
29 #define MAX_BRIGHTNESS 255
33 enum lp855x_chip_id chip_id
;
34 struct i2c_client
*client
;
35 struct backlight_device
*bl
;
37 struct mutex xfer_lock
;
38 struct lp855x_platform_data
*pdata
;
41 static int lp855x_read_byte(struct lp855x
*lp
, u8 reg
, u8
*data
)
45 mutex_lock(&lp
->xfer_lock
);
46 ret
= i2c_smbus_read_byte_data(lp
->client
, reg
);
48 mutex_unlock(&lp
->xfer_lock
);
49 dev_err(lp
->dev
, "failed to read 0x%.2x\n", reg
);
52 mutex_unlock(&lp
->xfer_lock
);
58 static int lp855x_write_byte(struct lp855x
*lp
, u8 reg
, u8 data
)
62 mutex_lock(&lp
->xfer_lock
);
63 ret
= i2c_smbus_write_byte_data(lp
->client
, reg
, data
);
64 mutex_unlock(&lp
->xfer_lock
);
69 static bool lp855x_is_valid_rom_area(struct lp855x
*lp
, u8 addr
)
73 switch (lp
->chip_id
) {
89 return (addr
>= start
&& addr
<= end
);
92 static int lp855x_init_registers(struct lp855x
*lp
)
96 struct lp855x_platform_data
*pd
= lp
->pdata
;
98 val
= pd
->initial_brightness
;
99 ret
= lp855x_write_byte(lp
, BRIGHTNESS_CTRL
, val
);
103 val
= pd
->device_control
;
104 ret
= lp855x_write_byte(lp
, DEVICE_CTRL
, val
);
108 if (pd
->load_new_rom_data
&& pd
->size_program
) {
109 for (i
= 0; i
< pd
->size_program
; i
++) {
110 addr
= pd
->rom_data
[i
].addr
;
111 val
= pd
->rom_data
[i
].val
;
112 if (!lp855x_is_valid_rom_area(lp
, addr
))
115 ret
= lp855x_write_byte(lp
, addr
, val
);
124 static int lp855x_bl_update_status(struct backlight_device
*bl
)
126 struct lp855x
*lp
= bl_get_data(bl
);
127 enum lp855x_brightness_ctrl_mode mode
= lp
->pdata
->mode
;
129 if (bl
->props
.state
& BL_CORE_SUSPENDED
)
130 bl
->props
.brightness
= 0;
132 if (mode
== PWM_BASED
) {
133 struct lp855x_pwm_data
*pd
= &lp
->pdata
->pwm_data
;
134 int br
= bl
->props
.brightness
;
135 int max_br
= bl
->props
.max_brightness
;
137 if (pd
->pwm_set_intensity
)
138 pd
->pwm_set_intensity(br
, max_br
);
140 } else if (mode
== REGISTER_BASED
) {
141 u8 val
= bl
->props
.brightness
;
142 lp855x_write_byte(lp
, BRIGHTNESS_CTRL
, val
);
148 static int lp855x_bl_get_brightness(struct backlight_device
*bl
)
150 struct lp855x
*lp
= bl_get_data(bl
);
151 enum lp855x_brightness_ctrl_mode mode
= lp
->pdata
->mode
;
153 if (mode
== PWM_BASED
) {
154 struct lp855x_pwm_data
*pd
= &lp
->pdata
->pwm_data
;
155 int max_br
= bl
->props
.max_brightness
;
157 if (pd
->pwm_get_intensity
)
158 bl
->props
.brightness
= pd
->pwm_get_intensity(max_br
);
160 } else if (mode
== REGISTER_BASED
) {
163 lp855x_read_byte(lp
, BRIGHTNESS_CTRL
, &val
);
164 bl
->props
.brightness
= val
;
167 return bl
->props
.brightness
;
170 static const struct backlight_ops lp855x_bl_ops
= {
171 .options
= BL_CORE_SUSPENDRESUME
,
172 .update_status
= lp855x_bl_update_status
,
173 .get_brightness
= lp855x_bl_get_brightness
,
176 static int lp855x_backlight_register(struct lp855x
*lp
)
178 struct backlight_device
*bl
;
179 struct backlight_properties props
;
180 struct lp855x_platform_data
*pdata
= lp
->pdata
;
181 char *name
= pdata
->name
? : DEFAULT_BL_NAME
;
183 props
.type
= BACKLIGHT_PLATFORM
;
184 props
.max_brightness
= MAX_BRIGHTNESS
;
186 if (pdata
->initial_brightness
> props
.max_brightness
)
187 pdata
->initial_brightness
= props
.max_brightness
;
189 props
.brightness
= pdata
->initial_brightness
;
191 bl
= backlight_device_register(name
, lp
->dev
, lp
,
192 &lp855x_bl_ops
, &props
);
201 static void lp855x_backlight_unregister(struct lp855x
*lp
)
204 backlight_device_unregister(lp
->bl
);
207 static ssize_t
lp855x_get_chip_id(struct device
*dev
,
208 struct device_attribute
*attr
, char *buf
)
210 struct lp855x
*lp
= dev_get_drvdata(dev
);
211 return scnprintf(buf
, BUF_SIZE
, "%s\n", lp
->chipname
);
214 static ssize_t
lp855x_get_bl_ctl_mode(struct device
*dev
,
215 struct device_attribute
*attr
, char *buf
)
217 struct lp855x
*lp
= dev_get_drvdata(dev
);
218 enum lp855x_brightness_ctrl_mode mode
= lp
->pdata
->mode
;
219 char *strmode
= NULL
;
221 if (mode
== PWM_BASED
)
222 strmode
= "pwm based";
223 else if (mode
== REGISTER_BASED
)
224 strmode
= "register based";
226 return scnprintf(buf
, BUF_SIZE
, "%s\n", strmode
);
229 static DEVICE_ATTR(chip_id
, S_IRUGO
, lp855x_get_chip_id
, NULL
);
230 static DEVICE_ATTR(bl_ctl_mode
, S_IRUGO
, lp855x_get_bl_ctl_mode
, NULL
);
232 static struct attribute
*lp855x_attributes
[] = {
233 &dev_attr_chip_id
.attr
,
234 &dev_attr_bl_ctl_mode
.attr
,
238 static const struct attribute_group lp855x_attr_group
= {
239 .attrs
= lp855x_attributes
,
242 static int lp855x_probe(struct i2c_client
*cl
, const struct i2c_device_id
*id
)
245 struct lp855x_platform_data
*pdata
= cl
->dev
.platform_data
;
246 enum lp855x_brightness_ctrl_mode mode
;
250 dev_err(&cl
->dev
, "no platform data supplied\n");
254 if (!i2c_check_functionality(cl
->adapter
, I2C_FUNC_SMBUS_I2C_BLOCK
))
257 lp
= devm_kzalloc(&cl
->dev
, sizeof(struct lp855x
), GFP_KERNEL
);
265 lp
->chipname
= id
->name
;
266 lp
->chip_id
= id
->driver_data
;
267 i2c_set_clientdata(cl
, lp
);
269 mutex_init(&lp
->xfer_lock
);
271 ret
= lp855x_init_registers(lp
);
273 dev_err(lp
->dev
, "i2c communication err: %d", ret
);
274 if (mode
== REGISTER_BASED
)
278 ret
= lp855x_backlight_register(lp
);
281 "failed to register backlight. err: %d\n", ret
);
285 ret
= sysfs_create_group(&lp
->dev
->kobj
, &lp855x_attr_group
);
287 dev_err(lp
->dev
, "failed to register sysfs. err: %d\n", ret
);
291 backlight_update_status(lp
->bl
);
295 lp855x_backlight_unregister(lp
);
300 static int __devexit
lp855x_remove(struct i2c_client
*cl
)
302 struct lp855x
*lp
= i2c_get_clientdata(cl
);
304 lp
->bl
->props
.brightness
= 0;
305 backlight_update_status(lp
->bl
);
306 sysfs_remove_group(&lp
->dev
->kobj
, &lp855x_attr_group
);
307 lp855x_backlight_unregister(lp
);
312 static const struct i2c_device_id lp855x_ids
[] = {
320 MODULE_DEVICE_TABLE(i2c
, lp855x_ids
);
322 static struct i2c_driver lp855x_driver
= {
326 .probe
= lp855x_probe
,
327 .remove
= __devexit_p(lp855x_remove
),
328 .id_table
= lp855x_ids
,
331 module_i2c_driver(lp855x_driver
);
333 MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
334 MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
335 MODULE_LICENSE("GPL");