LCOV - code coverage report
Current view: top level - drivers/leds/trigger - ledtrig-gpio.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 1 61 1.6 %
Date: 2020-09-30 20:25:01 Functions: 1 11 9.1 %
Branches: 0 32 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * ledtrig-gio.c - LED Trigger Based on GPIO events
       4                 :            :  *
       5                 :            :  * Copyright 2009 Felipe Balbi <me@felipebalbi.com>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/module.h>
       9                 :            : #include <linux/kernel.h>
      10                 :            : #include <linux/init.h>
      11                 :            : #include <linux/gpio.h>
      12                 :            : #include <linux/interrupt.h>
      13                 :            : #include <linux/leds.h>
      14                 :            : #include <linux/slab.h>
      15                 :            : #include "../leds.h"
      16                 :            : 
      17                 :            : struct gpio_trig_data {
      18                 :            :         struct led_classdev *led;
      19                 :            : 
      20                 :            :         unsigned desired_brightness;    /* desired brightness when led is on */
      21                 :            :         unsigned inverted;              /* true when gpio is inverted */
      22                 :            :         unsigned gpio;                  /* gpio that triggers the leds */
      23                 :            : };
      24                 :            : 
      25                 :          0 : static irqreturn_t gpio_trig_irq(int irq, void *_led)
      26                 :            : {
      27                 :            :         struct led_classdev *led = _led;
      28                 :            :         struct gpio_trig_data *gpio_data = led_get_trigger_data(led);
      29                 :            :         int tmp;
      30                 :            : 
      31                 :          0 :         tmp = gpio_get_value_cansleep(gpio_data->gpio);
      32         [ #  # ]:          0 :         if (gpio_data->inverted)
      33                 :          0 :                 tmp = !tmp;
      34                 :            : 
      35         [ #  # ]:          0 :         if (tmp) {
      36         [ #  # ]:          0 :                 if (gpio_data->desired_brightness)
      37                 :          0 :                         led_set_brightness_nosleep(gpio_data->led,
      38                 :            :                                            gpio_data->desired_brightness);
      39                 :            :                 else
      40                 :          0 :                         led_set_brightness_nosleep(gpio_data->led, LED_FULL);
      41                 :            :         } else {
      42                 :          0 :                 led_set_brightness_nosleep(gpio_data->led, LED_OFF);
      43                 :            :         }
      44                 :            : 
      45                 :          0 :         return IRQ_HANDLED;
      46                 :            : }
      47                 :            : 
      48                 :          0 : static ssize_t gpio_trig_brightness_show(struct device *dev,
      49                 :            :                 struct device_attribute *attr, char *buf)
      50                 :            : {
      51                 :            :         struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
      52                 :            : 
      53                 :          0 :         return sprintf(buf, "%u\n", gpio_data->desired_brightness);
      54                 :            : }
      55                 :            : 
      56                 :          0 : static ssize_t gpio_trig_brightness_store(struct device *dev,
      57                 :            :                 struct device_attribute *attr, const char *buf, size_t n)
      58                 :            : {
      59                 :            :         struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
      60                 :            :         unsigned desired_brightness;
      61                 :            :         int ret;
      62                 :            : 
      63                 :          0 :         ret = sscanf(buf, "%u", &desired_brightness);
      64   [ #  #  #  # ]:          0 :         if (ret < 1 || desired_brightness > 255) {
      65                 :          0 :                 dev_err(dev, "invalid value\n");
      66                 :          0 :                 return -EINVAL;
      67                 :            :         }
      68                 :            : 
      69                 :          0 :         gpio_data->desired_brightness = desired_brightness;
      70                 :            : 
      71                 :          0 :         return n;
      72                 :            : }
      73                 :            : static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show,
      74                 :            :                 gpio_trig_brightness_store);
      75                 :            : 
      76                 :          0 : static ssize_t gpio_trig_inverted_show(struct device *dev,
      77                 :            :                 struct device_attribute *attr, char *buf)
      78                 :            : {
      79                 :            :         struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
      80                 :            : 
      81                 :          0 :         return sprintf(buf, "%u\n", gpio_data->inverted);
      82                 :            : }
      83                 :            : 
      84                 :          0 : static ssize_t gpio_trig_inverted_store(struct device *dev,
      85                 :            :                 struct device_attribute *attr, const char *buf, size_t n)
      86                 :            : {
      87                 :            :         struct led_classdev *led = led_trigger_get_led(dev);
      88                 :            :         struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
      89                 :            :         unsigned long inverted;
      90                 :            :         int ret;
      91                 :            : 
      92                 :            :         ret = kstrtoul(buf, 10, &inverted);
      93         [ #  # ]:          0 :         if (ret < 0)
      94                 :            :                 return ret;
      95                 :            : 
      96         [ #  # ]:          0 :         if (inverted > 1)
      97                 :            :                 return -EINVAL;
      98                 :            : 
      99                 :          0 :         gpio_data->inverted = inverted;
     100                 :            : 
     101                 :            :         /* After inverting, we need to update the LED. */
     102                 :          0 :         gpio_trig_irq(0, led);
     103                 :            : 
     104                 :          0 :         return n;
     105                 :            : }
     106                 :            : static DEVICE_ATTR(inverted, 0644, gpio_trig_inverted_show,
     107                 :            :                 gpio_trig_inverted_store);
     108                 :            : 
     109                 :          0 : static ssize_t gpio_trig_gpio_show(struct device *dev,
     110                 :            :                 struct device_attribute *attr, char *buf)
     111                 :            : {
     112                 :            :         struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
     113                 :            : 
     114                 :          0 :         return sprintf(buf, "%u\n", gpio_data->gpio);
     115                 :            : }
     116                 :            : 
     117                 :          0 : static ssize_t gpio_trig_gpio_store(struct device *dev,
     118                 :            :                 struct device_attribute *attr, const char *buf, size_t n)
     119                 :            : {
     120                 :            :         struct led_classdev *led = led_trigger_get_led(dev);
     121                 :            :         struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
     122                 :            :         unsigned gpio;
     123                 :            :         int ret;
     124                 :            : 
     125                 :          0 :         ret = sscanf(buf, "%u", &gpio);
     126         [ #  # ]:          0 :         if (ret < 1) {
     127                 :          0 :                 dev_err(dev, "couldn't read gpio number\n");
     128                 :          0 :                 return -EINVAL;
     129                 :            :         }
     130                 :            : 
     131         [ #  # ]:          0 :         if (gpio_data->gpio == gpio)
     132                 :          0 :                 return n;
     133                 :            : 
     134         [ #  # ]:          0 :         if (!gpio_is_valid(gpio)) {
     135         [ #  # ]:          0 :                 if (gpio_is_valid(gpio_data->gpio))
     136                 :          0 :                         free_irq(gpio_to_irq(gpio_data->gpio), led);
     137                 :          0 :                 gpio_data->gpio = gpio;
     138                 :          0 :                 return n;
     139                 :            :         }
     140                 :            : 
     141                 :          0 :         ret = request_threaded_irq(gpio_to_irq(gpio), NULL, gpio_trig_irq,
     142                 :            :                         IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_RISING
     143                 :            :                         | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led);
     144         [ #  # ]:          0 :         if (ret) {
     145                 :          0 :                 dev_err(dev, "request_irq failed with error %d\n", ret);
     146                 :            :         } else {
     147         [ #  # ]:          0 :                 if (gpio_is_valid(gpio_data->gpio))
     148                 :          0 :                         free_irq(gpio_to_irq(gpio_data->gpio), led);
     149                 :          0 :                 gpio_data->gpio = gpio;
     150                 :            :                 /* After changing the GPIO, we need to update the LED. */
     151                 :          0 :                 gpio_trig_irq(0, led);
     152                 :            :         }
     153                 :            : 
     154         [ #  # ]:          0 :         return ret ? ret : n;
     155                 :            : }
     156                 :            : static DEVICE_ATTR(gpio, 0644, gpio_trig_gpio_show, gpio_trig_gpio_store);
     157                 :            : 
     158                 :            : static struct attribute *gpio_trig_attrs[] = {
     159                 :            :         &dev_attr_desired_brightness.attr,
     160                 :            :         &dev_attr_inverted.attr,
     161                 :            :         &dev_attr_gpio.attr,
     162                 :            :         NULL
     163                 :            : };
     164                 :            : ATTRIBUTE_GROUPS(gpio_trig);
     165                 :            : 
     166                 :          0 : static int gpio_trig_activate(struct led_classdev *led)
     167                 :            : {
     168                 :            :         struct gpio_trig_data *gpio_data;
     169                 :            : 
     170                 :          0 :         gpio_data = kzalloc(sizeof(*gpio_data), GFP_KERNEL);
     171         [ #  # ]:          0 :         if (!gpio_data)
     172                 :            :                 return -ENOMEM;
     173                 :            : 
     174                 :          0 :         gpio_data->led = led;
     175                 :          0 :         gpio_data->gpio = -ENOENT;
     176                 :            : 
     177                 :            :         led_set_trigger_data(led, gpio_data);
     178                 :            : 
     179                 :          0 :         return 0;
     180                 :            : }
     181                 :            : 
     182                 :          0 : static void gpio_trig_deactivate(struct led_classdev *led)
     183                 :            : {
     184                 :            :         struct gpio_trig_data *gpio_data = led_get_trigger_data(led);
     185                 :            : 
     186         [ #  # ]:          0 :         if (gpio_is_valid(gpio_data->gpio))
     187                 :          0 :                 free_irq(gpio_to_irq(gpio_data->gpio), led);
     188                 :          0 :         kfree(gpio_data);
     189                 :          0 : }
     190                 :            : 
     191                 :            : static struct led_trigger gpio_led_trigger = {
     192                 :            :         .name           = "gpio",
     193                 :            :         .activate       = gpio_trig_activate,
     194                 :            :         .deactivate     = gpio_trig_deactivate,
     195                 :            :         .groups         = gpio_trig_groups,
     196                 :            : };
     197                 :        404 : module_led_trigger(gpio_led_trigger);
     198                 :            : 
     199                 :            : MODULE_AUTHOR("Felipe Balbi <me@felipebalbi.com>");
     200                 :            : MODULE_DESCRIPTION("GPIO LED trigger");
     201                 :            : MODULE_LICENSE("GPL v2");

Generated by: LCOV version 1.14