root/drivers/leds/trigger/ledtrig-gpio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gpio_trig_irq
  2. gpio_trig_brightness_show
  3. gpio_trig_brightness_store
  4. gpio_trig_inverted_show
  5. gpio_trig_inverted_store
  6. gpio_trig_gpio_show
  7. gpio_trig_gpio_store
  8. gpio_trig_activate
  9. gpio_trig_deactivate

   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 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         tmp = gpio_get_value_cansleep(gpio_data->gpio);
  32         if (gpio_data->inverted)
  33                 tmp = !tmp;
  34 
  35         if (tmp) {
  36                 if (gpio_data->desired_brightness)
  37                         led_set_brightness_nosleep(gpio_data->led,
  38                                            gpio_data->desired_brightness);
  39                 else
  40                         led_set_brightness_nosleep(gpio_data->led, LED_FULL);
  41         } else {
  42                 led_set_brightness_nosleep(gpio_data->led, LED_OFF);
  43         }
  44 
  45         return IRQ_HANDLED;
  46 }
  47 
  48 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         return sprintf(buf, "%u\n", gpio_data->desired_brightness);
  54 }
  55 
  56 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         ret = sscanf(buf, "%u", &desired_brightness);
  64         if (ret < 1 || desired_brightness > 255) {
  65                 dev_err(dev, "invalid value\n");
  66                 return -EINVAL;
  67         }
  68 
  69         gpio_data->desired_brightness = desired_brightness;
  70 
  71         return n;
  72 }
  73 static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show,
  74                 gpio_trig_brightness_store);
  75 
  76 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         return sprintf(buf, "%u\n", gpio_data->inverted);
  82 }
  83 
  84 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         if (ret < 0)
  94                 return ret;
  95 
  96         if (inverted > 1)
  97                 return -EINVAL;
  98 
  99         gpio_data->inverted = inverted;
 100 
 101         /* After inverting, we need to update the LED. */
 102         gpio_trig_irq(0, led);
 103 
 104         return n;
 105 }
 106 static DEVICE_ATTR(inverted, 0644, gpio_trig_inverted_show,
 107                 gpio_trig_inverted_store);
 108 
 109 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         return sprintf(buf, "%u\n", gpio_data->gpio);
 115 }
 116 
 117 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         ret = sscanf(buf, "%u", &gpio);
 126         if (ret < 1) {
 127                 dev_err(dev, "couldn't read gpio number\n");
 128                 return -EINVAL;
 129         }
 130 
 131         if (gpio_data->gpio == gpio)
 132                 return n;
 133 
 134         if (!gpio_is_valid(gpio)) {
 135                 if (gpio_is_valid(gpio_data->gpio))
 136                         free_irq(gpio_to_irq(gpio_data->gpio), led);
 137                 gpio_data->gpio = gpio;
 138                 return n;
 139         }
 140 
 141         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         if (ret) {
 145                 dev_err(dev, "request_irq failed with error %d\n", ret);
 146         } else {
 147                 if (gpio_is_valid(gpio_data->gpio))
 148                         free_irq(gpio_to_irq(gpio_data->gpio), led);
 149                 gpio_data->gpio = gpio;
 150                 /* After changing the GPIO, we need to update the LED. */
 151                 gpio_trig_irq(0, led);
 152         }
 153 
 154         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 static int gpio_trig_activate(struct led_classdev *led)
 167 {
 168         struct gpio_trig_data *gpio_data;
 169 
 170         gpio_data = kzalloc(sizeof(*gpio_data), GFP_KERNEL);
 171         if (!gpio_data)
 172                 return -ENOMEM;
 173 
 174         gpio_data->led = led;
 175         gpio_data->gpio = -ENOENT;
 176 
 177         led_set_trigger_data(led, gpio_data);
 178 
 179         return 0;
 180 }
 181 
 182 static void gpio_trig_deactivate(struct led_classdev *led)
 183 {
 184         struct gpio_trig_data *gpio_data = led_get_trigger_data(led);
 185 
 186         if (gpio_is_valid(gpio_data->gpio))
 187                 free_irq(gpio_to_irq(gpio_data->gpio), led);
 188         kfree(gpio_data);
 189 }
 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 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");

/* [<][>][^][v][top][bottom][index][help] */