Skip to content

Commit

Permalink
gpio: defer probe if pinctrl cannot be found
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
tomeuv authored and linusw committed Jul 28, 2015
1 parent 23393d4 commit 28355f8
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 12 deletions.
27 changes: 18 additions & 9 deletions drivers/gpio/gpiolib-of.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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) {
Expand All @@ -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]) {
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 4 additions & 1 deletion drivers/gpio/gpiolib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions include/linux/of_gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 */
Expand Down

0 comments on commit 28355f8

Please sign in to comment.