1ff95ce9487a9c5ab4a61d78f027789ed684d9cc
[deliverable/linux.git] / drivers / leds / leds-gpio.c
1 /*
2 * LEDs driver for GPIOs
3 *
4 * Copyright (C) 2007 8D Technologies inc.
5 * Raphael Assenat <raph@8d.com>
6 * Copyright (C) 2008 Freescale Semiconductor, Inc.
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 #include <linux/err.h>
14 #include <linux/gpio.h>
15 #include <linux/gpio/consumer.h>
16 #include <linux/kernel.h>
17 #include <linux/leds.h>
18 #include <linux/module.h>
19 #include <linux/of.h>
20 #include <linux/of_gpio.h>
21 #include <linux/of_platform.h>
22 #include <linux/platform_device.h>
23 #include <linux/slab.h>
24 #include <linux/workqueue.h>
25
26 struct gpio_led_data {
27 struct led_classdev cdev;
28 struct gpio_desc *gpiod;
29 struct work_struct work;
30 u8 new_level;
31 u8 can_sleep;
32 u8 blinking;
33 int (*platform_gpio_blink_set)(unsigned gpio, int state,
34 unsigned long *delay_on, unsigned long *delay_off);
35 };
36
37 static void gpio_led_work(struct work_struct *work)
38 {
39 struct gpio_led_data *led_dat =
40 container_of(work, struct gpio_led_data, work);
41
42 if (led_dat->blinking) {
43 int gpio = desc_to_gpio(led_dat->gpiod);
44 int level = led_dat->new_level;
45
46 if (gpiod_is_active_low(led_dat->gpiod))
47 level = !level;
48
49 led_dat->platform_gpio_blink_set(gpio, level, NULL, NULL);
50 led_dat->blinking = 0;
51 } else
52 gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
53 }
54
55 static void gpio_led_set(struct led_classdev *led_cdev,
56 enum led_brightness value)
57 {
58 struct gpio_led_data *led_dat =
59 container_of(led_cdev, struct gpio_led_data, cdev);
60 int level;
61
62 if (value == LED_OFF)
63 level = 0;
64 else
65 level = 1;
66
67 /* Setting GPIOs with I2C/etc requires a task context, and we don't
68 * seem to have a reliable way to know if we're already in one; so
69 * let's just assume the worst.
70 */
71 if (led_dat->can_sleep) {
72 led_dat->new_level = level;
73 schedule_work(&led_dat->work);
74 } else {
75 if (led_dat->blinking) {
76 int gpio = desc_to_gpio(led_dat->gpiod);
77
78 if (gpiod_is_active_low(led_dat->gpiod))
79 level = !level;
80
81 led_dat->platform_gpio_blink_set(gpio, level, NULL,
82 NULL);
83 led_dat->blinking = 0;
84 } else
85 gpiod_set_value(led_dat->gpiod, level);
86 }
87 }
88
89 static int gpio_blink_set(struct led_classdev *led_cdev,
90 unsigned long *delay_on, unsigned long *delay_off)
91 {
92 struct gpio_led_data *led_dat =
93 container_of(led_cdev, struct gpio_led_data, cdev);
94 int gpio = desc_to_gpio(led_dat->gpiod);
95
96 led_dat->blinking = 1;
97 return led_dat->platform_gpio_blink_set(gpio, GPIO_LED_BLINK,
98 delay_on, delay_off);
99 }
100
101 static int create_gpio_led(const struct gpio_led *template,
102 struct gpio_led_data *led_dat, struct device *parent,
103 int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
104 {
105 int ret, state;
106
107 if (!template->gpiod) {
108 unsigned long flags = 0;
109
110 /* skip leds that aren't available */
111 if (!gpio_is_valid(template->gpio)) {
112 dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
113 template->gpio, template->name);
114 return 0;
115 }
116
117 if (template->active_low)
118 flags |= GPIOF_ACTIVE_LOW;
119
120 ret = devm_gpio_request_one(parent, template->gpio, flags,
121 template->name);
122 if (ret < 0)
123 return ret;
124
125 led_dat->gpiod = gpio_to_desc(template->gpio);
126 if (IS_ERR(led_dat->gpiod))
127 return PTR_ERR(led_dat->gpiod);
128 }
129
130 led_dat->cdev.name = template->name;
131 led_dat->cdev.default_trigger = template->default_trigger;
132 led_dat->gpiod = template->gpiod;
133 led_dat->can_sleep = gpiod_cansleep(template->gpiod);
134 led_dat->blinking = 0;
135 if (blink_set) {
136 led_dat->platform_gpio_blink_set = blink_set;
137 led_dat->cdev.blink_set = gpio_blink_set;
138 }
139 led_dat->cdev.brightness_set = gpio_led_set;
140 if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
141 state = !!gpiod_get_value_cansleep(led_dat->gpiod);
142 else
143 state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
144 led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
145 if (!template->retain_state_suspended)
146 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
147
148 ret = gpiod_direction_output(led_dat->gpiod, state);
149 if (ret < 0)
150 return ret;
151
152 INIT_WORK(&led_dat->work, gpio_led_work);
153
154 return led_classdev_register(parent, &led_dat->cdev);
155 }
156
157 static void delete_gpio_led(struct gpio_led_data *led)
158 {
159 led_classdev_unregister(&led->cdev);
160 cancel_work_sync(&led->work);
161 }
162
163 struct gpio_leds_priv {
164 int num_leds;
165 struct gpio_led_data leds[];
166 };
167
168 static inline int sizeof_gpio_leds_priv(int num_leds)
169 {
170 return sizeof(struct gpio_leds_priv) +
171 (sizeof(struct gpio_led_data) * num_leds);
172 }
173
174 /* Code to create from OpenFirmware platform devices */
175 #ifdef CONFIG_OF_GPIO
176 static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
177 {
178 struct device_node *np = pdev->dev.of_node, *child;
179 struct gpio_leds_priv *priv;
180 int count, ret;
181
182 /* count LEDs in this device, so we know how much to allocate */
183 count = of_get_available_child_count(np);
184 if (!count)
185 return ERR_PTR(-ENODEV);
186
187 for_each_available_child_of_node(np, child)
188 if (of_get_gpio(child, 0) == -EPROBE_DEFER)
189 return ERR_PTR(-EPROBE_DEFER);
190
191 priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
192 GFP_KERNEL);
193 if (!priv)
194 return ERR_PTR(-ENOMEM);
195
196 for_each_available_child_of_node(np, child) {
197 struct gpio_led led = {};
198 enum of_gpio_flags flags;
199 const char *state;
200
201 led.gpio = of_get_gpio_flags(child, 0, &flags);
202 led.active_low = flags & OF_GPIO_ACTIVE_LOW;
203 led.name = of_get_property(child, "label", NULL) ? : child->name;
204 led.default_trigger =
205 of_get_property(child, "linux,default-trigger", NULL);
206 state = of_get_property(child, "default-state", NULL);
207 if (state) {
208 if (!strcmp(state, "keep"))
209 led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
210 else if (!strcmp(state, "on"))
211 led.default_state = LEDS_GPIO_DEFSTATE_ON;
212 else
213 led.default_state = LEDS_GPIO_DEFSTATE_OFF;
214 }
215
216 if (of_get_property(child, "retain-state-suspended", NULL))
217 led.retain_state_suspended = 1;
218
219 ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
220 &pdev->dev, NULL);
221 if (ret < 0) {
222 of_node_put(child);
223 goto err;
224 }
225 }
226
227 return priv;
228
229 err:
230 for (count = priv->num_leds - 2; count >= 0; count--)
231 delete_gpio_led(&priv->leds[count]);
232 return ERR_PTR(-ENODEV);
233 }
234
235 static const struct of_device_id of_gpio_leds_match[] = {
236 { .compatible = "gpio-leds", },
237 {},
238 };
239
240 MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
241 #else /* CONFIG_OF_GPIO */
242 static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
243 {
244 return ERR_PTR(-ENODEV);
245 }
246 #endif /* CONFIG_OF_GPIO */
247
248 static int gpio_led_probe(struct platform_device *pdev)
249 {
250 struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
251 struct gpio_leds_priv *priv;
252 int i, ret = 0;
253
254 if (pdata && pdata->num_leds) {
255 priv = devm_kzalloc(&pdev->dev,
256 sizeof_gpio_leds_priv(pdata->num_leds),
257 GFP_KERNEL);
258 if (!priv)
259 return -ENOMEM;
260
261 priv->num_leds = pdata->num_leds;
262 for (i = 0; i < priv->num_leds; i++) {
263 ret = create_gpio_led(&pdata->leds[i],
264 &priv->leds[i],
265 &pdev->dev, pdata->gpio_blink_set);
266 if (ret < 0) {
267 /* On failure: unwind the led creations */
268 for (i = i - 1; i >= 0; i--)
269 delete_gpio_led(&priv->leds[i]);
270 return ret;
271 }
272 }
273 } else {
274 priv = gpio_leds_create_of(pdev);
275 if (IS_ERR(priv))
276 return PTR_ERR(priv);
277 }
278
279 platform_set_drvdata(pdev, priv);
280
281 return 0;
282 }
283
284 static int gpio_led_remove(struct platform_device *pdev)
285 {
286 struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
287 int i;
288
289 for (i = 0; i < priv->num_leds; i++)
290 delete_gpio_led(&priv->leds[i]);
291
292 return 0;
293 }
294
295 static struct platform_driver gpio_led_driver = {
296 .probe = gpio_led_probe,
297 .remove = gpio_led_remove,
298 .driver = {
299 .name = "leds-gpio",
300 .owner = THIS_MODULE,
301 .of_match_table = of_match_ptr(of_gpio_leds_match),
302 },
303 };
304
305 module_platform_driver(gpio_led_driver);
306
307 MODULE_AUTHOR("Raphael Assenat <raph@8d.com>, Trent Piepho <tpiepho@freescale.com>");
308 MODULE_DESCRIPTION("GPIO LED driver");
309 MODULE_LICENSE("GPL");
310 MODULE_ALIAS("platform:leds-gpio");
This page took 0.089756 seconds and 4 git commands to generate.