aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-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");