]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blobdiff - drivers/gpio/gpiolib.c
Merge tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux-2.6
[can-eth-gw-linux.git] / drivers / gpio / gpiolib.c
index fd2b71c7099769f12e48be87d80f5f9714894deb..199fca15f2703ba4b32f749cf5ee41d78736b5ae 100644 (file)
@@ -651,9 +651,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);
@@ -1118,6 +1120,10 @@ int gpiochip_add(struct gpio_chip *chip)
                }
        }
 
+#ifdef CONFIG_PINCTRL
+       INIT_LIST_HEAD(&chip->pin_ranges);
+#endif
+
        of_gpiochip_add(chip);
 
 unlock:
@@ -1158,6 +1164,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++) {
@@ -1215,6 +1222,77 @@ struct gpio_chip *gpiochip_find(void *data,
 }
 EXPORT_SYMBOL_GPL(gpiochip_find);
 
+#ifdef CONFIG_PINCTRL
+
+/**
+ * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping
+ * @chip: the gpiochip to add the range for
+ * @pinctrl_name: the dev_name() of the pin controller to map to
+ * @gpio_offset: the start offset in the current gpio_chip number space
+ * @pin_offset: the start offset in the pin controller number space
+ * @npins: the number of pins from the offset of each pin space (GPIO and
+ *     pin controller) to accumulate in this range
+ */
+int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+                          unsigned int gpio_offset, unsigned int pin_offset,
+                          unsigned int npins)
+{
+       struct gpio_pin_range *pin_range;
+       int ret;
+
+       pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
+       if (!pin_range) {
+               pr_err("%s: GPIO chip: failed to allocate pin ranges\n",
+                               chip->label);
+               return -ENOMEM;
+       }
+
+       /* Use local offset as range ID */
+       pin_range->range.id = gpio_offset;
+       pin_range->range.gc = chip;
+       pin_range->range.name = chip->label;
+       pin_range->range.base = chip->base + gpio_offset;
+       pin_range->range.pin_base = pin_offset;
+       pin_range->range.npins = npins;
+       pin_range->pctldev = pinctrl_find_and_add_gpio_range(pinctl_name,
+                       &pin_range->range);
+       if (IS_ERR(pin_range->pctldev)) {
+               ret = PTR_ERR(pin_range->pctldev);
+               pr_err("%s: GPIO chip: could not create pin range\n",
+                      chip->label);
+               kfree(pin_range);
+               return ret;
+       }
+       pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PIN %d->%d\n",
+                chip->label, gpio_offset, gpio_offset + npins - 1,
+                pinctl_name,
+                pin_offset, pin_offset + npins - 1);
+
+       list_add_tail(&pin_range->node, &chip->pin_ranges);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
+
+/**
+ * gpiochip_remove_pin_ranges() - remove all the GPIO <-> pin mappings
+ * @chip: the chip to remove all the mappings for
+ */
+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);
+               kfree(pin_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.
@@ -1228,8 +1306,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)