aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/powerpc/dts-bindings/gpio/led.txt46
-rw-r--r--drivers/leds/Kconfig21
-rw-r--r--drivers/leds/leds-gpio.c205
3 files changed, 219 insertions, 53 deletions
diff --git a/Documentation/powerpc/dts-bindings/gpio/led.txt b/Documentation/powerpc/dts-bindings/gpio/led.txt
index ff51f4c0fa9d..4fe14deedc0a 100644
--- a/Documentation/powerpc/dts-bindings/gpio/led.txt
+++ b/Documentation/powerpc/dts-bindings/gpio/led.txt
@@ -1,15 +1,43 @@
1LED connected to GPIO 1LEDs connected to GPIO lines
2 2
3Required properties: 3Required properties:
4- compatible : should be "gpio-led". 4- compatible : should be "gpio-leds".
5- label : (optional) the label for this LED. If omitted, the label is 5
6Each LED is represented as a sub-node of the gpio-leds device. Each
7node's name represents the name of the corresponding LED.
8
9LED sub-node properties:
10- gpios : Should specify the LED's GPIO, see "Specifying GPIO information
11 for devices" in Documentation/powerpc/booting-without-of.txt. Active
12 low LEDs should be indicated using flags in the GPIO specifier.
13- label : (optional) The label for this LED. If omitted, the label is
6 taken from the node name (excluding the unit address). 14 taken from the node name (excluding the unit address).
7- gpios : should specify LED GPIO. 15- linux,default-trigger : (optional) This parameter, if present, is a
16 string defining the trigger assigned to the LED. Current triggers are:
17 "backlight" - LED will act as a back-light, controlled by the framebuffer
18 system
19 "default-on" - LED will turn on
20 "heartbeat" - LED "double" flashes at a load average based rate
21 "ide-disk" - LED indicates disk activity
22 "timer" - LED flashes at a fixed, configurable rate
8 23
9Example: 24Examples:
10 25
11led@0 { 26leds {
12 compatible = "gpio-led"; 27 compatible = "gpio-leds";
13 label = "hdd"; 28 hdd {
14 gpios = <&mcu_pio 0 1>; 29 label = "IDE Activity";
30 gpios = <&mcu_pio 0 1>; /* Active low */
31 linux,default-trigger = "ide-disk";
32 };
15}; 33};
34
35run-control {
36 compatible = "gpio-leds";
37 red {
38 gpios = <&mpc8572 6 0>;
39 };
40 green {
41 gpios = <&mpc8572 7 0>;
42 };
43}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index d9db17624f12..90d39e5803cd 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -117,7 +117,26 @@ config LEDS_GPIO
117 help 117 help
118 This option enables support for the LEDs connected to GPIO 118 This option enables support for the LEDs connected to GPIO
119 outputs. To be useful the particular board must have LEDs 119 outputs. To be useful the particular board must have LEDs
120 and they must be connected to the GPIO lines. 120 and they must be connected to the GPIO lines. The LEDs must be
121 defined as platform devices and/or OpenFirmware platform devices.
122 The code to use these bindings can be selected below.
123
124config LEDS_GPIO_PLATFORM
125 bool "Platform device bindings for GPIO LEDs"
126 depends on LEDS_GPIO
127 default y
128 help
129 Let the leds-gpio driver drive LEDs which have been defined as
130 platform devices. If you don't know what this means, say yes.
131
132config LEDS_GPIO_OF
133 bool "OpenFirmware platform device bindings for GPIO LEDs"
134 depends on LEDS_GPIO && OF_DEVICE
135 default y
136 help
137 Let the leds-gpio driver drive LEDs which have been defined as
138 of_platform devices. For instance, LEDs which are listed in a "dts"
139 file.
121 140
122config LEDS_CLEVO_MAIL 141config LEDS_CLEVO_MAIL
123 tristate "Mail LED on Clevo notebook (EXPERIMENTAL)" 142 tristate "Mail LED on Clevo notebook (EXPERIMENTAL)"
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 2e3df08b649b..f8bcf98fc15c 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (C) 2007 8D Technologies inc. 4 * Copyright (C) 2007 8D Technologies inc.
5 * Raphael Assenat <raph@8d.com> 5 * Raphael Assenat <raph@8d.com>
6 * Copyright (C) 2008 Freescale Semiconductor, Inc.
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -71,11 +72,57 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
71 return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off); 72 return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off);
72} 73}
73 74
75static int __devinit create_gpio_led(const struct gpio_led *template,
76 struct gpio_led_data *led_dat, struct device *parent,
77 int (*blink_set)(unsigned, unsigned long *, unsigned long *))
78{
79 int ret;
80
81 ret = gpio_request(template->gpio, template->name);
82 if (ret < 0)
83 return ret;
84
85 led_dat->cdev.name = template->name;
86 led_dat->cdev.default_trigger = template->default_trigger;
87 led_dat->gpio = template->gpio;
88 led_dat->can_sleep = gpio_cansleep(template->gpio);
89 led_dat->active_low = template->active_low;
90 if (blink_set) {
91 led_dat->platform_gpio_blink_set = blink_set;
92 led_dat->cdev.blink_set = gpio_blink_set;
93 }
94 led_dat->cdev.brightness_set = gpio_led_set;
95 led_dat->cdev.brightness = LED_OFF;
96 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
97
98 ret = gpio_direction_output(led_dat->gpio, led_dat->active_low);
99 if (ret < 0)
100 goto err;
101
102 INIT_WORK(&led_dat->work, gpio_led_work);
103
104 ret = led_classdev_register(parent, &led_dat->cdev);
105 if (ret < 0)
106 goto err;
107
108 return 0;
109err:
110 gpio_free(led_dat->gpio);
111 return ret;
112}
113
114static void delete_gpio_led(struct gpio_led_data *led)
115{
116 led_classdev_unregister(&led->cdev);
117 cancel_work_sync(&led->work);
118 gpio_free(led->gpio);
119}
120
121#ifdef CONFIG_LEDS_GPIO_PLATFORM
74static int gpio_led_probe(struct platform_device *pdev) 122static int gpio_led_probe(struct platform_device *pdev)
75{ 123{
76 struct gpio_led_platform_data *pdata = pdev->dev.platform_data; 124 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
77 struct gpio_led *cur_led; 125 struct gpio_led_data *leds_data;
78 struct gpio_led_data *leds_data, *led_dat;
79 int i, ret = 0; 126 int i, ret = 0;
80 127
81 if (!pdata) 128 if (!pdata)
@@ -87,35 +134,10 @@ static int gpio_led_probe(struct platform_device *pdev)
87 return -ENOMEM; 134 return -ENOMEM;
88 135
89 for (i = 0; i < pdata->num_leds; i++) { 136 for (i = 0; i < pdata->num_leds; i++) {
90 cur_led = &pdata->leds[i]; 137 ret = create_gpio_led(&pdata->leds[i], &leds_data[i],
91 led_dat = &leds_data[i]; 138 &pdev->dev, pdata->gpio_blink_set);
92
93 ret = gpio_request(cur_led->gpio, cur_led->name);
94 if (ret < 0) 139 if (ret < 0)
95 goto err; 140 goto err;
96
97 led_dat->cdev.name = cur_led->name;
98 led_dat->cdev.default_trigger = cur_led->default_trigger;
99 led_dat->gpio = cur_led->gpio;
100 led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
101 led_dat->active_low = cur_led->active_low;
102 if (pdata->gpio_blink_set) {
103 led_dat->platform_gpio_blink_set = pdata->gpio_blink_set;
104 led_dat->cdev.blink_set = gpio_blink_set;
105 }
106 led_dat->cdev.brightness_set = gpio_led_set;
107 led_dat->cdev.brightness = LED_OFF;
108 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
109
110 gpio_direction_output(led_dat->gpio, led_dat->active_low);
111
112 INIT_WORK(&led_dat->work, gpio_led_work);
113
114 ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
115 if (ret < 0) {
116 gpio_free(led_dat->gpio);
117 goto err;
118 }
119 } 141 }
120 142
121 platform_set_drvdata(pdev, leds_data); 143 platform_set_drvdata(pdev, leds_data);
@@ -123,13 +145,8 @@ static int gpio_led_probe(struct platform_device *pdev)
123 return 0; 145 return 0;
124 146
125err: 147err:
126 if (i > 0) { 148 for (i = i - 1; i >= 0; i--)
127 for (i = i - 1; i >= 0; i--) { 149 delete_gpio_led(&leds_data[i]);
128 led_classdev_unregister(&leds_data[i].cdev);
129 cancel_work_sync(&leds_data[i].work);
130 gpio_free(leds_data[i].gpio);
131 }
132 }
133 150
134 kfree(leds_data); 151 kfree(leds_data);
135 152
@@ -144,11 +161,8 @@ static int __devexit gpio_led_remove(struct platform_device *pdev)
144 161
145 leds_data = platform_get_drvdata(pdev); 162 leds_data = platform_get_drvdata(pdev);
146 163
147 for (i = 0; i < pdata->num_leds; i++) { 164 for (i = 0; i < pdata->num_leds; i++)
148 led_classdev_unregister(&leds_data[i].cdev); 165 delete_gpio_led(&leds_data[i]);
149 cancel_work_sync(&leds_data[i].work);
150 gpio_free(leds_data[i].gpio);
151 }
152 166
153 kfree(leds_data); 167 kfree(leds_data);
154 168
@@ -177,7 +191,112 @@ static void __exit gpio_led_exit(void)
177module_init(gpio_led_init); 191module_init(gpio_led_init);
178module_exit(gpio_led_exit); 192module_exit(gpio_led_exit);
179 193
180MODULE_AUTHOR("Raphael Assenat <raph@8d.com>"); 194MODULE_ALIAS("platform:leds-gpio");
195#endif /* CONFIG_LEDS_GPIO_PLATFORM */
196
197/* Code to create from OpenFirmware platform devices */
198#ifdef CONFIG_LEDS_GPIO_OF
199#include <linux/of_platform.h>
200#include <linux/of_gpio.h>
201
202struct gpio_led_of_platform_data {
203 int num_leds;
204 struct gpio_led_data led_data[];
205};
206
207static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
208 const struct of_device_id *match)
209{
210 struct device_node *np = ofdev->node, *child;
211 struct gpio_led led;
212 struct gpio_led_of_platform_data *pdata;
213 int count = 0, ret;
214
215 /* count LEDs defined by this device, so we know how much to allocate */
216 for_each_child_of_node(np, child)
217 count++;
218 if (!count)
219 return 0; /* or ENODEV? */
220
221 pdata = kzalloc(sizeof(*pdata) + sizeof(struct gpio_led_data) * count,
222 GFP_KERNEL);
223 if (!pdata)
224 return -ENOMEM;
225
226 memset(&led, 0, sizeof(led));
227 for_each_child_of_node(np, child) {
228 enum of_gpio_flags flags;
229
230 led.gpio = of_get_gpio_flags(child, 0, &flags);
231 led.active_low = flags & OF_GPIO_ACTIVE_LOW;
232 led.name = of_get_property(child, "label", NULL) ? : child->name;
233 led.default_trigger =
234 of_get_property(child, "linux,default-trigger", NULL);
235
236 ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++],
237 &ofdev->dev, NULL);
238 if (ret < 0) {
239 of_node_put(child);
240 goto err;
241 }
242 }
243
244 dev_set_drvdata(&ofdev->dev, pdata);
245
246 return 0;
247
248err:
249 for (count = pdata->num_leds - 2; count >= 0; count--)
250 delete_gpio_led(&pdata->led_data[count]);
251
252 kfree(pdata);
253
254 return ret;
255}
256
257static int __devexit of_gpio_leds_remove(struct of_device *ofdev)
258{
259 struct gpio_led_of_platform_data *pdata = dev_get_drvdata(&ofdev->dev);
260 int i;
261
262 for (i = 0; i < pdata->num_leds; i++)
263 delete_gpio_led(&pdata->led_data[i]);
264
265 kfree(pdata);
266
267 dev_set_drvdata(&ofdev->dev, NULL);
268
269 return 0;
270}
271
272static const struct of_device_id of_gpio_leds_match[] = {
273 { .compatible = "gpio-leds", },
274 {},
275};
276
277static struct of_platform_driver of_gpio_leds_driver = {
278 .driver = {
279 .name = "of_gpio_leds",
280 .owner = THIS_MODULE,
281 },
282 .match_table = of_gpio_leds_match,
283 .probe = of_gpio_leds_probe,
284 .remove = __devexit_p(of_gpio_leds_remove),
285};
286
287static int __init of_gpio_leds_init(void)
288{
289 return of_register_platform_driver(&of_gpio_leds_driver);
290}
291module_init(of_gpio_leds_init);
292
293static void __exit of_gpio_leds_exit(void)
294{
295 of_unregister_platform_driver(&of_gpio_leds_driver);
296}
297module_exit(of_gpio_leds_exit);
298#endif
299
300MODULE_AUTHOR("Raphael Assenat <raph@8d.com>, Trent Piepho <tpiepho@freescale.com>");
181MODULE_DESCRIPTION("GPIO LED driver"); 301MODULE_DESCRIPTION("GPIO LED driver");
182MODULE_LICENSE("GPL"); 302MODULE_LICENSE("GPL");
183MODULE_ALIAS("platform:leds-gpio");