linux/drivers/leds/leds-gpio.c
<<
>>
Prefs
   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/kernel.h>
  14#include <linux/init.h>
  15#include <linux/platform_device.h>
  16#include <linux/leds.h>
  17#include <linux/slab.h>
  18#include <linux/workqueue.h>
  19
  20#include <asm/gpio.h>
  21
  22struct gpio_led_data {
  23        struct led_classdev cdev;
  24        unsigned gpio;
  25        struct work_struct work;
  26        u8 new_level;
  27        u8 can_sleep;
  28        u8 active_low;
  29        u8 blinking;
  30        int (*platform_gpio_blink_set)(unsigned gpio, int state,
  31                        unsigned long *delay_on, unsigned long *delay_off);
  32};
  33
  34static void gpio_led_work(struct work_struct *work)
  35{
  36        struct gpio_led_data    *led_dat =
  37                container_of(work, struct gpio_led_data, work);
  38
  39        if (led_dat->blinking) {
  40                led_dat->platform_gpio_blink_set(led_dat->gpio,
  41                                                 led_dat->new_level,
  42                                                 NULL, NULL);
  43                led_dat->blinking = 0;
  44        } else
  45                gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
  46}
  47
  48static void gpio_led_set(struct led_classdev *led_cdev,
  49        enum led_brightness value)
  50{
  51        struct gpio_led_data *led_dat =
  52                container_of(led_cdev, struct gpio_led_data, cdev);
  53        int level;
  54
  55        if (value == LED_OFF)
  56                level = 0;
  57        else
  58                level = 1;
  59
  60        if (led_dat->active_low)
  61                level = !level;
  62
  63        /* Setting GPIOs with I2C/etc requires a task context, and we don't
  64         * seem to have a reliable way to know if we're already in one; so
  65         * let's just assume the worst.
  66         */
  67        if (led_dat->can_sleep) {
  68                led_dat->new_level = level;
  69                schedule_work(&led_dat->work);
  70        } else {
  71                if (led_dat->blinking) {
  72                        led_dat->platform_gpio_blink_set(led_dat->gpio, level,
  73                                                         NULL, NULL);
  74                        led_dat->blinking = 0;
  75                } else
  76                        gpio_set_value(led_dat->gpio, level);
  77        }
  78}
  79
  80static int gpio_blink_set(struct led_classdev *led_cdev,
  81        unsigned long *delay_on, unsigned long *delay_off)
  82{
  83        struct gpio_led_data *led_dat =
  84                container_of(led_cdev, struct gpio_led_data, cdev);
  85
  86        led_dat->blinking = 1;
  87        return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
  88                                                delay_on, delay_off);
  89}
  90
  91static int __devinit create_gpio_led(const struct gpio_led *template,
  92        struct gpio_led_data *led_dat, struct device *parent,
  93        int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
  94{
  95        int ret, state;
  96
  97        led_dat->gpio = -1;
  98
  99        /* skip leds that aren't available */
 100        if (!gpio_is_valid(template->gpio)) {
 101                printk(KERN_INFO "Skipping unavailable LED gpio %d (%s)\n",
 102                                template->gpio, template->name);
 103                return 0;
 104        }
 105
 106        ret = gpio_request(template->gpio, template->name);
 107        if (ret < 0)
 108                return ret;
 109
 110        led_dat->cdev.name = template->name;
 111        led_dat->cdev.default_trigger = template->default_trigger;
 112        led_dat->gpio = template->gpio;
 113        led_dat->can_sleep = gpio_cansleep(template->gpio);
 114        led_dat->active_low = template->active_low;
 115        led_dat->blinking = 0;
 116        if (blink_set) {
 117                led_dat->platform_gpio_blink_set = blink_set;
 118                led_dat->cdev.blink_set = gpio_blink_set;
 119        }
 120        led_dat->cdev.brightness_set = gpio_led_set;
 121        if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
 122                state = !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low;
 123        else
 124                state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
 125        led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
 126        if (!template->retain_state_suspended)
 127                led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
 128
 129        ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
 130        if (ret < 0)
 131                goto err;
 132                
 133        INIT_WORK(&led_dat->work, gpio_led_work);
 134
 135        ret = led_classdev_register(parent, &led_dat->cdev);
 136        if (ret < 0)
 137                goto err;
 138
 139        return 0;
 140err:
 141        gpio_free(led_dat->gpio);
 142        return ret;
 143}
 144
 145static void delete_gpio_led(struct gpio_led_data *led)
 146{
 147        if (!gpio_is_valid(led->gpio))
 148                return;
 149        led_classdev_unregister(&led->cdev);
 150        cancel_work_sync(&led->work);
 151        gpio_free(led->gpio);
 152}
 153
 154#ifdef CONFIG_LEDS_GPIO_PLATFORM
 155static int __devinit gpio_led_probe(struct platform_device *pdev)
 156{
 157        struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
 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
 180err:
 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
 189static int __devexit gpio_led_remove(struct platform_device *pdev)
 190{
 191        int i;
 192        struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
 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}
 204
 205static 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
 214MODULE_ALIAS("platform:leds-gpio");
 215#endif /* CONFIG_LEDS_GPIO_PLATFORM */
 216
 217/* Code to create from OpenFirmware platform devices */
 218#ifdef CONFIG_LEDS_GPIO_OF
 219#include <linux/of_platform.h>
 220#include <linux/of_gpio.h>
 221
 222struct gpio_led_of_platform_data {
 223        int num_leds;
 224        struct gpio_led_data led_data[];
 225};
 226
 227static int __devinit of_gpio_leds_probe(struct platform_device *ofdev,
 228                                        const struct of_device_id *match)
 229{
 230        struct device_node *np = ofdev->dev.of_node, *child;
 231        struct gpio_led_of_platform_data *pdata;
 232        int count = 0, ret;
 233
 234        /* count LEDs defined by this device, so we know how much to allocate */
 235        for_each_child_of_node(np, child)
 236                count++;
 237        if (!count)
 238                return 0; /* or ENODEV? */
 239
 240        pdata = kzalloc(sizeof(*pdata) + sizeof(struct gpio_led_data) * count,
 241                        GFP_KERNEL);
 242        if (!pdata)
 243                return -ENOMEM;
 244
 245        for_each_child_of_node(np, child) {
 246                struct gpio_led led = {};
 247                enum of_gpio_flags flags;
 248                const char *state;
 249
 250                led.gpio = of_get_gpio_flags(child, 0, &flags);
 251                led.active_low = flags & OF_GPIO_ACTIVE_LOW;
 252                led.name = of_get_property(child, "label", NULL) ? : child->name;
 253                led.default_trigger =
 254                        of_get_property(child, "linux,default-trigger", NULL);
 255                state = of_get_property(child, "default-state", NULL);
 256                if (state) {
 257                        if (!strcmp(state, "keep"))
 258                                led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
 259                        else if(!strcmp(state, "on"))
 260                                led.default_state = LEDS_GPIO_DEFSTATE_ON;
 261                        else
 262                                led.default_state = LEDS_GPIO_DEFSTATE_OFF;
 263                }
 264
 265                ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++],
 266                                      &ofdev->dev, NULL);
 267                if (ret < 0) {
 268                        of_node_put(child);
 269                        goto err;
 270                }
 271        }
 272
 273        dev_set_drvdata(&ofdev->dev, pdata);
 274
 275        return 0;
 276
 277err:
 278        for (count = pdata->num_leds - 2; count >= 0; count--)
 279                delete_gpio_led(&pdata->led_data[count]);
 280
 281        kfree(pdata);
 282
 283        return ret;
 284}
 285
 286static int __devexit of_gpio_leds_remove(struct platform_device *ofdev)
 287{
 288        struct gpio_led_of_platform_data *pdata = dev_get_drvdata(&ofdev->dev);
 289        int i;
 290
 291        for (i = 0; i < pdata->num_leds; i++)
 292                delete_gpio_led(&pdata->led_data[i]);
 293
 294        kfree(pdata);
 295
 296        dev_set_drvdata(&ofdev->dev, NULL);
 297
 298        return 0;
 299}
 300
 301static const struct of_device_id of_gpio_leds_match[] = {
 302        { .compatible = "gpio-leds", },
 303        {},
 304};
 305
 306static struct of_platform_driver of_gpio_leds_driver = {
 307        .driver = {
 308                .name = "of_gpio_leds",
 309                .owner = THIS_MODULE,
 310                .of_match_table = of_gpio_leds_match,
 311        },
 312        .probe = of_gpio_leds_probe,
 313        .remove = __devexit_p(of_gpio_leds_remove),
 314};
 315#endif
 316
 317static int __init gpio_led_init(void)
 318{
 319        int ret = 0;
 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}
 336
 337static void __exit gpio_led_exit(void)
 338{
 339#ifdef CONFIG_LEDS_GPIO_PLATFORM
 340        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}
 346
 347module_init(gpio_led_init);
 348module_exit(gpio_led_exit);
 349
 350MODULE_AUTHOR("Raphael Assenat <raph@8d.com>, Trent Piepho <tpiepho@freescale.com>");
 351MODULE_DESCRIPTION("GPIO LED driver");
 352MODULE_LICENSE("GPL");
 353