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>
18 #include <linux/pwm.h>
21 #define BRIGHTNESS_CTRL 0x00
22 #define DEVICE_CTRL 0x01
23 #define EEPROM_START 0xA0
24 #define EEPROM_END 0xA7
25 #define EPROM_START 0xA0
26 #define EPROM_END 0xAF
29 #define DEFAULT_BL_NAME "lcd-backlight"
30 #define MAX_BRIGHTNESS 255
34 enum lp855x_chip_id chip_id
;
35 struct i2c_client
*client
;
36 struct backlight_device
*bl
;
38 struct lp855x_platform_data
*pdata
;
39 struct pwm_device
*pwm
;
42 static int lp855x_read_byte(struct lp855x
*lp
, u8 reg
, u8
*data
)
46 ret
= i2c_smbus_read_byte_data(lp
->client
, reg
);
48 dev_err(lp
->dev
, "failed to read 0x%.2x\n", reg
);
56 static int lp855x_write_byte(struct lp855x
*lp
, u8 reg
, u8 data
)
58 return i2c_smbus_write_byte_data(lp
->client
, reg
, data
);
61 static bool lp855x_is_valid_rom_area(struct lp855x
*lp
, u8 addr
)
65 switch (lp
->chip_id
) {
81 return (addr
>= start
&& addr
<= end
);
84 static int lp855x_init_registers(struct lp855x
*lp
)
88 struct lp855x_platform_data
*pd
= lp
->pdata
;
90 val
= pd
->initial_brightness
;
91 ret
= lp855x_write_byte(lp
, BRIGHTNESS_CTRL
, val
);
95 val
= pd
->device_control
;
96 ret
= lp855x_write_byte(lp
, DEVICE_CTRL
, val
);
100 if (pd
->load_new_rom_data
&& pd
->size_program
) {
101 for (i
= 0; i
< pd
->size_program
; i
++) {
102 addr
= pd
->rom_data
[i
].addr
;
103 val
= pd
->rom_data
[i
].val
;
104 if (!lp855x_is_valid_rom_area(lp
, addr
))
107 ret
= lp855x_write_byte(lp
, addr
, val
);
116 static void lp855x_pwm_ctrl(struct lp855x
*lp
, int br
, int max_br
)
118 unsigned int period
= lp
->pdata
->period_ns
;
119 unsigned int duty
= br
* period
/ max_br
;
120 struct pwm_device
*pwm
;
122 /* request pwm device with the consumer name */
124 pwm
= devm_pwm_get(lp
->dev
, lp
->chipname
);
131 pwm_config(lp
->pwm
, duty
, period
);
135 pwm_disable(lp
->pwm
);
138 static int lp855x_bl_update_status(struct backlight_device
*bl
)
140 struct lp855x
*lp
= bl_get_data(bl
);
141 enum lp855x_brightness_ctrl_mode mode
= lp
->pdata
->mode
;
143 if (bl
->props
.state
& BL_CORE_SUSPENDED
)
144 bl
->props
.brightness
= 0;
146 if (mode
== PWM_BASED
) {
147 int br
= bl
->props
.brightness
;
148 int max_br
= bl
->props
.max_brightness
;
150 lp855x_pwm_ctrl(lp
, br
, max_br
);
152 } else if (mode
== REGISTER_BASED
) {
153 u8 val
= bl
->props
.brightness
;
154 lp855x_write_byte(lp
, BRIGHTNESS_CTRL
, val
);
160 static int lp855x_bl_get_brightness(struct backlight_device
*bl
)
162 struct lp855x
*lp
= bl_get_data(bl
);
163 enum lp855x_brightness_ctrl_mode mode
= lp
->pdata
->mode
;
165 if (mode
== REGISTER_BASED
) {
168 lp855x_read_byte(lp
, BRIGHTNESS_CTRL
, &val
);
169 bl
->props
.brightness
= val
;
172 return bl
->props
.brightness
;
175 static const struct backlight_ops lp855x_bl_ops
= {
176 .options
= BL_CORE_SUSPENDRESUME
,
177 .update_status
= lp855x_bl_update_status
,
178 .get_brightness
= lp855x_bl_get_brightness
,
181 static int lp855x_backlight_register(struct lp855x
*lp
)
183 struct backlight_device
*bl
;
184 struct backlight_properties props
;
185 struct lp855x_platform_data
*pdata
= lp
->pdata
;
186 char *name
= pdata
->name
? : DEFAULT_BL_NAME
;
188 props
.type
= BACKLIGHT_PLATFORM
;
189 props
.max_brightness
= MAX_BRIGHTNESS
;
191 if (pdata
->initial_brightness
> props
.max_brightness
)
192 pdata
->initial_brightness
= props
.max_brightness
;
194 props
.brightness
= pdata
->initial_brightness
;
196 bl
= backlight_device_register(name
, lp
->dev
, lp
,
197 &lp855x_bl_ops
, &props
);
206 static void lp855x_backlight_unregister(struct lp855x
*lp
)
209 backlight_device_unregister(lp
->bl
);
212 static ssize_t
lp855x_get_chip_id(struct device
*dev
,
213 struct device_attribute
*attr
, char *buf
)
215 struct lp855x
*lp
= dev_get_drvdata(dev
);
216 return scnprintf(buf
, BUF_SIZE
, "%s\n", lp
->chipname
);
219 static ssize_t
lp855x_get_bl_ctl_mode(struct device
*dev
,
220 struct device_attribute
*attr
, char *buf
)
222 struct lp855x
*lp
= dev_get_drvdata(dev
);
223 enum lp855x_brightness_ctrl_mode mode
= lp
->pdata
->mode
;
224 char *strmode
= NULL
;
226 if (mode
== PWM_BASED
)
227 strmode
= "pwm based";
228 else if (mode
== REGISTER_BASED
)
229 strmode
= "register based";
231 return scnprintf(buf
, BUF_SIZE
, "%s\n", strmode
);
234 static DEVICE_ATTR(chip_id
, S_IRUGO
, lp855x_get_chip_id
, NULL
);
235 static DEVICE_ATTR(bl_ctl_mode
, S_IRUGO
, lp855x_get_bl_ctl_mode
, NULL
);
237 static struct attribute
*lp855x_attributes
[] = {
238 &dev_attr_chip_id
.attr
,
239 &dev_attr_bl_ctl_mode
.attr
,
243 static const struct attribute_group lp855x_attr_group
= {
244 .attrs
= lp855x_attributes
,
247 static int lp855x_probe(struct i2c_client
*cl
, const struct i2c_device_id
*id
)
250 struct lp855x_platform_data
*pdata
= cl
->dev
.platform_data
;
251 enum lp855x_brightness_ctrl_mode mode
;
255 dev_err(&cl
->dev
, "no platform data supplied\n");
259 if (!i2c_check_functionality(cl
->adapter
, I2C_FUNC_SMBUS_I2C_BLOCK
))
262 lp
= devm_kzalloc(&cl
->dev
, sizeof(struct lp855x
), GFP_KERNEL
);
270 lp
->chipname
= id
->name
;
271 lp
->chip_id
= id
->driver_data
;
272 i2c_set_clientdata(cl
, lp
);
274 ret
= lp855x_init_registers(lp
);
276 dev_err(lp
->dev
, "i2c communication err: %d", ret
);
277 if (mode
== REGISTER_BASED
)
281 ret
= lp855x_backlight_register(lp
);
284 "failed to register backlight. err: %d\n", ret
);
288 ret
= sysfs_create_group(&lp
->dev
->kobj
, &lp855x_attr_group
);
290 dev_err(lp
->dev
, "failed to register sysfs. err: %d\n", ret
);
294 backlight_update_status(lp
->bl
);
298 lp855x_backlight_unregister(lp
);
303 static int lp855x_remove(struct i2c_client
*cl
)
305 struct lp855x
*lp
= i2c_get_clientdata(cl
);
307 lp
->bl
->props
.brightness
= 0;
308 backlight_update_status(lp
->bl
);
309 sysfs_remove_group(&lp
->dev
->kobj
, &lp855x_attr_group
);
310 lp855x_backlight_unregister(lp
);
315 static const struct i2c_device_id lp855x_ids
[] = {
323 MODULE_DEVICE_TABLE(i2c
, lp855x_ids
);
325 static struct i2c_driver lp855x_driver
= {
329 .probe
= lp855x_probe
,
330 .remove
= lp855x_remove
,
331 .id_table
= lp855x_ids
,
334 module_i2c_driver(lp855x_driver
);
336 MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
337 MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
338 MODULE_LICENSE("GPL");