aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds/leds-gpio.c
diff options
context:
space:
mode:
authorRaphael Assenat <raph@8d.com>2007-02-27 14:49:53 -0500
committerRichard Purdie <rpurdie@rpsys.net>2007-07-15 20:15:50 -0400
commit22e03f3b58dfcca30f0c8de185022132459638d1 (patch)
tree0597fa494d55f44191ec99b4bb34a937efcab0e7 /drivers/leds/leds-gpio.c
parent8f41958bdd577731f7411c9605cfaa9db6766809 (diff)
leds: Add generic GPIO LED driver
This patch adds support for GPIO connected leds via the new GPIO framework. Information about leds (gpio, polarity, name, default trigger) is passed to the driver via platform_data. Signed-off-by: Raphael Assenat <raph@8d.com> Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Diffstat (limited to 'drivers/leds/leds-gpio.c')
-rw-r--r--drivers/leds/leds-gpio.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
new file mode 100644
index 000000000000..431dcb61902c
--- /dev/null
+++ b/drivers/leds/leds-gpio.c
@@ -0,0 +1,174 @@
1/*
2 * LEDs driver for GPIOs
3 *
4 * Copyright (C) 2007 8D Technologies inc.
5 * Raphael Assenat <raph@8d.com>
6 *
7 * 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 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/platform_device.h>
15#include <linux/leds.h>
16#include <asm/gpio.h>
17
18struct gpio_led_data {
19 struct led_classdev cdev;
20 unsigned gpio;
21 u8 active_low;
22};
23
24
25static void gpio_led_set(struct led_classdev *led_cdev,
26 enum led_brightness value)
27{
28 struct gpio_led_data *led_dat =
29 container_of(led_cdev, struct gpio_led_data, cdev);
30 int level;
31
32 if (value == LED_OFF)
33 level = 0;
34 else
35 level = 1;
36
37 if (led_dat->active_low)
38 level = !level;
39
40 gpio_set_value(led_dat->gpio, level);
41}
42
43static int __init gpio_led_probe(struct platform_device *pdev)
44{
45 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
46 struct gpio_led *cur_led;
47 struct gpio_led_data *leds_data, *led_dat;
48 int i, ret = 0;
49
50 if (!pdata)
51 return -EBUSY;
52
53 leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,
54 GFP_KERNEL);
55 if (!leds_data)
56 return -ENOMEM;
57
58 for (i = 0; i < pdata->num_leds; i++) {
59 cur_led = &pdata->leds[i];
60 led_dat = &leds_data[i];
61
62 led_dat->cdev.name = cur_led->name;
63 led_dat->cdev.default_trigger = cur_led->default_trigger;
64 led_dat->gpio = cur_led->gpio;
65 led_dat->active_low = cur_led->active_low;
66 led_dat->cdev.brightness_set = gpio_led_set;
67 led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
68
69 ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
70 if (ret < 0)
71 goto err;
72
73 gpio_direction_output(led_dat->gpio, led_dat->active_low);
74
75 ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
76 if (ret < 0) {
77 gpio_free(led_dat->gpio);
78 goto err;
79 }
80 }
81
82 platform_set_drvdata(pdev, leds_data);
83
84 return 0;
85
86err:
87 if (i > 0) {
88 for (i = i - 1; i >= 0; i--) {
89 led_classdev_unregister(&leds_data[i].cdev);
90 gpio_free(leds_data[i].gpio);
91 }
92 }
93 kfree(leds_data);
94
95 return ret;
96}
97
98static int __exit gpio_led_remove(struct platform_device *pdev)
99{
100 int i;
101 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
102 struct gpio_led_data *leds_data;
103
104 leds_data = platform_get_drvdata(pdev);
105
106 for (i = 0; i < pdata->num_leds; i++) {
107 led_classdev_unregister(&leds_data[i].cdev);
108 gpio_free(leds_data[i].gpio);
109 }
110
111 kfree(leds_data);
112
113 return 0;
114}
115
116#ifdef CONFIG_PM
117static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
118{
119 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
120 struct gpio_led_data *leds_data;
121 int i;
122
123 leds_data = platform_get_drvdata(pdev);
124
125 for (i = 0; i < pdata->num_leds; i++)
126 led_classdev_suspend(&leds_data[i].cdev);
127
128 return 0;
129}
130
131static int gpio_led_resume(struct platform_device *pdev)
132{
133 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
134 struct gpio_led_data *leds_data;
135 int i;
136
137 leds_data = platform_get_drvdata(pdev);
138
139 for (i = 0; i < pdata->num_leds; i++)
140 led_classdev_resume(&leds_data[i].cdev);
141
142 return 0;
143}
144#else
145#define gpio_led_suspend NULL
146#define gpio_led_resume NULL
147#endif
148
149static struct platform_driver gpio_led_driver = {
150 .remove = __exit_p(gpio_led_remove),
151 .suspend = gpio_led_suspend,
152 .resume = gpio_led_resume,
153 .driver = {
154 .name = "leds-gpio",
155 .owner = THIS_MODULE,
156 },
157};
158
159static int __init gpio_led_init(void)
160{
161 return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
162}
163
164static void __exit gpio_led_exit(void)
165{
166 platform_driver_unregister(&gpio_led_driver);
167}
168
169module_init(gpio_led_init);
170module_exit(gpio_led_exit);
171
172MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
173MODULE_DESCRIPTION("GPIO LED driver");
174MODULE_LICENSE("GPL");