aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/backlight
diff options
context:
space:
mode:
authorKim, Milo <Milo.Kim@ti.com>2013-02-27 20:02:43 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-27 22:10:09 -0500
commitc5a51053cf3b499ddba60a89ab067ea05ad15840 (patch)
tree0f76cd10dc1ee7f57782434f1aff21a4a4e39bc0 /drivers/video/backlight
parent9ed8a30f3471347c1b763bd062fa78ae80f18eae (diff)
backlight: add new lp8788 backlight driver
TI LP8788 PMU supports regulators, battery charger, RTC, ADC, backlight dri= ver and current sinks. This patch enables LP8788 backlight module. (Brightness mode) The brightness is controlled by PWM input or I2C register. All modes are supported in the driver. (Platform data) Configurable data can be defined in the platform side. name : backlight driver name. (default: "lcd-backlight") initial_brightness : initial value of backlight brightness bl_mode : brightness control by PWM or lp8788 register dim_mode : dimming mode selection full_scale : full scale current setting rise_time : brightness ramp up step time fall_time : brightness ramp down step time pwm_pol : PWM polarity setting when bl_mode is PWM based period_ns : platform specific PWM period value. unit is nano. The default values are set in case no platform data is defined. [akpm@linux-foundation.org: checkpatch fixes] Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com> Cc: Richard Purdie <rpurdie@rpsys.net> Cc: Samuel Ortiz <sameo@linux.intel.com> Cc: Thierry Reding <thierry.reding@avionic-design.de> Cc: "devendra.aaru" <devendra.aaru@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/backlight')
-rw-r--r--drivers/video/backlight/Kconfig6
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/lp8788_bl.c333
3 files changed, 340 insertions, 0 deletions
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index be27b551473f..db10d0120d2b 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -384,6 +384,12 @@ config BACKLIGHT_LP855X
384 This supports TI LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557 384 This supports TI LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557
385 backlight driver. 385 backlight driver.
386 386
387config BACKLIGHT_LP8788
388 tristate "Backlight driver for TI LP8788 MFD"
389 depends on BACKLIGHT_CLASS_DEVICE && MFD_LP8788
390 help
391 This supports TI LP8788 backlight driver.
392
387config BACKLIGHT_OT200 393config BACKLIGHT_OT200
388 tristate "Backlight driver for ot200 visualisation device" 394 tristate "Backlight driver for ot200 visualisation device"
389 depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535 395 depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 4606c218e8e4..96c4d620c5ce 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_BACKLIGHT_LM3630) += lm3630_bl.o
38obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o 38obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
39obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o 39obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
40obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o 40obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
41obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o
41obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o 42obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o
42obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o 43obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
43obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o 44obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o
diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c
new file mode 100644
index 000000000000..4bb8b4f140cf
--- /dev/null
+++ b/drivers/video/backlight/lp8788_bl.c
@@ -0,0 +1,333 @@
1/*
2 * TI LP8788 MFD - backlight driver
3 *
4 * Copyright 2012 Texas Instruments
5 *
6 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/backlight.h>
15#include <linux/err.h>
16#include <linux/mfd/lp8788.h>
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <linux/pwm.h>
20#include <linux/slab.h>
21
22/* Register address */
23#define LP8788_BL_CONFIG 0x96
24#define LP8788_BL_EN BIT(0)
25#define LP8788_BL_PWM_INPUT_EN BIT(5)
26#define LP8788_BL_FULLSCALE_SHIFT 2
27#define LP8788_BL_DIM_MODE_SHIFT 1
28#define LP8788_BL_PWM_POLARITY_SHIFT 6
29
30#define LP8788_BL_BRIGHTNESS 0x97
31
32#define LP8788_BL_RAMP 0x98
33#define LP8788_BL_RAMP_RISE_SHIFT 4
34
35#define MAX_BRIGHTNESS 127
36#define DEFAULT_BL_NAME "lcd-backlight"
37
38struct lp8788_bl_config {
39 enum lp8788_bl_ctrl_mode bl_mode;
40 enum lp8788_bl_dim_mode dim_mode;
41 enum lp8788_bl_full_scale_current full_scale;
42 enum lp8788_bl_ramp_step rise_time;
43 enum lp8788_bl_ramp_step fall_time;
44 enum pwm_polarity pwm_pol;
45};
46
47struct lp8788_bl {
48 struct lp8788 *lp;
49 struct backlight_device *bl_dev;
50 struct lp8788_backlight_platform_data *pdata;
51 enum lp8788_bl_ctrl_mode mode;
52 struct pwm_device *pwm;
53};
54
55struct lp8788_bl_config default_bl_config = {
56 .bl_mode = LP8788_BL_REGISTER_ONLY,
57 .dim_mode = LP8788_DIM_EXPONENTIAL,
58 .full_scale = LP8788_FULLSCALE_1900uA,
59 .rise_time = LP8788_RAMP_8192us,
60 .fall_time = LP8788_RAMP_8192us,
61 .pwm_pol = PWM_POLARITY_NORMAL,
62};
63
64static inline bool is_brightness_ctrl_by_pwm(enum lp8788_bl_ctrl_mode mode)
65{
66 return (mode == LP8788_BL_COMB_PWM_BASED);
67}
68
69static inline bool is_brightness_ctrl_by_register(enum lp8788_bl_ctrl_mode mode)
70{
71 return (mode == LP8788_BL_REGISTER_ONLY ||
72 mode == LP8788_BL_COMB_REGISTER_BASED);
73}
74
75static int lp8788_backlight_configure(struct lp8788_bl *bl)
76{
77 struct lp8788_backlight_platform_data *pdata = bl->pdata;
78 struct lp8788_bl_config *cfg = &default_bl_config;
79 int ret;
80 u8 val;
81
82 /*
83 * Update chip configuration if platform data exists,
84 * otherwise use the default settings.
85 */
86 if (pdata) {
87 cfg->bl_mode = pdata->bl_mode;
88 cfg->dim_mode = pdata->dim_mode;
89 cfg->full_scale = pdata->full_scale;
90 cfg->rise_time = pdata->rise_time;
91 cfg->fall_time = pdata->fall_time;
92 cfg->pwm_pol = pdata->pwm_pol;
93 }
94
95 /* Brightness ramp up/down */
96 val = (cfg->rise_time << LP8788_BL_RAMP_RISE_SHIFT) | cfg->fall_time;
97 ret = lp8788_write_byte(bl->lp, LP8788_BL_RAMP, val);
98 if (ret)
99 return ret;
100
101 /* Fullscale current setting */
102 val = (cfg->full_scale << LP8788_BL_FULLSCALE_SHIFT) |
103 (cfg->dim_mode << LP8788_BL_DIM_MODE_SHIFT);
104
105 /* Brightness control mode */
106 switch (cfg->bl_mode) {
107 case LP8788_BL_REGISTER_ONLY:
108 val |= LP8788_BL_EN;
109 break;
110 case LP8788_BL_COMB_PWM_BASED:
111 case LP8788_BL_COMB_REGISTER_BASED:
112 val |= LP8788_BL_EN | LP8788_BL_PWM_INPUT_EN |
113 (cfg->pwm_pol << LP8788_BL_PWM_POLARITY_SHIFT);
114 break;
115 default:
116 dev_err(bl->lp->dev, "invalid mode: %d\n", cfg->bl_mode);
117 return -EINVAL;
118 }
119
120 bl->mode = cfg->bl_mode;
121
122 return lp8788_write_byte(bl->lp, LP8788_BL_CONFIG, val);
123}
124
125static void lp8788_pwm_ctrl(struct lp8788_bl *bl, int br, int max_br)
126{
127 unsigned int period;
128 unsigned int duty;
129 struct device *dev;
130 struct pwm_device *pwm;
131
132 if (!bl->pdata)
133 return;
134
135 period = bl->pdata->period_ns;
136 duty = br * period / max_br;
137 dev = bl->lp->dev;
138
139 /* request PWM device with the consumer name */
140 if (!bl->pwm) {
141 pwm = devm_pwm_get(dev, LP8788_DEV_BACKLIGHT);
142 if (IS_ERR(pwm)) {
143 dev_err(dev, "can not get PWM device\n");
144 return;
145 }
146
147 bl->pwm = pwm;
148 }
149
150 pwm_config(bl->pwm, duty, period);
151 if (duty)
152 pwm_enable(bl->pwm);
153 else
154 pwm_disable(bl->pwm);
155}
156
157static int lp8788_bl_update_status(struct backlight_device *bl_dev)
158{
159 struct lp8788_bl *bl = bl_get_data(bl_dev);
160 enum lp8788_bl_ctrl_mode mode = bl->mode;
161
162 if (bl_dev->props.state & BL_CORE_SUSPENDED)
163 bl_dev->props.brightness = 0;
164
165 if (is_brightness_ctrl_by_pwm(mode)) {
166 int brt = bl_dev->props.brightness;
167 int max = bl_dev->props.max_brightness;
168
169 lp8788_pwm_ctrl(bl, brt, max);
170 } else if (is_brightness_ctrl_by_register(mode)) {
171 u8 brt = bl_dev->props.brightness;
172
173 lp8788_write_byte(bl->lp, LP8788_BL_BRIGHTNESS, brt);
174 }
175
176 return 0;
177}
178
179static int lp8788_bl_get_brightness(struct backlight_device *bl_dev)
180{
181 return bl_dev->props.brightness;
182}
183
184static const struct backlight_ops lp8788_bl_ops = {
185 .options = BL_CORE_SUSPENDRESUME,
186 .update_status = lp8788_bl_update_status,
187 .get_brightness = lp8788_bl_get_brightness,
188};
189
190static int lp8788_backlight_register(struct lp8788_bl *bl)
191{
192 struct backlight_device *bl_dev;
193 struct backlight_properties props;
194 struct lp8788_backlight_platform_data *pdata = bl->pdata;
195 int init_brt;
196 char *name;
197
198 props.type = BACKLIGHT_PLATFORM;
199 props.max_brightness = MAX_BRIGHTNESS;
200
201 /* Initial brightness */
202 if (pdata)
203 init_brt = min_t(int, pdata->initial_brightness,
204 props.max_brightness);
205 else
206 init_brt = 0;
207
208 props.brightness = init_brt;
209
210 /* Backlight device name */
211 if (!pdata || !pdata->name)
212 name = DEFAULT_BL_NAME;
213 else
214 name = pdata->name;
215
216 bl_dev = backlight_device_register(name, bl->lp->dev, bl,
217 &lp8788_bl_ops, &props);
218 if (IS_ERR(bl_dev))
219 return PTR_ERR(bl_dev);
220
221 bl->bl_dev = bl_dev;
222
223 return 0;
224}
225
226static void lp8788_backlight_unregister(struct lp8788_bl *bl)
227{
228 struct backlight_device *bl_dev = bl->bl_dev;
229
230 if (bl_dev)
231 backlight_device_unregister(bl_dev);
232}
233
234static ssize_t lp8788_get_bl_ctl_mode(struct device *dev,
235 struct device_attribute *attr, char *buf)
236{
237 struct lp8788_bl *bl = dev_get_drvdata(dev);
238 enum lp8788_bl_ctrl_mode mode = bl->mode;
239 char *strmode;
240
241 if (is_brightness_ctrl_by_pwm(mode))
242 strmode = "PWM based";
243 else if (is_brightness_ctrl_by_register(mode))
244 strmode = "Register based";
245 else
246 strmode = "Invalid mode";
247
248 return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
249}
250
251static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp8788_get_bl_ctl_mode, NULL);
252
253static struct attribute *lp8788_attributes[] = {
254 &dev_attr_bl_ctl_mode.attr,
255 NULL,
256};
257
258static const struct attribute_group lp8788_attr_group = {
259 .attrs = lp8788_attributes,
260};
261
262static int lp8788_backlight_probe(struct platform_device *pdev)
263{
264 struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
265 struct lp8788_bl *bl;
266 int ret;
267
268 bl = devm_kzalloc(lp->dev, sizeof(struct lp8788_bl), GFP_KERNEL);
269 if (!bl)
270 return -ENOMEM;
271
272 bl->lp = lp;
273 if (lp->pdata)
274 bl->pdata = lp->pdata->bl_pdata;
275
276 platform_set_drvdata(pdev, bl);
277
278 ret = lp8788_backlight_configure(bl);
279 if (ret) {
280 dev_err(lp->dev, "backlight config err: %d\n", ret);
281 goto err_dev;
282 }
283
284 ret = lp8788_backlight_register(bl);
285 if (ret) {
286 dev_err(lp->dev, "register backlight err: %d\n", ret);
287 goto err_dev;
288 }
289
290 ret = sysfs_create_group(&pdev->dev.kobj, &lp8788_attr_group);
291 if (ret) {
292 dev_err(lp->dev, "register sysfs err: %d\n", ret);
293 goto err_sysfs;
294 }
295
296 backlight_update_status(bl->bl_dev);
297
298 return 0;
299
300err_sysfs:
301 lp8788_backlight_unregister(bl);
302err_dev:
303 return ret;
304}
305
306static int lp8788_backlight_remove(struct platform_device *pdev)
307{
308 struct lp8788_bl *bl = platform_get_drvdata(pdev);
309 struct backlight_device *bl_dev = bl->bl_dev;
310
311 bl_dev->props.brightness = 0;
312 backlight_update_status(bl_dev);
313 sysfs_remove_group(&pdev->dev.kobj, &lp8788_attr_group);
314 lp8788_backlight_unregister(bl);
315 platform_set_drvdata(pdev, NULL);
316
317 return 0;
318}
319
320static struct platform_driver lp8788_bl_driver = {
321 .probe = lp8788_backlight_probe,
322 .remove = lp8788_backlight_remove,
323 .driver = {
324 .name = LP8788_DEV_BACKLIGHT,
325 .owner = THIS_MODULE,
326 },
327};
328module_platform_driver(lp8788_bl_driver);
329
330MODULE_DESCRIPTION("Texas Instruments LP8788 Backlight Driver");
331MODULE_AUTHOR("Milo Kim");
332MODULE_LICENSE("GPL");
333MODULE_ALIAS("platform:lp8788-backlight");