summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c56
1 files changed, 53 insertions, 3 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5d6c71edc73..c5f650095fa 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -623,9 +623,11 @@ static ssize_t export_store(struct class *class,
*/
status = gpio_request(gpio, "sysfs");
- if (status < 0)
+ if (status < 0) {
+ if (status == -EPROBE_DEFER)
+ status = -ENODEV;
goto done;
-
+ }
status = gpio_export(gpio, true);
if (status < 0)
gpio_free(gpio);
@@ -1081,6 +1083,10 @@ int gpiochip_add(struct gpio_chip *chip)
}
}
+#ifdef CONFIG_PINCTRL
+ INIT_LIST_HEAD(&chip->pin_ranges);
+#endif
+
of_gpiochip_add(chip);
unlock:
@@ -1121,6 +1127,7 @@ int gpiochip_remove(struct gpio_chip *chip)
spin_lock_irqsave(&gpio_lock, flags);
+ gpiochip_remove_pin_ranges(chip);
of_gpiochip_remove(chip);
for (id = chip->base; id < chip->base + chip->ngpio; id++) {
@@ -1178,6 +1185,47 @@ struct gpio_chip *gpiochip_find(void *data,
}
EXPORT_SYMBOL_GPL(gpiochip_find);
+#ifdef CONFIG_PINCTRL
+
+int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+ unsigned int pin_base, unsigned int npins)
+{
+ struct gpio_pin_range *pin_range;
+
+ pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), GFP_KERNEL);
+ if (!pin_range) {
+ pr_err("%s: GPIO chip: failed to allocate pin ranges\n",
+ chip->label);
+ return -ENOMEM;
+ }
+
+ pin_range->range.name = chip->label;
+ pin_range->range.base = chip->base;
+ pin_range->range.pin_base = pin_base;
+ pin_range->range.npins = npins;
+ pin_range->pctldev = find_pinctrl_and_add_gpio_range(pinctl_name,
+ &pin_range->range);
+
+ list_add_tail(&pin_range->node, &chip->pin_ranges);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
+
+void gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+ struct gpio_pin_range *pin_range, *tmp;
+
+ list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) {
+ list_del(&pin_range->node);
+ pinctrl_remove_gpio_range(pin_range->pctldev,
+ &pin_range->range);
+ }
+}
+EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
+
+#endif /* CONFIG_PINCTRL */
+
/* These "optional" allocation calls help prevent drivers from stomping
* on each other, and help provide better diagnostics in debugfs.
* They're called even less than the "set direction" calls.
@@ -1191,8 +1239,10 @@ int gpio_request(unsigned gpio, const char *label)
spin_lock_irqsave(&gpio_lock, flags);
- if (!gpio_is_valid(gpio))
+ if (!gpio_is_valid(gpio)) {
+ status = -EINVAL;
goto done;
+ }
desc = &gpio_desc[gpio];
chip = desc->chip;
if (chip == NULL)