aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-09-26 13:49:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-26 13:49:42 -0400
commitd910fc786014ac3fb72f837c329c112e0c7a9aea (patch)
tree32f6c6eb4fdcf60fc0384f94502862cb24b8ab38 /drivers
parent1d1764c39815db55e10b2d78732db4d6dd9d6039 (diff)
parenta7998cecf5073e0755feeb7fd50b2bdc08dea6bd (diff)
Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight
* 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight: backlight: new driver for ADP5520/ADP5501 MFD PMICs backlight: extend event support to also support poll() backlight/eeepc-laptop: Update the backlight state when we change brightness backlight/acpi: Update the backlight state when we change brightness backlight: Allow drivers to update the core, and generate events on changes backlight: switch to da903x driver to dev_pm_ops backlight: Add support for the Avionic Design Xanthos backlight device. backlight: spi driver for LMS283GF05 LCD backlight: move hp680-bl's probe function to .devinit.text backlight: Add support for new Apple machines. backlight: mbp_nvidia_bl: add support for MacBookAir 1,1 backlight: Add WM831x backlight driver Trivial conflicts due to '#ifdef CONFIG_PM' differences in drivers/video/backlight/da903x_bl.c
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/video.c4
-rw-r--r--drivers/platform/x86/eeepc-laptop.c2
-rw-r--r--drivers/video/backlight/Kconfig33
-rw-r--r--drivers/video/backlight/Makefile4
-rw-r--r--drivers/video/backlight/adp5520_bl.c377
-rw-r--r--drivers/video/backlight/adx_bl.c178
-rw-r--r--drivers/video/backlight/backlight.c42
-rw-r--r--drivers/video/backlight/hp680_bl.c2
-rw-r--r--drivers/video/backlight/lms283gf05.c242
-rw-r--r--drivers/video/backlight/mbp_nvidia_bl.c36
-rw-r--r--drivers/video/backlight/wm831x_bl.c250
11 files changed, 1168 insertions, 2 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 94b1a4c5abab..a4fddb24476f 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1986,6 +1986,10 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
1986 1986
1987 result = acpi_video_device_lcd_set_level(device, level_next); 1987 result = acpi_video_device_lcd_set_level(device, level_next);
1988 1988
1989 if (!result)
1990 backlight_force_update(device->backlight,
1991 BACKLIGHT_UPDATE_HOTKEY);
1992
1989out: 1993out:
1990 if (result) 1994 if (result)
1991 printk(KERN_ERR PREFIX "Failed to switch the brightness\n"); 1995 printk(KERN_ERR PREFIX "Failed to switch the brightness\n");
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index da3c08b3dcc1..749e2102b2be 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -624,7 +624,7 @@ static int notify_brn(void)
624 struct backlight_device *bd = eeepc_backlight_device; 624 struct backlight_device *bd = eeepc_backlight_device;
625 if (bd) { 625 if (bd) {
626 int old = bd->props.brightness; 626 int old = bd->props.brightness;
627 bd->props.brightness = read_brightness(bd); 627 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
628 return old; 628 return old;
629 } 629 }
630 return -1; 630 return -1;
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 90861cd93165..09bfa9662e4d 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -31,6 +31,13 @@ config LCD_CORGI
31 Say y here to support the LCD panels usually found on SHARP 31 Say y here to support the LCD panels usually found on SHARP
32 corgi (C7x0) and spitz (Cxx00) models. 32 corgi (C7x0) and spitz (Cxx00) models.
33 33
34config LCD_LMS283GF05
35 tristate "Samsung LMS283GF05 LCD"
36 depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO
37 help
38 SPI driver for Samsung LMS283GF05. This provides basic support
39 for powering the LCD up/down through a sysfs interface.
40
34config LCD_LTV350QV 41config LCD_LTV350QV
35 tristate "Samsung LTV350QV LCD Panel" 42 tristate "Samsung LTV350QV LCD Panel"
36 depends on LCD_CLASS_DEVICE && SPI_MASTER 43 depends on LCD_CLASS_DEVICE && SPI_MASTER
@@ -229,3 +236,29 @@ config BACKLIGHT_SAHARA
229 help 236 help
230 If you have a Tabletkiosk Sahara Touch-iT, say y to enable the 237 If you have a Tabletkiosk Sahara Touch-iT, say y to enable the
231 backlight driver. 238 backlight driver.
239
240config BACKLIGHT_WM831X
241 tristate "WM831x PMIC Backlight Driver"
242 depends on BACKLIGHT_CLASS_DEVICE && MFD_WM831X
243 help
244 If you have a backlight driven by the ISINK and DCDC of a
245 WM831x PMIC say y to enable the backlight driver for it.
246
247config BACKLIGHT_ADX
248 tristate "Avionic Design Xanthos Backlight Driver"
249 depends on BACKLIGHT_CLASS_DEVICE && ARCH_PXA_ADX
250 default y
251 help
252 Say Y to enable the backlight driver on Avionic Design Xanthos-based
253 boards.
254
255config BACKLIGHT_ADP5520
256 tristate "Backlight Driver for ADP5520/ADP5501 using WLED"
257 depends on BACKLIGHT_CLASS_DEVICE && PMIC_ADP5520
258 help
259 If you have a LCD backlight connected to the BST/BL_SNK output of
260 ADP5520 or ADP5501, say Y here to enable this driver.
261
262 To compile this driver as a module, choose M here: the module will
263 be called adp5520_bl.
264
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 4eb178c1d684..9a405548874c 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -3,6 +3,7 @@
3obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o 3obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
4obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o 4obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o
5obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o 5obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o
6obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o
6obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o 7obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
7obj-$(CONFIG_LCD_ILI9320) += ili9320.o 8obj-$(CONFIG_LCD_ILI9320) += ili9320.o
8obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o 9obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
@@ -24,4 +25,7 @@ obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
24obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o 25obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o
25obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o 26obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
26obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o 27obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
28obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
29obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o
30obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o
27 31
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
new file mode 100644
index 000000000000..ad05da5ba3c7
--- /dev/null
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -0,0 +1,377 @@
1/*
2 * Backlight driver for Analog Devices ADP5520/ADP5501 MFD PMICs
3 *
4 * Copyright 2009 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/platform_device.h>
12#include <linux/fb.h>
13#include <linux/backlight.h>
14#include <linux/mfd/adp5520.h>
15
16struct adp5520_bl {
17 struct device *master;
18 struct adp5520_backlight_platfrom_data *pdata;
19 struct mutex lock;
20 unsigned long cached_daylight_max;
21 int id;
22 int current_brightness;
23};
24
25static int adp5520_bl_set(struct backlight_device *bl, int brightness)
26{
27 struct adp5520_bl *data = bl_get_data(bl);
28 struct device *master = data->master;
29 int ret = 0;
30
31 if (data->pdata->en_ambl_sens) {
32 if ((brightness > 0) && (brightness < ADP5020_MAX_BRIGHTNESS)) {
33 /* Disable Ambient Light auto adjust */
34 ret |= adp5520_clr_bits(master, BL_CONTROL,
35 BL_AUTO_ADJ);
36 ret |= adp5520_write(master, DAYLIGHT_MAX, brightness);
37 } else {
38 /*
39 * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
40 * restore daylight l3 sysfs brightness
41 */
42 ret |= adp5520_write(master, DAYLIGHT_MAX,
43 data->cached_daylight_max);
44 ret |= adp5520_set_bits(master, BL_CONTROL,
45 BL_AUTO_ADJ);
46 }
47 } else {
48 ret |= adp5520_write(master, DAYLIGHT_MAX, brightness);
49 }
50
51 if (data->current_brightness && brightness == 0)
52 ret |= adp5520_set_bits(master,
53 MODE_STATUS, DIM_EN);
54 else if (data->current_brightness == 0 && brightness)
55 ret |= adp5520_clr_bits(master,
56 MODE_STATUS, DIM_EN);
57
58 if (!ret)
59 data->current_brightness = brightness;
60
61 return ret;
62}
63
64static int adp5520_bl_update_status(struct backlight_device *bl)
65{
66 int brightness = bl->props.brightness;
67 if (bl->props.power != FB_BLANK_UNBLANK)
68 brightness = 0;
69
70 if (bl->props.fb_blank != FB_BLANK_UNBLANK)
71 brightness = 0;
72
73 return adp5520_bl_set(bl, brightness);
74}
75
76static int adp5520_bl_get_brightness(struct backlight_device *bl)
77{
78 struct adp5520_bl *data = bl_get_data(bl);
79 int error;
80 uint8_t reg_val;
81
82 error = adp5520_read(data->master, BL_VALUE, &reg_val);
83
84 return error ? data->current_brightness : reg_val;
85}
86
87static struct backlight_ops adp5520_bl_ops = {
88 .update_status = adp5520_bl_update_status,
89 .get_brightness = adp5520_bl_get_brightness,
90};
91
92static int adp5520_bl_setup(struct backlight_device *bl)
93{
94 struct adp5520_bl *data = bl_get_data(bl);
95 struct device *master = data->master;
96 struct adp5520_backlight_platfrom_data *pdata = data->pdata;
97 int ret = 0;
98
99 ret |= adp5520_write(master, DAYLIGHT_MAX, pdata->l1_daylight_max);
100 ret |= adp5520_write(master, DAYLIGHT_DIM, pdata->l1_daylight_dim);
101
102 if (pdata->en_ambl_sens) {
103 data->cached_daylight_max = pdata->l1_daylight_max;
104 ret |= adp5520_write(master, OFFICE_MAX, pdata->l2_office_max);
105 ret |= adp5520_write(master, OFFICE_DIM, pdata->l2_office_dim);
106 ret |= adp5520_write(master, DARK_MAX, pdata->l3_dark_max);
107 ret |= adp5520_write(master, DARK_DIM, pdata->l3_dark_dim);
108 ret |= adp5520_write(master, L2_TRIP, pdata->l2_trip);
109 ret |= adp5520_write(master, L2_HYS, pdata->l2_hyst);
110 ret |= adp5520_write(master, L3_TRIP, pdata->l3_trip);
111 ret |= adp5520_write(master, L3_HYS, pdata->l3_hyst);
112 ret |= adp5520_write(master, ALS_CMPR_CFG,
113 ALS_CMPR_CFG_VAL(pdata->abml_filt, L3_EN));
114 }
115
116 ret |= adp5520_write(master, BL_CONTROL,
117 BL_CTRL_VAL(pdata->fade_led_law, pdata->en_ambl_sens));
118
119 ret |= adp5520_write(master, BL_FADE, FADE_VAL(pdata->fade_in,
120 pdata->fade_out));
121
122 ret |= adp5520_set_bits(master, MODE_STATUS, BL_EN | DIM_EN);
123
124 return ret;
125}
126
127static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
128{
129 struct adp5520_bl *data = dev_get_drvdata(dev);
130 int error;
131 uint8_t reg_val;
132
133 mutex_lock(&data->lock);
134 error = adp5520_read(data->master, reg, &reg_val);
135 mutex_unlock(&data->lock);
136
137 return sprintf(buf, "%u\n", reg_val);
138}
139
140static ssize_t adp5520_store(struct device *dev, const char *buf,
141 size_t count, int reg)
142{
143 struct adp5520_bl *data = dev_get_drvdata(dev);
144 unsigned long val;
145 int ret;
146
147 ret = strict_strtoul(buf, 10, &val);
148 if (ret)
149 return ret;
150
151 mutex_lock(&data->lock);
152 adp5520_write(data->master, reg, val);
153 mutex_unlock(&data->lock);
154
155 return count;
156}
157
158static ssize_t adp5520_bl_dark_max_show(struct device *dev,
159 struct device_attribute *attr, char *buf)
160{
161 return adp5520_show(dev, buf, DARK_MAX);
162}
163
164static ssize_t adp5520_bl_dark_max_store(struct device *dev,
165 struct device_attribute *attr, const char *buf, size_t count)
166{
167 return adp5520_store(dev, buf, count, DARK_MAX);
168}
169static DEVICE_ATTR(dark_max, 0664, adp5520_bl_dark_max_show,
170 adp5520_bl_dark_max_store);
171
172static ssize_t adp5520_bl_office_max_show(struct device *dev,
173 struct device_attribute *attr, char *buf)
174{
175 return adp5520_show(dev, buf, OFFICE_MAX);
176}
177
178static ssize_t adp5520_bl_office_max_store(struct device *dev,
179 struct device_attribute *attr, const char *buf, size_t count)
180{
181 return adp5520_store(dev, buf, count, OFFICE_MAX);
182}
183static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show,
184 adp5520_bl_office_max_store);
185
186static ssize_t adp5520_bl_daylight_max_show(struct device *dev,
187 struct device_attribute *attr, char *buf)
188{
189 return adp5520_show(dev, buf, DAYLIGHT_MAX);
190}
191
192static ssize_t adp5520_bl_daylight_max_store(struct device *dev,
193 struct device_attribute *attr, const char *buf, size_t count)
194{
195 struct adp5520_bl *data = dev_get_drvdata(dev);
196
197 strict_strtoul(buf, 10, &data->cached_daylight_max);
198 return adp5520_store(dev, buf, count, DAYLIGHT_MAX);
199}
200static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
201 adp5520_bl_daylight_max_store);
202
203static ssize_t adp5520_bl_dark_dim_show(struct device *dev,
204 struct device_attribute *attr, char *buf)
205{
206 return adp5520_show(dev, buf, DARK_DIM);
207}
208
209static ssize_t adp5520_bl_dark_dim_store(struct device *dev,
210 struct device_attribute *attr,
211 const char *buf, size_t count)
212{
213 return adp5520_store(dev, buf, count, DARK_DIM);
214}
215static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show,
216 adp5520_bl_dark_dim_store);
217
218static ssize_t adp5520_bl_office_dim_show(struct device *dev,
219 struct device_attribute *attr, char *buf)
220{
221 return adp5520_show(dev, buf, OFFICE_DIM);
222}
223
224static ssize_t adp5520_bl_office_dim_store(struct device *dev,
225 struct device_attribute *attr,
226 const char *buf, size_t count)
227{
228 return adp5520_store(dev, buf, count, OFFICE_DIM);
229}
230static DEVICE_ATTR(office_dim, 0664, adp5520_bl_office_dim_show,
231 adp5520_bl_office_dim_store);
232
233static ssize_t adp5520_bl_daylight_dim_show(struct device *dev,
234 struct device_attribute *attr, char *buf)
235{
236 return adp5520_show(dev, buf, DAYLIGHT_DIM);
237}
238
239static ssize_t adp5520_bl_daylight_dim_store(struct device *dev,
240 struct device_attribute *attr,
241 const char *buf, size_t count)
242{
243 return adp5520_store(dev, buf, count, DAYLIGHT_DIM);
244}
245static DEVICE_ATTR(daylight_dim, 0664, adp5520_bl_daylight_dim_show,
246 adp5520_bl_daylight_dim_store);
247
248static struct attribute *adp5520_bl_attributes[] = {
249 &dev_attr_dark_max.attr,
250 &dev_attr_dark_dim.attr,
251 &dev_attr_office_max.attr,
252 &dev_attr_office_dim.attr,
253 &dev_attr_daylight_max.attr,
254 &dev_attr_daylight_dim.attr,
255 NULL
256};
257
258static const struct attribute_group adp5520_bl_attr_group = {
259 .attrs = adp5520_bl_attributes,
260};
261
262static int __devinit adp5520_bl_probe(struct platform_device *pdev)
263{
264 struct backlight_device *bl;
265 struct adp5520_bl *data;
266 int ret = 0;
267
268 data = kzalloc(sizeof(*data), GFP_KERNEL);
269 if (data == NULL)
270 return -ENOMEM;
271
272 data->master = pdev->dev.parent;
273 data->pdata = pdev->dev.platform_data;
274
275 if (data->pdata == NULL) {
276 dev_err(&pdev->dev, "missing platform data\n");
277 kfree(data);
278 return -ENODEV;
279 }
280
281 data->id = pdev->id;
282 data->current_brightness = 0;
283
284 mutex_init(&data->lock);
285
286 bl = backlight_device_register(pdev->name, data->master,
287 data, &adp5520_bl_ops);
288 if (IS_ERR(bl)) {
289 dev_err(&pdev->dev, "failed to register backlight\n");
290 kfree(data);
291 return PTR_ERR(bl);
292 }
293
294 bl->props.max_brightness =
295 bl->props.brightness = ADP5020_MAX_BRIGHTNESS;
296
297 if (data->pdata->en_ambl_sens)
298 ret = sysfs_create_group(&bl->dev.kobj,
299 &adp5520_bl_attr_group);
300
301 if (ret) {
302 dev_err(&pdev->dev, "failed to register sysfs\n");
303 backlight_device_unregister(bl);
304 kfree(data);
305 }
306
307 platform_set_drvdata(pdev, bl);
308 ret |= adp5520_bl_setup(bl);
309 backlight_update_status(bl);
310
311 return ret;
312}
313
314static int __devexit adp5520_bl_remove(struct platform_device *pdev)
315{
316 struct backlight_device *bl = platform_get_drvdata(pdev);
317 struct adp5520_bl *data = bl_get_data(bl);
318
319 adp5520_clr_bits(data->master, MODE_STATUS, BL_EN);
320
321 if (data->pdata->en_ambl_sens)
322 sysfs_remove_group(&bl->dev.kobj,
323 &adp5520_bl_attr_group);
324
325 backlight_device_unregister(bl);
326 kfree(data);
327
328 return 0;
329}
330
331#ifdef CONFIG_PM
332static int adp5520_bl_suspend(struct platform_device *pdev,
333 pm_message_t state)
334{
335 struct backlight_device *bl = platform_get_drvdata(pdev);
336 return adp5520_bl_set(bl, 0);
337}
338
339static int adp5520_bl_resume(struct platform_device *pdev)
340{
341 struct backlight_device *bl = platform_get_drvdata(pdev);
342
343 backlight_update_status(bl);
344 return 0;
345}
346#else
347#define adp5520_bl_suspend NULL
348#define adp5520_bl_resume NULL
349#endif
350
351static struct platform_driver adp5520_bl_driver = {
352 .driver = {
353 .name = "adp5520-backlight",
354 .owner = THIS_MODULE,
355 },
356 .probe = adp5520_bl_probe,
357 .remove = __devexit_p(adp5520_bl_remove),
358 .suspend = adp5520_bl_suspend,
359 .resume = adp5520_bl_resume,
360};
361
362static int __init adp5520_bl_init(void)
363{
364 return platform_driver_register(&adp5520_bl_driver);
365}
366module_init(adp5520_bl_init);
367
368static void __exit adp5520_bl_exit(void)
369{
370 platform_driver_unregister(&adp5520_bl_driver);
371}
372module_exit(adp5520_bl_exit);
373
374MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
375MODULE_DESCRIPTION("ADP5520(01) Backlight Driver");
376MODULE_LICENSE("GPL");
377MODULE_ALIAS("platform:adp5520-backlight");
diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c
new file mode 100644
index 000000000000..2c3bdfc620b7
--- /dev/null
+++ b/drivers/video/backlight/adx_bl.c
@@ -0,0 +1,178 @@
1/*
2 * linux/drivers/video/backlight/adx.c
3 *
4 * Copyright (C) 2009 Avionic Design GmbH
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 * Written by Thierry Reding <thierry.reding@avionic-design.de>
11 */
12
13#include <linux/backlight.h>
14#include <linux/fb.h>
15#include <linux/io.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18
19/* register definitions */
20#define ADX_BACKLIGHT_CONTROL 0x00
21#define ADX_BACKLIGHT_CONTROL_ENABLE (1 << 0)
22#define ADX_BACKLIGHT_BRIGHTNESS 0x08
23#define ADX_BACKLIGHT_STATUS 0x10
24#define ADX_BACKLIGHT_ERROR 0x18
25
26struct adxbl {
27 void __iomem *base;
28};
29
30static int adx_backlight_update_status(struct backlight_device *bldev)
31{
32 struct adxbl *bl = bl_get_data(bldev);
33 u32 value;
34
35 value = bldev->props.brightness;
36 writel(value, bl->base + ADX_BACKLIGHT_BRIGHTNESS);
37
38 value = readl(bl->base + ADX_BACKLIGHT_CONTROL);
39
40 if (bldev->props.state & BL_CORE_FBBLANK)
41 value &= ~ADX_BACKLIGHT_CONTROL_ENABLE;
42 else
43 value |= ADX_BACKLIGHT_CONTROL_ENABLE;
44
45 writel(value, bl->base + ADX_BACKLIGHT_CONTROL);
46
47 return 0;
48}
49
50static int adx_backlight_get_brightness(struct backlight_device *bldev)
51{
52 struct adxbl *bl = bl_get_data(bldev);
53 u32 brightness;
54
55 brightness = readl(bl->base + ADX_BACKLIGHT_BRIGHTNESS);
56 return brightness & 0xff;
57}
58
59static int adx_backlight_check_fb(struct fb_info *fb)
60{
61 return 1;
62}
63
64static struct backlight_ops adx_backlight_ops = {
65 .options = 0,
66 .update_status = adx_backlight_update_status,
67 .get_brightness = adx_backlight_get_brightness,
68 .check_fb = adx_backlight_check_fb,
69};
70
71static int __devinit adx_backlight_probe(struct platform_device *pdev)
72{
73 struct backlight_device *bldev;
74 struct resource *res;
75 struct adxbl *bl;
76 int ret = 0;
77
78 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
79 if (!res) {
80 ret = -ENXIO;
81 goto out;
82 }
83
84 res = devm_request_mem_region(&pdev->dev, res->start,
85 resource_size(res), res->name);
86 if (!res) {
87 ret = -ENXIO;
88 goto out;
89 }
90
91 bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL);
92 if (!bl) {
93 ret = -ENOMEM;
94 goto out;
95 }
96
97 bl->base = devm_ioremap_nocache(&pdev->dev, res->start,
98 resource_size(res));
99 if (!bl->base) {
100 ret = -ENXIO;
101 goto out;
102 }
103
104 bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, bl,
105 &adx_backlight_ops);
106 if (!bldev) {
107 ret = -ENOMEM;
108 goto out;
109 }
110
111 bldev->props.max_brightness = 0xff;
112 bldev->props.brightness = 0xff;
113 bldev->props.power = FB_BLANK_UNBLANK;
114
115 platform_set_drvdata(pdev, bldev);
116
117out:
118 return ret;
119}
120
121static int __devexit adx_backlight_remove(struct platform_device *pdev)
122{
123 struct backlight_device *bldev;
124 int ret = 0;
125
126 bldev = platform_get_drvdata(pdev);
127 bldev->props.power = FB_BLANK_UNBLANK;
128 bldev->props.brightness = 0xff;
129 backlight_update_status(bldev);
130 backlight_device_unregister(bldev);
131 platform_set_drvdata(pdev, NULL);
132
133 return ret;
134}
135
136#ifdef CONFIG_PM
137static int adx_backlight_suspend(struct platform_device *pdev,
138 pm_message_t state)
139{
140 return 0;
141}
142
143static int adx_backlight_resume(struct platform_device *pdev)
144{
145 return 0;
146}
147#else
148#define adx_backlight_suspend NULL
149#define adx_backlight_resume NULL
150#endif
151
152static struct platform_driver adx_backlight_driver = {
153 .probe = adx_backlight_probe,
154 .remove = __devexit_p(adx_backlight_remove),
155 .suspend = adx_backlight_suspend,
156 .resume = adx_backlight_resume,
157 .driver = {
158 .name = "adx-backlight",
159 .owner = THIS_MODULE,
160 },
161};
162
163static int __init adx_backlight_init(void)
164{
165 return platform_driver_register(&adx_backlight_driver);
166}
167
168static void __exit adx_backlight_exit(void)
169{
170 platform_driver_unregister(&adx_backlight_driver);
171}
172
173module_init(adx_backlight_init);
174module_exit(adx_backlight_exit);
175
176MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
177MODULE_DESCRIPTION("Avionic Design Xanthos Backlight Driver");
178MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 157057c79ca3..6615ac7fa60a 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -73,6 +73,27 @@ static inline void backlight_unregister_fb(struct backlight_device *bd)
73} 73}
74#endif /* CONFIG_FB */ 74#endif /* CONFIG_FB */
75 75
76static void backlight_generate_event(struct backlight_device *bd,
77 enum backlight_update_reason reason)
78{
79 char *envp[2];
80
81 switch (reason) {
82 case BACKLIGHT_UPDATE_SYSFS:
83 envp[0] = "SOURCE=sysfs";
84 break;
85 case BACKLIGHT_UPDATE_HOTKEY:
86 envp[0] = "SOURCE=hotkey";
87 break;
88 default:
89 envp[0] = "SOURCE=unknown";
90 break;
91 }
92 envp[1] = NULL;
93 kobject_uevent_env(&bd->dev.kobj, KOBJ_CHANGE, envp);
94 sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness");
95}
96
76static ssize_t backlight_show_power(struct device *dev, 97static ssize_t backlight_show_power(struct device *dev,
77 struct device_attribute *attr,char *buf) 98 struct device_attribute *attr,char *buf)
78{ 99{
@@ -142,6 +163,8 @@ static ssize_t backlight_store_brightness(struct device *dev,
142 } 163 }
143 mutex_unlock(&bd->ops_lock); 164 mutex_unlock(&bd->ops_lock);
144 165
166 backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS);
167
145 return rc; 168 return rc;
146} 169}
147 170
@@ -214,6 +237,25 @@ static struct device_attribute bl_device_attributes[] = {
214}; 237};
215 238
216/** 239/**
240 * backlight_force_update - tell the backlight subsystem that hardware state
241 * has changed
242 * @bd: the backlight device to update
243 *
244 * Updates the internal state of the backlight in response to a hardware event,
245 * and generate a uevent to notify userspace
246 */
247void backlight_force_update(struct backlight_device *bd,
248 enum backlight_update_reason reason)
249{
250 mutex_lock(&bd->ops_lock);
251 if (bd->ops && bd->ops->get_brightness)
252 bd->props.brightness = bd->ops->get_brightness(bd);
253 mutex_unlock(&bd->ops_lock);
254 backlight_generate_event(bd, reason);
255}
256EXPORT_SYMBOL(backlight_force_update);
257
258/**
217 * backlight_device_register - create and register a new object of 259 * backlight_device_register - create and register a new object of
218 * backlight_device class. 260 * backlight_device class.
219 * @name: the name of the new object(must be the same as the name of the 261 * @name: the name of the new object(must be the same as the name of the
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 5be55a20d8c7..7fb4eefff80d 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -103,7 +103,7 @@ static struct backlight_ops hp680bl_ops = {
103 .update_status = hp680bl_set_intensity, 103 .update_status = hp680bl_set_intensity,
104}; 104};
105 105
106static int __init hp680bl_probe(struct platform_device *pdev) 106static int __devinit hp680bl_probe(struct platform_device *pdev)
107{ 107{
108 struct backlight_device *bd; 108 struct backlight_device *bd;
109 109
diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c
new file mode 100644
index 000000000000..447b542a20ca
--- /dev/null
+++ b/drivers/video/backlight/lms283gf05.c
@@ -0,0 +1,242 @@
1/*
2 * lms283gf05.c -- support for Samsung LMS283GF05 LCD
3 *
4 * Copyright (c) 2009 Marek Vasut <marek.vasut@gmail.com>
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#include <linux/device.h>
12#include <linux/kernel.h>
13#include <linux/delay.h>
14#include <linux/gpio.h>
15#include <linux/lcd.h>
16
17#include <linux/spi/spi.h>
18#include <linux/spi/lms283gf05.h>
19
20struct lms283gf05_state {
21 struct spi_device *spi;
22 struct lcd_device *ld;
23};
24
25struct lms283gf05_seq {
26 unsigned char reg;
27 unsigned short value;
28 unsigned char delay;
29};
30
31/* Magic sequences supplied by manufacturer, for details refer to datasheet */
32static struct lms283gf05_seq disp_initseq[] = {
33 /* REG, VALUE, DELAY */
34 { 0x07, 0x0000, 0 },
35 { 0x13, 0x0000, 10 },
36
37 { 0x11, 0x3004, 0 },
38 { 0x14, 0x200F, 0 },
39 { 0x10, 0x1a20, 0 },
40 { 0x13, 0x0040, 50 },
41
42 { 0x13, 0x0060, 0 },
43 { 0x13, 0x0070, 200 },
44
45 { 0x01, 0x0127, 0 },
46 { 0x02, 0x0700, 0 },
47 { 0x03, 0x1030, 0 },
48 { 0x08, 0x0208, 0 },
49 { 0x0B, 0x0620, 0 },
50 { 0x0C, 0x0110, 0 },
51 { 0x30, 0x0120, 0 },
52 { 0x31, 0x0127, 0 },
53 { 0x32, 0x0000, 0 },
54 { 0x33, 0x0503, 0 },
55 { 0x34, 0x0727, 0 },
56 { 0x35, 0x0124, 0 },
57 { 0x36, 0x0706, 0 },
58 { 0x37, 0x0701, 0 },
59 { 0x38, 0x0F00, 0 },
60 { 0x39, 0x0F00, 0 },
61 { 0x40, 0x0000, 0 },
62 { 0x41, 0x0000, 0 },
63 { 0x42, 0x013f, 0 },
64 { 0x43, 0x0000, 0 },
65 { 0x44, 0x013f, 0 },
66 { 0x45, 0x0000, 0 },
67 { 0x46, 0xef00, 0 },
68 { 0x47, 0x013f, 0 },
69 { 0x48, 0x0000, 0 },
70 { 0x07, 0x0015, 30 },
71
72 { 0x07, 0x0017, 0 },
73
74 { 0x20, 0x0000, 0 },
75 { 0x21, 0x0000, 0 },
76 { 0x22, 0x0000, 0 }
77};
78
79static struct lms283gf05_seq disp_pdwnseq[] = {
80 { 0x07, 0x0016, 30 },
81
82 { 0x07, 0x0004, 0 },
83 { 0x10, 0x0220, 20 },
84
85 { 0x13, 0x0060, 50 },
86
87 { 0x13, 0x0040, 50 },
88
89 { 0x13, 0x0000, 0 },
90 { 0x10, 0x0000, 0 }
91};
92
93
94static void lms283gf05_reset(unsigned long gpio, bool inverted)
95{
96 gpio_set_value(gpio, !inverted);
97 mdelay(100);
98 gpio_set_value(gpio, inverted);
99 mdelay(20);
100 gpio_set_value(gpio, !inverted);
101 mdelay(20);
102}
103
104static void lms283gf05_toggle(struct spi_device *spi,
105 struct lms283gf05_seq *seq, int sz)
106{
107 char buf[3];
108 int i;
109
110 for (i = 0; i < sz; i++) {
111 buf[0] = 0x74;
112 buf[1] = 0x00;
113 buf[2] = seq[i].reg;
114 spi_write(spi, buf, 3);
115
116 buf[0] = 0x76;
117 buf[1] = seq[i].value >> 8;
118 buf[2] = seq[i].value & 0xff;
119 spi_write(spi, buf, 3);
120
121 mdelay(seq[i].delay);
122 }
123}
124
125static int lms283gf05_power_set(struct lcd_device *ld, int power)
126{
127 struct lms283gf05_state *st = lcd_get_data(ld);
128 struct spi_device *spi = st->spi;
129 struct lms283gf05_pdata *pdata = spi->dev.platform_data;
130
131 if (power) {
132 if (pdata)
133 lms283gf05_reset(pdata->reset_gpio,
134 pdata->reset_inverted);
135 lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq));
136 } else {
137 lms283gf05_toggle(spi, disp_pdwnseq, ARRAY_SIZE(disp_pdwnseq));
138 if (pdata)
139 gpio_set_value(pdata->reset_gpio,
140 pdata->reset_inverted);
141 }
142
143 return 0;
144}
145
146static struct lcd_ops lms_ops = {
147 .set_power = lms283gf05_power_set,
148 .get_power = NULL,
149};
150
151static int __devinit lms283gf05_probe(struct spi_device *spi)
152{
153 struct lms283gf05_state *st;
154 struct lms283gf05_pdata *pdata = spi->dev.platform_data;
155 struct lcd_device *ld;
156 int ret = 0;
157
158 if (pdata != NULL) {
159 ret = gpio_request(pdata->reset_gpio, "LMS285GF05 RESET");
160 if (ret)
161 return ret;
162
163 ret = gpio_direction_output(pdata->reset_gpio,
164 !pdata->reset_inverted);
165 if (ret)
166 goto err;
167 }
168
169 st = kzalloc(sizeof(struct lms283gf05_state), GFP_KERNEL);
170 if (st == NULL) {
171 dev_err(&spi->dev, "No memory for device state\n");
172 ret = -ENOMEM;
173 goto err;
174 }
175
176 ld = lcd_device_register("lms283gf05", &spi->dev, st, &lms_ops);
177 if (IS_ERR(ld)) {
178 ret = PTR_ERR(ld);
179 goto err2;
180 }
181
182 st->spi = spi;
183 st->ld = ld;
184
185 dev_set_drvdata(&spi->dev, st);
186
187 /* kick in the LCD */
188 if (pdata)
189 lms283gf05_reset(pdata->reset_gpio, pdata->reset_inverted);
190 lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq));
191
192 return 0;
193
194err2:
195 kfree(st);
196err:
197 if (pdata != NULL)
198 gpio_free(pdata->reset_gpio);
199
200 return ret;
201}
202
203static int __devexit lms283gf05_remove(struct spi_device *spi)
204{
205 struct lms283gf05_state *st = dev_get_drvdata(&spi->dev);
206 struct lms283gf05_pdata *pdata = st->spi->dev.platform_data;
207
208 lcd_device_unregister(st->ld);
209
210 if (pdata != NULL)
211 gpio_free(pdata->reset_gpio);
212
213 kfree(st);
214
215 return 0;
216}
217
218static struct spi_driver lms283gf05_driver = {
219 .driver = {
220 .name = "lms283gf05",
221 .owner = THIS_MODULE,
222 },
223 .probe = lms283gf05_probe,
224 .remove = __devexit_p(lms283gf05_remove),
225};
226
227static __init int lms283gf05_init(void)
228{
229 return spi_register_driver(&lms283gf05_driver);
230}
231
232static __exit void lms283gf05_exit(void)
233{
234 spi_unregister_driver(&lms283gf05_driver);
235}
236
237module_init(lms283gf05_init);
238module_exit(lms283gf05_exit);
239
240MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
241MODULE_DESCRIPTION("LCD283GF05 LCD");
242MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 3bb4c0a50c62..9edb8d7c295f 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -166,6 +166,15 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
166 }, 166 },
167 { 167 {
168 .callback = mbp_dmi_match, 168 .callback = mbp_dmi_match,
169 .ident = "MacBookAir 1,1",
170 .matches = {
171 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
172 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir1,1"),
173 },
174 .driver_data = (void *)&intel_chipset_data,
175 },
176 {
177 .callback = mbp_dmi_match,
169 .ident = "MacBook 5,1", 178 .ident = "MacBook 5,1",
170 .matches = { 179 .matches = {
171 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 180 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
@@ -175,6 +184,15 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
175 }, 184 },
176 { 185 {
177 .callback = mbp_dmi_match, 186 .callback = mbp_dmi_match,
187 .ident = "MacBook 5,2",
188 .matches = {
189 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
190 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,2"),
191 },
192 .driver_data = (void *)&nvidia_chipset_data,
193 },
194 {
195 .callback = mbp_dmi_match,
178 .ident = "MacBookAir 2,1", 196 .ident = "MacBookAir 2,1",
179 .matches = { 197 .matches = {
180 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 198 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
@@ -191,6 +209,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
191 }, 209 },
192 .driver_data = (void *)&nvidia_chipset_data, 210 .driver_data = (void *)&nvidia_chipset_data,
193 }, 211 },
212 {
213 .callback = mbp_dmi_match,
214 .ident = "MacBookPro 5,2",
215 .matches = {
216 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
217 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,2"),
218 },
219 .driver_data = (void *)&nvidia_chipset_data,
220 },
221 {
222 .callback = mbp_dmi_match,
223 .ident = "MacBookPro 5,5",
224 .matches = {
225 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
226 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,5"),
227 },
228 .driver_data = (void *)&nvidia_chipset_data,
229 },
194 { } 230 { }
195}; 231};
196 232
diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c
new file mode 100644
index 000000000000..467bdb7efb23
--- /dev/null
+++ b/drivers/video/backlight/wm831x_bl.c
@@ -0,0 +1,250 @@
1/*
2 * Backlight driver for Wolfson Microelectronics WM831x PMICs
3 *
4 * Copyright 2009 Wolfson Microelectonics plc
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#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/platform_device.h>
14#include <linux/fb.h>
15#include <linux/backlight.h>
16
17#include <linux/mfd/wm831x/core.h>
18#include <linux/mfd/wm831x/pdata.h>
19#include <linux/mfd/wm831x/regulator.h>
20
21struct wm831x_backlight_data {
22 struct wm831x *wm831x;
23 int isink_reg;
24 int current_brightness;
25};
26
27static int wm831x_backlight_set(struct backlight_device *bl, int brightness)
28{
29 struct wm831x_backlight_data *data = bl_get_data(bl);
30 struct wm831x *wm831x = data->wm831x;
31 int power_up = !data->current_brightness && brightness;
32 int power_down = data->current_brightness && !brightness;
33 int ret;
34
35 if (power_up) {
36 /* Enable the ISINK */
37 ret = wm831x_set_bits(wm831x, data->isink_reg,
38 WM831X_CS1_ENA, WM831X_CS1_ENA);
39 if (ret < 0)
40 goto err;
41
42 /* Enable the DC-DC */
43 ret = wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE,
44 WM831X_DC4_ENA, WM831X_DC4_ENA);
45 if (ret < 0)
46 goto err;
47 }
48
49 if (power_down) {
50 /* DCDC first */
51 ret = wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE,
52 WM831X_DC4_ENA, 0);
53 if (ret < 0)
54 goto err;
55
56 /* ISINK */
57 ret = wm831x_set_bits(wm831x, data->isink_reg,
58 WM831X_CS1_DRIVE | WM831X_CS1_ENA, 0);
59 if (ret < 0)
60 goto err;
61 }
62
63 /* Set the new brightness */
64 ret = wm831x_set_bits(wm831x, data->isink_reg,
65 WM831X_CS1_ISEL_MASK, brightness);
66 if (ret < 0)
67 goto err;
68
69 if (power_up) {
70 /* Drive current through the ISINK */
71 ret = wm831x_set_bits(wm831x, data->isink_reg,
72 WM831X_CS1_DRIVE, WM831X_CS1_DRIVE);
73 if (ret < 0)
74 return ret;
75 }
76
77 data->current_brightness = brightness;
78
79 return 0;
80
81err:
82 /* If we were in the middle of a power transition always shut down
83 * for safety.
84 */
85 if (power_up || power_down) {
86 wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0);
87 wm831x_set_bits(wm831x, data->isink_reg, WM831X_CS1_ENA, 0);
88 }
89
90 return ret;
91}
92
93static int wm831x_backlight_update_status(struct backlight_device *bl)
94{
95 int brightness = bl->props.brightness;
96
97 if (bl->props.power != FB_BLANK_UNBLANK)
98 brightness = 0;
99
100 if (bl->props.fb_blank != FB_BLANK_UNBLANK)
101 brightness = 0;
102
103 if (bl->props.state & BL_CORE_SUSPENDED)
104 brightness = 0;
105
106 return wm831x_backlight_set(bl, brightness);
107}
108
109static int wm831x_backlight_get_brightness(struct backlight_device *bl)
110{
111 struct wm831x_backlight_data *data = bl_get_data(bl);
112 return data->current_brightness;
113}
114
115static struct backlight_ops wm831x_backlight_ops = {
116 .options = BL_CORE_SUSPENDRESUME,
117 .update_status = wm831x_backlight_update_status,
118 .get_brightness = wm831x_backlight_get_brightness,
119};
120
121static int wm831x_backlight_probe(struct platform_device *pdev)
122{
123 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
124 struct wm831x_pdata *wm831x_pdata;
125 struct wm831x_backlight_pdata *pdata;
126 struct wm831x_backlight_data *data;
127 struct backlight_device *bl;
128 int ret, i, max_isel, isink_reg, dcdc_cfg;
129
130 /* We need platform data */
131 if (pdev->dev.parent->platform_data) {
132 wm831x_pdata = pdev->dev.parent->platform_data;
133 pdata = wm831x_pdata->backlight;
134 } else {
135 pdata = NULL;
136 }
137
138 if (!pdata) {
139 dev_err(&pdev->dev, "No platform data supplied\n");
140 return -EINVAL;
141 }
142
143 /* Figure out the maximum current we can use */
144 for (i = 0; i < WM831X_ISINK_MAX_ISEL; i++) {
145 if (wm831x_isinkv_values[i] > pdata->max_uA)
146 break;
147 }
148
149 if (i == 0) {
150 dev_err(&pdev->dev, "Invalid max_uA: %duA\n", pdata->max_uA);
151 return -EINVAL;
152 }
153 max_isel = i - 1;
154
155 if (pdata->max_uA != wm831x_isinkv_values[max_isel])
156 dev_warn(&pdev->dev,
157 "Maximum current is %duA not %duA as requested\n",
158 wm831x_isinkv_values[max_isel], pdata->max_uA);
159
160 switch (pdata->isink) {
161 case 1:
162 isink_reg = WM831X_CURRENT_SINK_1;
163 dcdc_cfg = 0;
164 break;
165 case 2:
166 isink_reg = WM831X_CURRENT_SINK_2;
167 dcdc_cfg = WM831X_DC4_FBSRC;
168 break;
169 default:
170 dev_err(&pdev->dev, "Invalid ISINK %d\n", pdata->isink);
171 return -EINVAL;
172 }
173
174 /* Configure the ISINK to use for feedback */
175 ret = wm831x_reg_unlock(wm831x);
176 if (ret < 0)
177 return ret;
178
179 ret = wm831x_set_bits(wm831x, WM831X_DC4_CONTROL, WM831X_DC4_FBSRC,
180 dcdc_cfg);
181
182 wm831x_reg_lock(wm831x);
183 if (ret < 0)
184 return ret;
185
186 data = kzalloc(sizeof(*data), GFP_KERNEL);
187 if (data == NULL)
188 return -ENOMEM;
189
190 data->wm831x = wm831x;
191 data->current_brightness = 0;
192 data->isink_reg = isink_reg;
193
194 bl = backlight_device_register("wm831x", &pdev->dev,
195 data, &wm831x_backlight_ops);
196 if (IS_ERR(bl)) {
197 dev_err(&pdev->dev, "failed to register backlight\n");
198 kfree(data);
199 return PTR_ERR(bl);
200 }
201
202 bl->props.max_brightness = max_isel;
203 bl->props.brightness = max_isel;
204
205 platform_set_drvdata(pdev, bl);
206
207 /* Disable the DCDC if it was started so we can bootstrap */
208 wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0);
209
210
211 backlight_update_status(bl);
212
213 return 0;
214}
215
216static int wm831x_backlight_remove(struct platform_device *pdev)
217{
218 struct backlight_device *bl = platform_get_drvdata(pdev);
219 struct wm831x_backlight_data *data = bl_get_data(bl);
220
221 backlight_device_unregister(bl);
222 kfree(data);
223 return 0;
224}
225
226static struct platform_driver wm831x_backlight_driver = {
227 .driver = {
228 .name = "wm831x-backlight",
229 .owner = THIS_MODULE,
230 },
231 .probe = wm831x_backlight_probe,
232 .remove = wm831x_backlight_remove,
233};
234
235static int __init wm831x_backlight_init(void)
236{
237 return platform_driver_register(&wm831x_backlight_driver);
238}
239module_init(wm831x_backlight_init);
240
241static void __exit wm831x_backlight_exit(void)
242{
243 platform_driver_unregister(&wm831x_backlight_driver);
244}
245module_exit(wm831x_backlight_exit);
246
247MODULE_DESCRIPTION("Backlight Driver for WM831x PMICs");
248MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com");
249MODULE_LICENSE("GPL");
250MODULE_ALIAS("platform:wm831x-backlight");