diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2017-05-26 09:17:47 -0400 |
---|---|---|
committer | Jacek Anaszewski <jacek.anaszewski@gmail.com> | 2017-05-29 15:55:58 -0400 |
commit | 71c17b06ef7dd23a09725827303e6ed19bf16cce (patch) | |
tree | f8d48c754719d10b1f7d5e38f348196fbc2a4c44 /drivers/leds/trigger | |
parent | 71afe3cb1e8fdf89556047e03bcbcd731f1ab108 (diff) |
leds: trigger: gpio: Use threaded IRQ
This both simplifies the code because we can drop the workqueue
indirection, and it enables using the trigger for GPIOs that work with
threaded IRQs themselves.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
Diffstat (limited to 'drivers/leds/trigger')
-rw-r--r-- | drivers/leds/trigger/ledtrig-gpio.c | 29 |
1 files changed, 6 insertions, 23 deletions
diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c index 93d6b82e6437..8891e88d54dd 100644 --- a/drivers/leds/trigger/ledtrig-gpio.c +++ b/drivers/leds/trigger/ledtrig-gpio.c | |||
@@ -14,14 +14,12 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/gpio.h> | 15 | #include <linux/gpio.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/workqueue.h> | ||
18 | #include <linux/leds.h> | 17 | #include <linux/leds.h> |
19 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
20 | #include "../leds.h" | 19 | #include "../leds.h" |
21 | 20 | ||
22 | struct gpio_trig_data { | 21 | struct gpio_trig_data { |
23 | struct led_classdev *led; | 22 | struct led_classdev *led; |
24 | struct work_struct work; | ||
25 | 23 | ||
26 | unsigned desired_brightness; /* desired brightness when led is on */ | 24 | unsigned desired_brightness; /* desired brightness when led is on */ |
27 | unsigned inverted; /* true when gpio is inverted */ | 25 | unsigned inverted; /* true when gpio is inverted */ |
@@ -32,22 +30,8 @@ static irqreturn_t gpio_trig_irq(int irq, void *_led) | |||
32 | { | 30 | { |
33 | struct led_classdev *led = _led; | 31 | struct led_classdev *led = _led; |
34 | struct gpio_trig_data *gpio_data = led->trigger_data; | 32 | struct gpio_trig_data *gpio_data = led->trigger_data; |
35 | |||
36 | /* just schedule_work since gpio_get_value can sleep */ | ||
37 | schedule_work(&gpio_data->work); | ||
38 | |||
39 | return IRQ_HANDLED; | ||
40 | }; | ||
41 | |||
42 | static void gpio_trig_work(struct work_struct *work) | ||
43 | { | ||
44 | struct gpio_trig_data *gpio_data = container_of(work, | ||
45 | struct gpio_trig_data, work); | ||
46 | int tmp; | 33 | int tmp; |
47 | 34 | ||
48 | if (!gpio_data->gpio) | ||
49 | return; | ||
50 | |||
51 | tmp = gpio_get_value_cansleep(gpio_data->gpio); | 35 | tmp = gpio_get_value_cansleep(gpio_data->gpio); |
52 | if (gpio_data->inverted) | 36 | if (gpio_data->inverted) |
53 | tmp = !tmp; | 37 | tmp = !tmp; |
@@ -61,6 +45,8 @@ static void gpio_trig_work(struct work_struct *work) | |||
61 | } else { | 45 | } else { |
62 | led_set_brightness_nosleep(gpio_data->led, LED_OFF); | 46 | led_set_brightness_nosleep(gpio_data->led, LED_OFF); |
63 | } | 47 | } |
48 | |||
49 | return IRQ_HANDLED; | ||
64 | } | 50 | } |
65 | 51 | ||
66 | static ssize_t gpio_trig_brightness_show(struct device *dev, | 52 | static ssize_t gpio_trig_brightness_show(struct device *dev, |
@@ -120,7 +106,7 @@ static ssize_t gpio_trig_inverted_store(struct device *dev, | |||
120 | gpio_data->inverted = inverted; | 106 | gpio_data->inverted = inverted; |
121 | 107 | ||
122 | /* After inverting, we need to update the LED. */ | 108 | /* After inverting, we need to update the LED. */ |
123 | schedule_work(&gpio_data->work); | 109 | gpio_trig_irq(0, led); |
124 | 110 | ||
125 | return n; | 111 | return n; |
126 | } | 112 | } |
@@ -147,7 +133,6 @@ static ssize_t gpio_trig_gpio_store(struct device *dev, | |||
147 | ret = sscanf(buf, "%u", &gpio); | 133 | ret = sscanf(buf, "%u", &gpio); |
148 | if (ret < 1) { | 134 | if (ret < 1) { |
149 | dev_err(dev, "couldn't read gpio number\n"); | 135 | dev_err(dev, "couldn't read gpio number\n"); |
150 | flush_work(&gpio_data->work); | ||
151 | return -EINVAL; | 136 | return -EINVAL; |
152 | } | 137 | } |
153 | 138 | ||
@@ -161,8 +146,8 @@ static ssize_t gpio_trig_gpio_store(struct device *dev, | |||
161 | return n; | 146 | return n; |
162 | } | 147 | } |
163 | 148 | ||
164 | ret = request_irq(gpio_to_irq(gpio), gpio_trig_irq, | 149 | ret = request_threaded_irq(gpio_to_irq(gpio), NULL, gpio_trig_irq, |
165 | IRQF_SHARED | IRQF_TRIGGER_RISING | 150 | IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_RISING |
166 | | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led); | 151 | | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led); |
167 | if (ret) { | 152 | if (ret) { |
168 | dev_err(dev, "request_irq failed with error %d\n", ret); | 153 | dev_err(dev, "request_irq failed with error %d\n", ret); |
@@ -171,7 +156,7 @@ static ssize_t gpio_trig_gpio_store(struct device *dev, | |||
171 | free_irq(gpio_to_irq(gpio_data->gpio), led); | 156 | free_irq(gpio_to_irq(gpio_data->gpio), led); |
172 | gpio_data->gpio = gpio; | 157 | gpio_data->gpio = gpio; |
173 | /* After changing the GPIO, we need to update the LED. */ | 158 | /* After changing the GPIO, we need to update the LED. */ |
174 | schedule_work(&gpio_data->work); | 159 | gpio_trig_irq(0, led); |
175 | } | 160 | } |
176 | 161 | ||
177 | return ret ? ret : n; | 162 | return ret ? ret : n; |
@@ -201,7 +186,6 @@ static void gpio_trig_activate(struct led_classdev *led) | |||
201 | 186 | ||
202 | gpio_data->led = led; | 187 | gpio_data->led = led; |
203 | led->trigger_data = gpio_data; | 188 | led->trigger_data = gpio_data; |
204 | INIT_WORK(&gpio_data->work, gpio_trig_work); | ||
205 | led->activated = true; | 189 | led->activated = true; |
206 | 190 | ||
207 | return; | 191 | return; |
@@ -224,7 +208,6 @@ static void gpio_trig_deactivate(struct led_classdev *led) | |||
224 | device_remove_file(led->dev, &dev_attr_gpio); | 208 | device_remove_file(led->dev, &dev_attr_gpio); |
225 | device_remove_file(led->dev, &dev_attr_inverted); | 209 | device_remove_file(led->dev, &dev_attr_inverted); |
226 | device_remove_file(led->dev, &dev_attr_desired_brightness); | 210 | device_remove_file(led->dev, &dev_attr_desired_brightness); |
227 | flush_work(&gpio_data->work); | ||
228 | if (gpio_data->gpio != 0) | 211 | if (gpio_data->gpio != 0) |
229 | free_irq(gpio_to_irq(gpio_data->gpio), led); | 212 | free_irq(gpio_to_irq(gpio_data->gpio), led); |
230 | kfree(gpio_data); | 213 | kfree(gpio_data); |