gpio: sysfs: fix redundant lock-as-irq handling
authorJohan Hovold <johan@kernel.org>
Mon, 4 May 2015 15:10:28 +0000 (17:10 +0200)
committerLinus Walleij <linus.walleij@linaro.org>
Tue, 12 May 2015 08:46:31 +0000 (10:46 +0200)
Drivers should call gpiochip_lock_as_irq (which prevents the pin
direction from being changed) in their irq_request_resources callbacks
but some drivers currently fail to do so.

Instead a second, explicit and often redundant call to lock-as-irq is
made by the sysfs-interface implementation after an irq has been
requested.

Move the explicit call before the irq-request to match the unlock done
after the irq is later released. Note that this also fixes an irq leak,
should the explicit call ever have failed.

Also add a comment about removing the redundant call once the broken
drivers have been fixed.

Signed-off-by: Johan Hovold <johan@kernel.org>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/gpio/gpiolib-sysfs.c

index af3bc7a8033bdcbaa2e93602bb107fbe12968d35..b2b62cc6f9e1ed7133bd6c0d186c9c005ed41872 100644 (file)
@@ -195,20 +195,28 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
                }
        }
 
-       ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
-                               "gpiolib", value_sd);
+       /*
+        * FIXME: This should be done in the irq_request_resources callback
+        *        when the irq is requested, but a few drivers currently fail
+        *        to do so.
+        *
+        *        Remove this redundant call (along with the corresponding
+        *        unlock) when those drivers have been fixed.
+        */
+       ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
        if (ret < 0)
                goto free_id;
 
-       ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
-       if (ret < 0) {
-               gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
-               goto free_id;
-       }
+       ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
+                               "gpiolib", value_sd);
+       if (ret < 0)
+               goto err_unlock;
 
        desc->flags |= gpio_flags;
        return 0;
 
+err_unlock:
+       gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
 free_id:
        idr_remove(&dirent_idr, id);
        desc->flags &= GPIO_FLAGS_MASK;