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/lp855x.h>
20 #define BRIGHTNESS_CTRL (0x00)
21 #define DEVICE_CTRL (0x01)
24 #define DEFAULT_BL_NAME "lcd-backlight"
25 #define MAX_BRIGHTNESS 255
29 enum lp855x_chip_id chip_id
;
30 struct i2c_client
*client
;
31 struct backlight_device
*bl
;
33 struct mutex xfer_lock
;
34 struct lp855x_platform_data
*pdata
;
37 static int lp855x_read_byte(struct lp855x
*lp
, u8 reg
, u8
*data
)
41 mutex_lock(&lp
->xfer_lock
);
42 ret
= i2c_smbus_read_byte_data(lp
->client
, reg
);
44 mutex_unlock(&lp
->xfer_lock
);
45 dev_err(lp
->dev
, "failed to read 0x%.2x\n", reg
);
48 mutex_unlock(&lp
->xfer_lock
);
54 static int lp855x_write_byte(struct lp855x
*lp
, u8 reg
, u8 data
)
58 mutex_lock(&lp
->xfer_lock
);
59 ret
= i2c_smbus_write_byte_data(lp
->client
, reg
, data
);
60 mutex_unlock(&lp
->xfer_lock
);
65 static bool lp855x_is_valid_rom_area(struct lp855x
*lp
, u8 addr
)
69 switch (lp
->chip_id
) {
85 return (addr
>= start
&& addr
<= end
);
88 static int lp855x_init_registers(struct lp855x
*lp
)
92 struct lp855x_platform_data
*pd
= lp
->pdata
;
94 val
= pd
->initial_brightness
;
95 ret
= lp855x_write_byte(lp
, BRIGHTNESS_CTRL
, val
);
99 val
= pd
->device_control
;
100 ret
= lp855x_write_byte(lp
, DEVICE_CTRL
, val
);
104 if (pd
->load_new_rom_data
&& pd
->size_program
) {
105 for (i
= 0; i
< pd
->size_program
; i
++) {
106 addr
= pd
->rom_data
[i
].addr
;
107 val
= pd
->rom_data
[i
].val
;
108 if (!lp855x_is_valid_rom_area(lp
, addr
))
111 ret
= lp855x_write_byte(lp
, addr
, val
);
120 static int lp855x_bl_update_status(struct backlight_device
*bl
)
122 struct lp855x
*lp
= bl_get_data(bl
);
123 enum lp855x_brightness_ctrl_mode mode
= lp
->pdata
->mode
;
125 if (bl
->props
.state
& BL_CORE_SUSPENDED
)
126 bl
->props
.brightness
= 0;
128 if (mode
== PWM_BASED
) {
129 struct lp855x_pwm_data
*pd
= &lp
->pdata
->pwm_data
;
130 int br
= bl
->props
.brightness
;
131 int max_br
= bl
->props
.max_brightness
;
133 if (pd
->pwm_set_intensity
)
134 pd
->pwm_set_intensity(br
, max_br
);
136 } else if (mode
== REGISTER_BASED
) {
137 u8 val
= bl
->props
.brightness
;
138 lp855x_write_byte(lp
, BRIGHTNESS_CTRL
, val
);
144 static int lp855x_bl_get_brightness(struct backlight_device
*bl
)
146 struct lp855x
*lp
= bl_get_data(bl
);
147 enum lp855x_brightness_ctrl_mode mode
= lp
->pdata
->mode
;
149 if (mode
== PWM_BASED
) {
150 struct lp855x_pwm_data
*pd
= &lp
->pdata
->pwm_data
;
151 int max_br
= bl
->props
.max_brightness
;
153 if (pd
->pwm_get_intensity
)
154 bl
->props
.brightness
= pd
->pwm_get_intensity(max_br
);
156 } else if (mode
== REGISTER_BASED
) {
159 lp855x_read_byte(lp
, BRIGHTNESS_CTRL
, &val
);
160 bl
->props
.brightness
= val
;
163 return bl
->props
.brightness
;
166 static const struct backlight_ops lp855x_bl_ops
= {
167 .options
= BL_CORE_SUSPENDRESUME
,
168 .update_status
= lp855x_bl_update_status
,
169 .get_brightness
= lp855x_bl_get_brightness
,
172 static int lp855x_backlight_register(struct lp855x
*lp
)
174 struct backlight_device
*bl
;
175 struct backlight_properties props
;
176 struct lp855x_platform_data
*pdata
= lp
->pdata
;
177 char *name
= pdata
->name
? : DEFAULT_BL_NAME
;
179 props
.type
= BACKLIGHT_PLATFORM
;
180 props
.max_brightness
= MAX_BRIGHTNESS
;
182 if (pdata
->initial_brightness
> props
.max_brightness
)
183 pdata
->initial_brightness
= props
.max_brightness
;
185 props
.brightness
= pdata
->initial_brightness
;
187 bl
= backlight_device_register(name
, lp
->dev
, lp
,
188 &lp855x_bl_ops
, &props
);
197 static void lp855x_backlight_unregister(struct lp855x
*lp
)
200 backlight_device_unregister(lp
->bl
);
203 static ssize_t
lp855x_get_chip_id(struct device
*dev
,
204 struct device_attribute
*attr
, char *buf
)
206 struct lp855x
*lp
= dev_get_drvdata(dev
);
207 return scnprintf(buf
, BUF_SIZE
, "%s\n", lp
->chipname
);
210 static ssize_t
lp855x_get_bl_ctl_mode(struct device
*dev
,
211 struct device_attribute
*attr
, char *buf
)
213 struct lp855x
*lp
= dev_get_drvdata(dev
);
214 enum lp855x_brightness_ctrl_mode mode
= lp
->pdata
->mode
;
215 char *strmode
= NULL
;
217 if (mode
== PWM_BASED
)
218 strmode
= "pwm based";
219 else if (mode
== REGISTER_BASED
)
220 strmode
= "register based";
222 return scnprintf(buf
, BUF_SIZE
, "%s\n", strmode
);
225 static DEVICE_ATTR(chip_id
, S_IRUGO
, lp855x_get_chip_id
, NULL
);
226 static DEVICE_ATTR(bl_ctl_mode
, S_IRUGO
, lp855x_get_bl_ctl_mode
, NULL
);
228 static struct attribute
*lp855x_attributes
[] = {
229 &dev_attr_chip_id
.attr
,
230 &dev_attr_bl_ctl_mode
.attr
,
234 static const struct attribute_group lp855x_attr_group
= {
235 .attrs
= lp855x_attributes
,
238 static int lp855x_probe(struct i2c_client
*cl
, const struct i2c_device_id
*id
)
241 struct lp855x_platform_data
*pdata
= cl
->dev
.platform_data
;
242 enum lp855x_brightness_ctrl_mode mode
;
246 dev_err(&cl
->dev
, "no platform data supplied\n");
250 if (!i2c_check_functionality(cl
->adapter
, I2C_FUNC_SMBUS_I2C_BLOCK
))
253 lp
= devm_kzalloc(&cl
->dev
, sizeof(struct lp855x
), GFP_KERNEL
);
261 lp
->chipname
= id
->name
;
262 lp
->chip_id
= id
->driver_data
;
263 i2c_set_clientdata(cl
, lp
);
265 mutex_init(&lp
->xfer_lock
);
267 ret
= lp855x_init_registers(lp
);
269 dev_err(lp
->dev
, "i2c communication err: %d", ret
);
270 if (mode
== REGISTER_BASED
)
274 ret
= lp855x_backlight_register(lp
);
277 "failed to register backlight. err: %d\n", ret
);
281 ret
= sysfs_create_group(&lp
->dev
->kobj
, &lp855x_attr_group
);
283 dev_err(lp
->dev
, "failed to register sysfs. err: %d\n", ret
);
287 backlight_update_status(lp
->bl
);
291 lp855x_backlight_unregister(lp
);
296 static int __devexit
lp855x_remove(struct i2c_client
*cl
)
298 struct lp855x
*lp
= i2c_get_clientdata(cl
);
300 lp
->bl
->props
.brightness
= 0;
301 backlight_update_status(lp
->bl
);
302 sysfs_remove_group(&lp
->dev
->kobj
, &lp855x_attr_group
);
303 lp855x_backlight_unregister(lp
);
308 static const struct i2c_device_id lp855x_ids
[] = {
316 MODULE_DEVICE_TABLE(i2c
, lp855x_ids
);
318 static struct i2c_driver lp855x_driver
= {
322 .probe
= lp855x_probe
,
323 .remove
= __devexit_p(lp855x_remove
),
324 .id_table
= lp855x_ids
,
327 module_i2c_driver(lp855x_driver
);
329 MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
330 MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
331 MODULE_LICENSE("GPL");