aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorKim, Milo <Milo.Kim@ti.com>2012-07-20 04:43:59 -0400
committerBryan Wu <bryan.wu@canonical.com>2012-07-26 00:04:33 -0400
commiteb80411b54fde031e9a8b368ff7b32c774ecfc5c (patch)
tree6b7183457dec3835c421a6e0a2c8242cb841180e /drivers/leds
parentb54cf35a7f656c61dd695509e8cf8cc7e1dc3e53 (diff)
leds: add new lp8788 led driver
TI LP8788 PMU has the current sink as the keyboard led driver. The brightness is controlled by the i2c commands. Configurable parameters can be defined in the platform side. Patch v2. (a) use workqueue on changing the brightness (b) use mutex_lock/unlock when the brightness is set and the led block of lp8788 device is enabled (c) remove err_dev on _probe() : just return as returned value if any errors (d) replace module_init/exit() with module_platform_driver() (e) add led configuration structure and loading them by default if platform data is null Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Bryan Wu <bryan.wu@canonical.com>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig7
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-lp8788.c192
3 files changed, 200 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index f0aaf415316d..c96bbaadeebd 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -200,6 +200,13 @@ config LEDS_LP5523
200 Driver provides direct control via LED class and interface for 200 Driver provides direct control via LED class and interface for
201 programming the engines. 201 programming the engines.
202 202
203config LEDS_LP8788
204 tristate "LED support for the TI LP8788 PMIC"
205 depends on LEDS_CLASS
206 depends on MFD_LP8788
207 help
208 This option enables support for the Keyboard LEDs on the LP8788 PMIC.
209
203config LEDS_CLEVO_MAIL 210config LEDS_CLEVO_MAIL
204 tristate "Mail LED on Clevo notebook" 211 tristate "Mail LED on Clevo notebook"
205 depends on LEDS_CLASS 212 depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index d94d18f8a4be..a4429a9217bc 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
24obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o 24obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
25obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o 25obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
26obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o 26obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o
27obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
27obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o 28obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
28obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o 29obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
29obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o 30obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c
new file mode 100644
index 000000000000..574b49f79093
--- /dev/null
+++ b/drivers/leds/leds-lp8788.c
@@ -0,0 +1,192 @@
1/*
2 * TI LP8788 MFD - keyled 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/module.h>
15#include <linux/slab.h>
16#include <linux/err.h>
17#include <linux/platform_device.h>
18#include <linux/leds.h>
19#include <linux/mutex.h>
20#include <linux/mfd/lp8788.h>
21#include <linux/mfd/lp8788-isink.h>
22
23#define MAX_BRIGHTNESS LP8788_ISINK_MAX_PWM
24#define DEFAULT_LED_NAME "keyboard-backlight"
25
26struct lp8788_led {
27 struct lp8788 *lp;
28 struct mutex lock;
29 struct work_struct work;
30 struct led_classdev led_dev;
31 enum lp8788_isink_number isink_num;
32 enum led_brightness brightness;
33 int on;
34};
35
36struct lp8788_led_config {
37 enum lp8788_isink_scale scale;
38 enum lp8788_isink_number num;
39 int iout;
40};
41
42static struct lp8788_led_config default_led_config = {
43 .scale = LP8788_ISINK_SCALE_100mA,
44 .num = LP8788_ISINK_3,
45 .iout = 0,
46};
47
48static int lp8788_led_init_device(struct lp8788_led *led,
49 struct lp8788_led_platform_data *pdata)
50{
51 struct lp8788_led_config *cfg = &default_led_config;
52 u8 addr, mask, val;
53 int ret;
54
55 if (pdata) {
56 cfg->scale = pdata->scale;
57 cfg->num = pdata->num;
58 cfg->iout = pdata->iout_code;
59 }
60
61 led->isink_num = cfg->num;
62
63 /* scale configuration */
64 addr = LP8788_ISINK_CTRL;
65 mask = 1 << (cfg->num + LP8788_ISINK_SCALE_OFFSET);
66 val = cfg->scale << cfg->num;
67 ret = lp8788_update_bits(led->lp, addr, mask, val);
68 if (ret)
69 return ret;
70
71 /* current configuration */
72 addr = lp8788_iout_addr[cfg->num];
73 mask = lp8788_iout_mask[cfg->num];
74 val = cfg->iout;
75
76 return lp8788_update_bits(led->lp, addr, mask, val);
77}
78
79static void lp8788_led_enable(struct lp8788_led *led,
80 enum lp8788_isink_number num, int on)
81{
82 u8 mask = 1 << num;
83 u8 val = on << num;
84
85 if (lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val))
86 return;
87
88 led->on = on;
89}
90
91static void lp8788_led_work(struct work_struct *work)
92{
93 struct lp8788_led *led = container_of(work, struct lp8788_led, work);
94 enum lp8788_isink_number num = led->isink_num;
95 int enable;
96 u8 val = led->brightness;
97
98 mutex_lock(&led->lock);
99
100 switch (num) {
101 case LP8788_ISINK_1:
102 case LP8788_ISINK_2:
103 case LP8788_ISINK_3:
104 lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val);
105 break;
106 default:
107 return;
108 }
109
110 enable = (val > 0) ? 1 : 0;
111 if (enable != led->on)
112 lp8788_led_enable(led, num, enable);
113
114 mutex_unlock(&led->lock);
115}
116
117static void lp8788_brightness_set(struct led_classdev *led_cdev,
118 enum led_brightness brt_val)
119{
120 struct lp8788_led *led =
121 container_of(led_cdev, struct lp8788_led, led_dev);
122
123 led->brightness = brt_val;
124 schedule_work(&led->work);
125}
126
127static __devinit int lp8788_led_probe(struct platform_device *pdev)
128{
129 struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
130 struct lp8788_led_platform_data *led_pdata;
131 struct lp8788_led *led;
132 int ret;
133
134 led = devm_kzalloc(lp->dev, sizeof(struct lp8788_led), GFP_KERNEL);
135 if (!led)
136 return -ENOMEM;
137
138 led->lp = lp;
139 led->led_dev.max_brightness = MAX_BRIGHTNESS;
140 led->led_dev.brightness_set = lp8788_brightness_set;
141
142 led_pdata = lp->pdata ? lp->pdata->led_pdata : NULL;
143
144 if (!led_pdata || !led_pdata->name)
145 led->led_dev.name = DEFAULT_LED_NAME;
146 else
147 led->led_dev.name = led_pdata->name;
148
149 mutex_init(&led->lock);
150 INIT_WORK(&led->work, lp8788_led_work);
151
152 platform_set_drvdata(pdev, led);
153
154 ret = lp8788_led_init_device(led, led_pdata);
155 if (ret) {
156 dev_err(lp->dev, "led init device err: %d\n", ret);
157 return ret;
158 }
159
160 ret = led_classdev_register(lp->dev, &led->led_dev);
161 if (ret) {
162 dev_err(lp->dev, "led register err: %d\n", ret);
163 return ret;
164 }
165
166 return 0;
167}
168
169static int __devexit lp8788_led_remove(struct platform_device *pdev)
170{
171 struct lp8788_led *led = platform_get_drvdata(pdev);
172
173 led_classdev_unregister(&led->led_dev);
174 flush_work_sync(&led->work);
175
176 return 0;
177}
178
179static struct platform_driver lp8788_led_driver = {
180 .probe = lp8788_led_probe,
181 .remove = __devexit_p(lp8788_led_remove),
182 .driver = {
183 .name = LP8788_DEV_KEYLED,
184 .owner = THIS_MODULE,
185 },
186};
187module_platform_driver(lp8788_led_driver);
188
189MODULE_DESCRIPTION("Texas Instruments LP8788 Keyboard LED Driver");
190MODULE_AUTHOR("Milo Kim");
191MODULE_LICENSE("GPL");
192MODULE_ALIAS("platform:lp8788-keyled");