summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomeu Vizoso <tomeu.vizoso@collabora.com>2015-07-14 10:29:54 +0200
committerLinus Walleij <linus.walleij@linaro.org>2015-07-28 13:55:36 +0200
commit28355f81969962cf01aef5b13d7de5b4ab0c5f13 (patch)
treed2f124df65cc05d337ddf3958c6263c021c3eb2a
parent23393d49fb75ca97b179668aa86b7038c2dc0831 (diff)
gpio: defer probe if pinctrl cannot be found
When an OF node has a pin range for its GPIOs, return -EPROBE_DEFER if the pin controller isn't available. Otherwise, the GPIO range wouldn't be set at all unless the pin controller probed always before the GPIO chip. With this change, the probe of the GPIO chip will be deferred and will be retried at a later point, hopefully once the pin controller has been registered and probed already. Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/gpio/gpiolib-of.c27
-rw-r--r--drivers/gpio/gpiolib.c5
-rw-r--r--include/linux/of_gpio.h4
3 files changed, 24 insertions, 12 deletions
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 1e36ec5e2e0c..fa6e3c8823d6 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -335,7 +335,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
EXPORT_SYMBOL(of_mm_gpiochip_remove);
#ifdef CONFIG_PINCTRL
-static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
+static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
{
struct device_node *np = chip->of_node;
struct of_phandle_args pinspec;
@@ -346,7 +346,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
struct property *group_names;
if (!np)
- return;
+ return 0;
group_names = of_find_property(np, group_names_propname, NULL);
@@ -358,7 +358,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
pctldev = of_pinctrl_get(pinspec.np);
if (!pctldev)
- break;
+ return -EPROBE_DEFER;
if (pinspec.args[2]) {
if (group_names) {
@@ -378,7 +378,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
pinspec.args[1],
pinspec.args[2]);
if (ret)
- break;
+ return ret;
} else {
/* npins == 0: special range */
if (pinspec.args[1]) {
@@ -408,32 +408,41 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
ret = gpiochip_add_pingroup_range(chip, pctldev,
pinspec.args[0], name);
if (ret)
- break;
+ return ret;
}
}
+
+ return 0;
}
#else
-static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {}
+static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; }
#endif
-void of_gpiochip_add(struct gpio_chip *chip)
+int of_gpiochip_add(struct gpio_chip *chip)
{
+ int status;
+
if ((!chip->of_node) && (chip->dev))
chip->of_node = chip->dev->of_node;
if (!chip->of_node)
- return;
+ return 0;
if (!chip->of_xlate) {
chip->of_gpio_n_cells = 2;
chip->of_xlate = of_gpio_simple_xlate;
}
- of_gpiochip_add_pin_range(chip);
+ status = of_gpiochip_add_pin_range(chip);
+ if (status)
+ return status;
+
of_node_get(chip->of_node);
of_gpiochip_scan_hogs(chip);
+
+ return 0;
}
void of_gpiochip_remove(struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 9312bbcb19b9..1b5b8da71154 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -290,7 +290,10 @@ int gpiochip_add(struct gpio_chip *chip)
if (!chip->owner && chip->dev && chip->dev->driver)
chip->owner = chip->dev->driver->owner;
- of_gpiochip_add(chip);
+ status = of_gpiochip_add(chip);
+ if (status)
+ goto err_remove_chip;
+
acpi_gpiochip_add(chip);
status = gpiochip_sysfs_register(chip);
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index 69dbe312b11b..f3191828f037 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -54,7 +54,7 @@ extern int of_mm_gpiochip_add(struct device_node *np,
struct of_mm_gpio_chip *mm_gc);
extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
-extern void of_gpiochip_add(struct gpio_chip *gc);
+extern int of_gpiochip_add(struct gpio_chip *gc);
extern void of_gpiochip_remove(struct gpio_chip *gc);
extern int of_gpio_simple_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec,
@@ -76,7 +76,7 @@ static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
return -ENOSYS;
}
-static inline void of_gpiochip_add(struct gpio_chip *gc) { }
+static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
#endif /* CONFIG_OF_GPIO */