summaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2014-12-02 15:15:05 +0100
committerLinus Walleij <linus.walleij@linaro.org>2014-12-02 15:46:36 +0100
commit0e9a5edf5d01356fa4a561772a25d97b3fd13de6 (patch)
treefc38446b2de4c5edd95f69df5d770cd48779a2d6 /drivers/gpio
parentserial: mctrl_gpio: use gpiod_set_array function (diff)
downloadlinux-0e9a5edf5d01356fa4a561772a25d97b3fd13de6.tar.xz
linux-0e9a5edf5d01356fa4a561772a25d97b3fd13de6.zip
gpio: fix deferred probe detection for legacy API
Commit 14e85c0e69d5 ("gpio: remove gpio_descs global array") changed gpio_to_desc()'s behavior to return NULL not only for GPIOs numbers not in the valid range, but also for all GPIOs whose controller has not been probed yet. Although this behavior is more correct (nothing hints that these GPIO numbers will be populated later), this affects gpio_request() and gpio_request_one() which call gpiod_request() with a NULL descriptor, causing it to return -EINVAL instead of the expected -EPROBE_DEFER for a non-probed GPIO. gpiod_request() is only called with a descriptor obtained from gpio_to_desc() from these two functions, so address the issue there. Other ways to obtain GPIOs rely on well-defined mappings and can thus return -EPROBE_DEFER only for relevant GPIOs, and are thus not affected by this issue. Reported-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpiolib-legacy.c12
-rw-r--r--drivers/gpio/gpiolib.c4
2 files changed, 14 insertions, 2 deletions
diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c
index 078ae6c2df79..8b830996fe02 100644
--- a/drivers/gpio/gpiolib-legacy.c
+++ b/drivers/gpio/gpiolib-legacy.c
@@ -24,6 +24,10 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
desc = gpio_to_desc(gpio);
+ /* Compatibility: assume unavailable "valid" GPIOs will appear later */
+ if (!desc && gpio_is_valid(gpio))
+ return -EPROBE_DEFER;
+
err = gpiod_request(desc, label);
if (err)
return err;
@@ -62,7 +66,13 @@ EXPORT_SYMBOL_GPL(gpio_request_one);
int gpio_request(unsigned gpio, const char *label)
{
- return gpiod_request(gpio_to_desc(gpio), label);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
+
+ /* Compatibility: assume unavailable "valid" GPIOs will appear later */
+ if (!desc && gpio_is_valid(gpio))
+ return -EPROBE_DEFER;
+
+ return gpiod_request(desc, label);
}
EXPORT_SYMBOL_GPL(gpio_request);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 0b271ef87c09..56b7c5de95a0 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -77,7 +77,9 @@ struct gpio_desc *gpio_to_desc(unsigned gpio)
spin_unlock_irqrestore(&gpio_lock, flags);
- WARN(1, "invalid GPIO %d\n", gpio);
+ if (!gpio_is_valid(gpio))
+ WARN(1, "invalid GPIO %d\n", gpio);
+
return NULL;
}
EXPORT_SYMBOL_GPL(gpio_to_desc);