diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2016-05-25 04:56:03 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2016-05-30 03:42:03 -0400 |
commit | 9c10280d85c14a20751ab6c1185ad725172936d6 (patch) | |
tree | f72f8ad76edba5852dd72714dfd0bf8a5ac3bd8c /drivers/gpio | |
parent | 320a6480ef24b03655e1854bd01c9b0a8b8d4a3f (diff) |
gpio: flush direction status in gpiochip_lock_as_irq()
As irqchip and gpiochip functions are orthogonal, the IRQ
set-up or something else can have changed the direction of
the GPIO line from what the GPIO descriptor knows when we
get into gpiochip_lock_as_irq(). Make sure to re-read the
direction setting if we have the .get_direction() callback
enabled for the chip.
Else we get problems like this:
iio iio:device2: interrupts on the rising edge
gpio gpiochip2: (8012e080.gpio): gpiochip_lock_as_irq:
tried to flag a GPIO set as output for IRQ
gpio gpiochip2: (8012e080.gpio): unable to lock HW IRQ 0 for IRQ
genirq: Failed to request resources for l3g4200d-trigger
(irq 111) on irqchip nmk1-32-63
iio iio:device2: failed to request trigger IRQ.
st-gyro-i2c: probe of 2-0068 failed with error -22
Fixes: 72d320006177 ("gpio: set up initial state from .get_direction()")
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpiolib.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d407f904a31c..e901d2666b46 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -2066,17 +2066,30 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq); | |||
2066 | */ | 2066 | */ |
2067 | int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) | 2067 | int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) |
2068 | { | 2068 | { |
2069 | if (offset >= chip->ngpio) | 2069 | struct gpio_desc *desc; |
2070 | return -EINVAL; | 2070 | |
2071 | desc = gpiochip_get_desc(chip, offset); | ||
2072 | if (IS_ERR(desc)) | ||
2073 | return PTR_ERR(desc); | ||
2074 | |||
2075 | /* Flush direction if something changed behind our back */ | ||
2076 | if (chip->get_direction) { | ||
2077 | int dir = chip->get_direction(chip, offset); | ||
2078 | |||
2079 | if (dir) | ||
2080 | clear_bit(FLAG_IS_OUT, &desc->flags); | ||
2081 | else | ||
2082 | set_bit(FLAG_IS_OUT, &desc->flags); | ||
2083 | } | ||
2071 | 2084 | ||
2072 | if (test_bit(FLAG_IS_OUT, &chip->gpiodev->descs[offset].flags)) { | 2085 | if (test_bit(FLAG_IS_OUT, &desc->flags)) { |
2073 | chip_err(chip, | 2086 | chip_err(chip, |
2074 | "%s: tried to flag a GPIO set as output for IRQ\n", | 2087 | "%s: tried to flag a GPIO set as output for IRQ\n", |
2075 | __func__); | 2088 | __func__); |
2076 | return -EIO; | 2089 | return -EIO; |
2077 | } | 2090 | } |
2078 | 2091 | ||
2079 | set_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags); | 2092 | set_bit(FLAG_USED_AS_IRQ, &desc->flags); |
2080 | return 0; | 2093 | return 0; |
2081 | } | 2094 | } |
2082 | EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); | 2095 | EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); |