diff options
Diffstat (limited to 'drivers/leds/leds-gpio.c')
-rw-r--r-- | drivers/leds/leds-gpio.c | 214 |
1 files changed, 87 insertions, 127 deletions
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 4d9fa38d9ff6..b0480c8fbcbf 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/leds.h> | 16 | #include <linux/leds.h> |
17 | #include <linux/of_platform.h> | ||
18 | #include <linux/of_gpio.h> | ||
17 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
18 | #include <linux/workqueue.h> | 20 | #include <linux/workqueue.h> |
19 | 21 | ||
@@ -151,96 +153,34 @@ static void delete_gpio_led(struct gpio_led_data *led) | |||
151 | gpio_free(led->gpio); | 153 | gpio_free(led->gpio); |
152 | } | 154 | } |
153 | 155 | ||
154 | #ifdef CONFIG_LEDS_GPIO_PLATFORM | 156 | struct gpio_leds_priv { |
155 | static int __devinit gpio_led_probe(struct platform_device *pdev) | 157 | int num_leds; |
156 | { | 158 | struct gpio_led_data leds[]; |
157 | struct gpio_led_platform_data *pdata = pdev->dev.platform_data; | 159 | }; |
158 | struct gpio_led_data *leds_data; | ||
159 | int i, ret = 0; | ||
160 | |||
161 | if (!pdata) | ||
162 | return -EBUSY; | ||
163 | |||
164 | leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds, | ||
165 | GFP_KERNEL); | ||
166 | if (!leds_data) | ||
167 | return -ENOMEM; | ||
168 | |||
169 | for (i = 0; i < pdata->num_leds; i++) { | ||
170 | ret = create_gpio_led(&pdata->leds[i], &leds_data[i], | ||
171 | &pdev->dev, pdata->gpio_blink_set); | ||
172 | if (ret < 0) | ||
173 | goto err; | ||
174 | } | ||
175 | |||
176 | platform_set_drvdata(pdev, leds_data); | ||
177 | |||
178 | return 0; | ||
179 | |||
180 | err: | ||
181 | for (i = i - 1; i >= 0; i--) | ||
182 | delete_gpio_led(&leds_data[i]); | ||
183 | |||
184 | kfree(leds_data); | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | 160 | ||
189 | static int __devexit gpio_led_remove(struct platform_device *pdev) | 161 | static inline int sizeof_gpio_leds_priv(int num_leds) |
190 | { | 162 | { |
191 | int i; | 163 | return sizeof(struct gpio_leds_priv) + |
192 | struct gpio_led_platform_data *pdata = pdev->dev.platform_data; | 164 | (sizeof(struct gpio_led_data) * num_leds); |
193 | struct gpio_led_data *leds_data; | ||
194 | |||
195 | leds_data = platform_get_drvdata(pdev); | ||
196 | |||
197 | for (i = 0; i < pdata->num_leds; i++) | ||
198 | delete_gpio_led(&leds_data[i]); | ||
199 | |||
200 | kfree(leds_data); | ||
201 | |||
202 | return 0; | ||
203 | } | 165 | } |
204 | 166 | ||
205 | static struct platform_driver gpio_led_driver = { | ||
206 | .probe = gpio_led_probe, | ||
207 | .remove = __devexit_p(gpio_led_remove), | ||
208 | .driver = { | ||
209 | .name = "leds-gpio", | ||
210 | .owner = THIS_MODULE, | ||
211 | }, | ||
212 | }; | ||
213 | |||
214 | MODULE_ALIAS("platform:leds-gpio"); | ||
215 | #endif /* CONFIG_LEDS_GPIO_PLATFORM */ | ||
216 | |||
217 | /* Code to create from OpenFirmware platform devices */ | 167 | /* Code to create from OpenFirmware platform devices */ |
218 | #ifdef CONFIG_LEDS_GPIO_OF | 168 | #ifdef CONFIG_LEDS_GPIO_OF |
219 | #include <linux/of_platform.h> | 169 | static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev) |
220 | #include <linux/of_gpio.h> | ||
221 | |||
222 | struct gpio_led_of_platform_data { | ||
223 | int num_leds; | ||
224 | struct gpio_led_data led_data[]; | ||
225 | }; | ||
226 | |||
227 | static int __devinit of_gpio_leds_probe(struct platform_device *ofdev, | ||
228 | const struct of_device_id *match) | ||
229 | { | 170 | { |
230 | struct device_node *np = ofdev->dev.of_node, *child; | 171 | struct device_node *np = pdev->dev.of_node, *child; |
231 | struct gpio_led_of_platform_data *pdata; | 172 | struct gpio_leds_priv *priv; |
232 | int count = 0, ret; | 173 | int count = 0, ret; |
233 | 174 | ||
234 | /* count LEDs defined by this device, so we know how much to allocate */ | 175 | /* count LEDs in this device, so we know how much to allocate */ |
235 | for_each_child_of_node(np, child) | 176 | for_each_child_of_node(np, child) |
236 | count++; | 177 | count++; |
237 | if (!count) | 178 | if (!count) |
238 | return 0; /* or ENODEV? */ | 179 | return NULL; |
239 | 180 | ||
240 | pdata = kzalloc(sizeof(*pdata) + sizeof(struct gpio_led_data) * count, | 181 | priv = kzalloc(sizeof_gpio_leds_priv(count), GFP_KERNEL); |
241 | GFP_KERNEL); | 182 | if (!priv) |
242 | if (!pdata) | 183 | return NULL; |
243 | return -ENOMEM; | ||
244 | 184 | ||
245 | for_each_child_of_node(np, child) { | 185 | for_each_child_of_node(np, child) { |
246 | struct gpio_led led = {}; | 186 | struct gpio_led led = {}; |
@@ -256,92 +196,112 @@ static int __devinit of_gpio_leds_probe(struct platform_device *ofdev, | |||
256 | if (state) { | 196 | if (state) { |
257 | if (!strcmp(state, "keep")) | 197 | if (!strcmp(state, "keep")) |
258 | led.default_state = LEDS_GPIO_DEFSTATE_KEEP; | 198 | led.default_state = LEDS_GPIO_DEFSTATE_KEEP; |
259 | else if(!strcmp(state, "on")) | 199 | else if (!strcmp(state, "on")) |
260 | led.default_state = LEDS_GPIO_DEFSTATE_ON; | 200 | led.default_state = LEDS_GPIO_DEFSTATE_ON; |
261 | else | 201 | else |
262 | led.default_state = LEDS_GPIO_DEFSTATE_OFF; | 202 | led.default_state = LEDS_GPIO_DEFSTATE_OFF; |
263 | } | 203 | } |
264 | 204 | ||
265 | ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++], | 205 | ret = create_gpio_led(&led, &priv->leds[priv->num_leds++], |
266 | &ofdev->dev, NULL); | 206 | &pdev->dev, NULL); |
267 | if (ret < 0) { | 207 | if (ret < 0) { |
268 | of_node_put(child); | 208 | of_node_put(child); |
269 | goto err; | 209 | goto err; |
270 | } | 210 | } |
271 | } | 211 | } |
272 | 212 | ||
273 | dev_set_drvdata(&ofdev->dev, pdata); | 213 | return priv; |
274 | |||
275 | return 0; | ||
276 | 214 | ||
277 | err: | 215 | err: |
278 | for (count = pdata->num_leds - 2; count >= 0; count--) | 216 | for (count = priv->num_leds - 2; count >= 0; count--) |
279 | delete_gpio_led(&pdata->led_data[count]); | 217 | delete_gpio_led(&priv->leds[count]); |
218 | kfree(priv); | ||
219 | return NULL; | ||
220 | } | ||
280 | 221 | ||
281 | kfree(pdata); | 222 | static const struct of_device_id of_gpio_leds_match[] = { |
223 | { .compatible = "gpio-leds", }, | ||
224 | {}, | ||
225 | }; | ||
226 | #else | ||
227 | static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev) | ||
228 | { | ||
229 | return NULL; | ||
230 | } | ||
231 | #define of_gpio_leds_match NULL | ||
232 | #endif | ||
282 | 233 | ||
283 | return ret; | 234 | |
235 | static int __devinit gpio_led_probe(struct platform_device *pdev) | ||
236 | { | ||
237 | struct gpio_led_platform_data *pdata = pdev->dev.platform_data; | ||
238 | struct gpio_leds_priv *priv; | ||
239 | int i, ret = 0; | ||
240 | |||
241 | if (pdata && pdata->num_leds) { | ||
242 | priv = kzalloc(sizeof_gpio_leds_priv(pdata->num_leds), | ||
243 | GFP_KERNEL); | ||
244 | if (!priv) | ||
245 | return -ENOMEM; | ||
246 | |||
247 | priv->num_leds = pdata->num_leds; | ||
248 | for (i = 0; i < priv->num_leds; i++) { | ||
249 | ret = create_gpio_led(&pdata->leds[i], | ||
250 | &priv->leds[i], | ||
251 | &pdev->dev, pdata->gpio_blink_set); | ||
252 | if (ret < 0) { | ||
253 | /* On failure: unwind the led creations */ | ||
254 | for (i = i - 1; i >= 0; i--) | ||
255 | delete_gpio_led(&priv->leds[i]); | ||
256 | kfree(priv); | ||
257 | return ret; | ||
258 | } | ||
259 | } | ||
260 | } else { | ||
261 | priv = gpio_leds_create_of(pdev); | ||
262 | if (!priv) | ||
263 | return -ENODEV; | ||
264 | } | ||
265 | |||
266 | platform_set_drvdata(pdev, priv); | ||
267 | |||
268 | return 0; | ||
284 | } | 269 | } |
285 | 270 | ||
286 | static int __devexit of_gpio_leds_remove(struct platform_device *ofdev) | 271 | static int __devexit gpio_led_remove(struct platform_device *pdev) |
287 | { | 272 | { |
288 | struct gpio_led_of_platform_data *pdata = dev_get_drvdata(&ofdev->dev); | 273 | struct gpio_leds_priv *priv = dev_get_drvdata(&pdev->dev); |
289 | int i; | 274 | int i; |
290 | 275 | ||
291 | for (i = 0; i < pdata->num_leds; i++) | 276 | for (i = 0; i < priv->num_leds; i++) |
292 | delete_gpio_led(&pdata->led_data[i]); | 277 | delete_gpio_led(&priv->leds[i]); |
293 | |||
294 | kfree(pdata); | ||
295 | 278 | ||
296 | dev_set_drvdata(&ofdev->dev, NULL); | 279 | dev_set_drvdata(&pdev->dev, NULL); |
280 | kfree(priv); | ||
297 | 281 | ||
298 | return 0; | 282 | return 0; |
299 | } | 283 | } |
300 | 284 | ||
301 | static const struct of_device_id of_gpio_leds_match[] = { | 285 | static struct platform_driver gpio_led_driver = { |
302 | { .compatible = "gpio-leds", }, | 286 | .probe = gpio_led_probe, |
303 | {}, | 287 | .remove = __devexit_p(gpio_led_remove), |
304 | }; | 288 | .driver = { |
305 | 289 | .name = "leds-gpio", | |
306 | static struct of_platform_driver of_gpio_leds_driver = { | 290 | .owner = THIS_MODULE, |
307 | .driver = { | ||
308 | .name = "of_gpio_leds", | ||
309 | .owner = THIS_MODULE, | ||
310 | .of_match_table = of_gpio_leds_match, | 291 | .of_match_table = of_gpio_leds_match, |
311 | }, | 292 | }, |
312 | .probe = of_gpio_leds_probe, | ||
313 | .remove = __devexit_p(of_gpio_leds_remove), | ||
314 | }; | 293 | }; |
315 | #endif | 294 | |
295 | MODULE_ALIAS("platform:leds-gpio"); | ||
316 | 296 | ||
317 | static int __init gpio_led_init(void) | 297 | static int __init gpio_led_init(void) |
318 | { | 298 | { |
319 | int ret = 0; | 299 | return platform_driver_register(&gpio_led_driver); |
320 | |||
321 | #ifdef CONFIG_LEDS_GPIO_PLATFORM | ||
322 | ret = platform_driver_register(&gpio_led_driver); | ||
323 | if (ret) | ||
324 | return ret; | ||
325 | #endif | ||
326 | #ifdef CONFIG_LEDS_GPIO_OF | ||
327 | ret = of_register_platform_driver(&of_gpio_leds_driver); | ||
328 | #endif | ||
329 | #ifdef CONFIG_LEDS_GPIO_PLATFORM | ||
330 | if (ret) | ||
331 | platform_driver_unregister(&gpio_led_driver); | ||
332 | #endif | ||
333 | |||
334 | return ret; | ||
335 | } | 300 | } |
336 | 301 | ||
337 | static void __exit gpio_led_exit(void) | 302 | static void __exit gpio_led_exit(void) |
338 | { | 303 | { |
339 | #ifdef CONFIG_LEDS_GPIO_PLATFORM | ||
340 | platform_driver_unregister(&gpio_led_driver); | 304 | platform_driver_unregister(&gpio_led_driver); |
341 | #endif | ||
342 | #ifdef CONFIG_LEDS_GPIO_OF | ||
343 | of_unregister_platform_driver(&of_gpio_leds_driver); | ||
344 | #endif | ||
345 | } | 305 | } |
346 | 306 | ||
347 | module_init(gpio_led_init); | 307 | module_init(gpio_led_init); |