Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

leds: triggers: gpio: Rewrite to use trigger-sources

By providing a GPIO line as "trigger-sources" in the FWNODE
(such as from the device tree) and combining with the
GPIO trigger, we can support a GPIO LED trigger in a natural
way from the hardware description instead of using the
custom sysfs and deprecated global GPIO numberspace.

Example:

gpio: gpio@0 {
compatible "my-gpio";
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
#trigger-source-cells = <2>;
};

leds {
compatible = "gpio-leds";
led-my-gpio {
label = "device:blue:myled";
gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
default-state = "off";
linux,default-trigger = "gpio";
trigger-sources = <&gpio 1 GPIO_ACTIVE_HIGH>;
};
};

Make this the norm, unmark the driver as broken.

Delete the sysfs handling of GPIOs.

Since GPIO descriptors inherently can describe inversion,
the inversion handling can just be deleted.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20230926-gpio-led-trigger-dt-v2-3-e06e458b788e@linaro.org
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Linus Walleij and committed by
Lee Jones
4a11dbf0 f9be4d5b

+41 -101
+1 -4
drivers/leds/trigger/Kconfig
··· 83 83 config LEDS_TRIGGER_GPIO 84 84 tristate "LED GPIO Trigger" 85 85 depends on GPIOLIB || COMPILE_TEST 86 - depends on BROKEN 87 86 help 88 87 This allows LEDs to be controlled by gpio events. It's good 89 88 when using gpios as switches and triggering the needed LEDs 90 - from there. One use case is n810's keypad LEDs that could 91 - be triggered by this trigger when user slides up to show 92 - keypad. 89 + from there. Triggers are defined as device properties. 93 90 94 91 If unsure, say N. 95 92
+40 -97
drivers/leds/trigger/ledtrig-gpio.c
··· 3 3 * ledtrig-gio.c - LED Trigger Based on GPIO events 4 4 * 5 5 * Copyright 2009 Felipe Balbi <me@felipebalbi.com> 6 + * Copyright 2023 Linus Walleij <linus.walleij@linaro.org> 6 7 */ 7 8 8 9 #include <linux/module.h> 9 10 #include <linux/kernel.h> 10 11 #include <linux/init.h> 11 - #include <linux/gpio.h> 12 + #include <linux/gpio/consumer.h> 12 13 #include <linux/interrupt.h> 13 14 #include <linux/leds.h> 14 15 #include <linux/slab.h> ··· 17 16 18 17 struct gpio_trig_data { 19 18 struct led_classdev *led; 20 - 21 19 unsigned desired_brightness; /* desired brightness when led is on */ 22 - unsigned inverted; /* true when gpio is inverted */ 23 - unsigned gpio; /* gpio that triggers the leds */ 20 + struct gpio_desc *gpiod; /* gpio that triggers the led */ 24 21 }; 25 22 26 23 static irqreturn_t gpio_trig_irq(int irq, void *_led) ··· 27 28 struct gpio_trig_data *gpio_data = led_get_trigger_data(led); 28 29 int tmp; 29 30 30 - tmp = gpio_get_value_cansleep(gpio_data->gpio); 31 - if (gpio_data->inverted) 32 - tmp = !tmp; 33 - 31 + tmp = gpiod_get_value_cansleep(gpio_data->gpiod); 34 32 if (tmp) { 35 33 if (gpio_data->desired_brightness) 36 34 led_set_brightness_nosleep(gpio_data->led, ··· 69 73 static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show, 70 74 gpio_trig_brightness_store); 71 75 72 - static ssize_t gpio_trig_inverted_show(struct device *dev, 73 - struct device_attribute *attr, char *buf) 74 - { 75 - struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 76 - 77 - return sprintf(buf, "%u\n", gpio_data->inverted); 78 - } 79 - 80 - static ssize_t gpio_trig_inverted_store(struct device *dev, 81 - struct device_attribute *attr, const char *buf, size_t n) 82 - { 83 - struct led_classdev *led = led_trigger_get_led(dev); 84 - struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 85 - unsigned long inverted; 86 - int ret; 87 - 88 - ret = kstrtoul(buf, 10, &inverted); 89 - if (ret < 0) 90 - return ret; 91 - 92 - if (inverted > 1) 93 - return -EINVAL; 94 - 95 - gpio_data->inverted = inverted; 96 - 97 - /* After inverting, we need to update the LED. */ 98 - if (gpio_is_valid(gpio_data->gpio)) 99 - gpio_trig_irq(0, led); 100 - 101 - return n; 102 - } 103 - static DEVICE_ATTR(inverted, 0644, gpio_trig_inverted_show, 104 - gpio_trig_inverted_store); 105 - 106 - static ssize_t gpio_trig_gpio_show(struct device *dev, 107 - struct device_attribute *attr, char *buf) 108 - { 109 - struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 110 - 111 - return sprintf(buf, "%u\n", gpio_data->gpio); 112 - } 113 - 114 - static ssize_t gpio_trig_gpio_store(struct device *dev, 115 - struct device_attribute *attr, const char *buf, size_t n) 116 - { 117 - struct led_classdev *led = led_trigger_get_led(dev); 118 - struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 119 - unsigned gpio; 120 - int ret; 121 - 122 - ret = sscanf(buf, "%u", &gpio); 123 - if (ret < 1) { 124 - dev_err(dev, "couldn't read gpio number\n"); 125 - return -EINVAL; 126 - } 127 - 128 - if (gpio_data->gpio == gpio) 129 - return n; 130 - 131 - if (!gpio_is_valid(gpio)) { 132 - if (gpio_is_valid(gpio_data->gpio)) 133 - free_irq(gpio_to_irq(gpio_data->gpio), led); 134 - gpio_data->gpio = gpio; 135 - return n; 136 - } 137 - 138 - ret = request_threaded_irq(gpio_to_irq(gpio), NULL, gpio_trig_irq, 139 - IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_RISING 140 - | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led); 141 - if (ret) { 142 - dev_err(dev, "request_irq failed with error %d\n", ret); 143 - } else { 144 - if (gpio_is_valid(gpio_data->gpio)) 145 - free_irq(gpio_to_irq(gpio_data->gpio), led); 146 - gpio_data->gpio = gpio; 147 - /* After changing the GPIO, we need to update the LED. */ 148 - gpio_trig_irq(0, led); 149 - } 150 - 151 - return ret ? ret : n; 152 - } 153 - static DEVICE_ATTR(gpio, 0644, gpio_trig_gpio_show, gpio_trig_gpio_store); 154 - 155 76 static struct attribute *gpio_trig_attrs[] = { 156 77 &dev_attr_desired_brightness.attr, 157 - &dev_attr_inverted.attr, 158 - &dev_attr_gpio.attr, 159 78 NULL 160 79 }; 161 80 ATTRIBUTE_GROUPS(gpio_trig); ··· 78 167 static int gpio_trig_activate(struct led_classdev *led) 79 168 { 80 169 struct gpio_trig_data *gpio_data; 170 + struct device *dev = led->dev; 171 + int ret; 81 172 82 173 gpio_data = kzalloc(sizeof(*gpio_data), GFP_KERNEL); 83 174 if (!gpio_data) 84 175 return -ENOMEM; 85 176 86 - gpio_data->led = led; 87 - gpio_data->gpio = -ENOENT; 177 + /* 178 + * The generic property "trigger-sources" is followed, 179 + * and we hope that this is a GPIO. 180 + */ 181 + gpio_data->gpiod = fwnode_gpiod_get_index(dev->fwnode, 182 + "trigger-sources", 183 + 0, GPIOD_IN, 184 + "led-trigger"); 185 + if (IS_ERR(gpio_data->gpiod)) { 186 + ret = PTR_ERR(gpio_data->gpiod); 187 + kfree(gpio_data); 188 + return ret; 189 + } 190 + if (!gpio_data->gpiod) { 191 + dev_err(dev, "no valid GPIO for the trigger\n"); 192 + kfree(gpio_data); 193 + return -EINVAL; 194 + } 88 195 196 + gpio_data->led = led; 89 197 led_set_trigger_data(led, gpio_data); 198 + 199 + ret = request_threaded_irq(gpiod_to_irq(gpio_data->gpiod), NULL, gpio_trig_irq, 200 + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_RISING 201 + | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led); 202 + if (ret) { 203 + dev_err(dev, "request_irq failed with error %d\n", ret); 204 + gpiod_put(gpio_data->gpiod); 205 + kfree(gpio_data); 206 + return ret; 207 + } 208 + 209 + /* Finally update the LED to initial status */ 210 + gpio_trig_irq(0, led); 90 211 91 212 return 0; 92 213 } ··· 127 184 { 128 185 struct gpio_trig_data *gpio_data = led_get_trigger_data(led); 129 186 130 - if (gpio_is_valid(gpio_data->gpio)) 131 - free_irq(gpio_to_irq(gpio_data->gpio), led); 187 + free_irq(gpiod_to_irq(gpio_data->gpiod), led); 188 + gpiod_put(gpio_data->gpiod); 132 189 kfree(gpio_data); 133 190 } 134 191