LCOV - code coverage report
Current view: top level - drivers/leds - leds-gpio.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 6 104 5.8 %
Date: 2014-02-18 Functions: 1 10 10.0 %
Branches: 5 66 7.6 %

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

Generated by: LCOV version 1.9