Merge branch 'for-4.1' of git://linux-nfs.org/~bfields/linux
[firefly-linux-kernel-4.4.55.git] / drivers / gpio / gpiolib.c
index 1ca9295b2c1017df34dacad5c0217677b6c2d60d..59eaa23767d8dca5bddf740fa90a24c9699c4a0b 100644 (file)
@@ -315,6 +315,7 @@ EXPORT_SYMBOL_GPL(gpiochip_add);
 
 /* Forward-declaration */
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
+static void gpiochip_free_hogs(struct gpio_chip *chip);
 
 /**
  * gpiochip_remove() - unregister a gpio_chip
@@ -333,6 +334,7 @@ void gpiochip_remove(struct gpio_chip *chip)
 
        acpi_gpiochip_remove(chip);
        gpiochip_remove_pin_ranges(chip);
+       gpiochip_free_hogs(chip);
        of_gpiochip_remove(chip);
 
        spin_lock_irqsave(&gpio_lock, flags);
@@ -866,6 +868,7 @@ static bool __gpiod_free(struct gpio_desc *desc)
                clear_bit(FLAG_REQUESTED, &desc->flags);
                clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
                clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
+               clear_bit(FLAG_IS_HOGGED, &desc->flags);
                ret = true;
        }
 
@@ -1659,19 +1662,18 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
                                      unsigned int idx,
                                      enum gpio_lookup_flags *flags)
 {
-       static const char * const suffixes[] = { "gpios", "gpio" };
        char prop_name[32]; /* 32 is max size of property name */
        enum of_gpio_flags of_flags;
        struct gpio_desc *desc;
        unsigned int i;
 
-       for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
                if (con_id)
                        snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id,
-                                                              suffixes[i]);
+                                gpio_suffixes[i]);
                else
                        snprintf(prop_name, sizeof(prop_name), "%s",
-                                                              suffixes[i]);
+                                gpio_suffixes[i]);
 
                desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
                                                &of_flags);
@@ -1692,7 +1694,6 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
                                        unsigned int idx,
                                        enum gpio_lookup_flags *flags)
 {
-       static const char * const suffixes[] = { "gpios", "gpio" };
        struct acpi_device *adev = ACPI_COMPANION(dev);
        struct acpi_gpio_info info;
        struct gpio_desc *desc;
@@ -1700,13 +1701,13 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
        int i;
 
        /* Try first from _DSD */
-       for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
                if (con_id && strcmp(con_id, "gpios")) {
                        snprintf(propname, sizeof(propname), "%s-%s",
-                                con_id, suffixes[i]);
+                                con_id, gpio_suffixes[i]);
                } else {
                        snprintf(propname, sizeof(propname), "%s",
-                                suffixes[i]);
+                                gpio_suffixes[i]);
                }
 
                desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
@@ -1805,6 +1806,70 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
        return desc;
 }
 
+static int dt_gpio_count(struct device *dev, const char *con_id)
+{
+       int ret;
+       char propname[32];
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+               if (con_id)
+                       snprintf(propname, sizeof(propname), "%s-%s",
+                                con_id, gpio_suffixes[i]);
+               else
+                       snprintf(propname, sizeof(propname), "%s",
+                                gpio_suffixes[i]);
+
+               ret = of_gpio_named_count(dev->of_node, propname);
+               if (ret >= 0)
+                       break;
+       }
+       return ret;
+}
+
+static int platform_gpio_count(struct device *dev, const char *con_id)
+{
+       struct gpiod_lookup_table *table;
+       struct gpiod_lookup *p;
+       unsigned int count = 0;
+
+       table = gpiod_find_lookup_table(dev);
+       if (!table)
+               return -ENOENT;
+
+       for (p = &table->table[0]; p->chip_label; p++) {
+               if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) ||
+                   (!con_id && !p->con_id))
+                       count++;
+       }
+       if (!count)
+               return -ENOENT;
+
+       return count;
+}
+
+/**
+ * gpiod_count - return the number of GPIOs associated with a device / function
+ *             or -ENOENT if no GPIO has been assigned to the requested function
+ * @dev:       GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id:    function within the GPIO consumer
+ */
+int gpiod_count(struct device *dev, const char *con_id)
+{
+       int count = -ENOENT;
+
+       if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
+               count = dt_gpio_count(dev, con_id);
+       else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev))
+               count = acpi_gpio_count(dev, con_id);
+
+       if (count < 0)
+               count = platform_gpio_count(dev, con_id);
+
+       return count;
+}
+EXPORT_SYMBOL_GPL(gpiod_count);
+
 /**
  * gpiod_get - obtain a GPIO for a given GPIO function
  * @dev:       GPIO consumer, can be NULL for system-global GPIOs
@@ -1840,6 +1905,47 @@ struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(__gpiod_get_optional);
 
+
+/**
+ * gpiod_configure_flags - helper function to configure a given GPIO
+ * @desc:      gpio whose value will be assigned
+ * @con_id:    function within the GPIO consumer
+ * @lflags:    gpio_lookup_flags - returned from of_find_gpio() or
+ *             of_get_gpio_hog()
+ * @dflags:    gpiod_flags - optional GPIO initialization flags
+ *
+ * Return 0 on success, -ENOENT if no GPIO has been assigned to the
+ * requested function and/or index, or another IS_ERR() code if an error
+ * occurred while trying to acquire the GPIO.
+ */
+static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
+               unsigned long lflags, enum gpiod_flags dflags)
+{
+       int status;
+
+       if (lflags & GPIO_ACTIVE_LOW)
+               set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+       if (lflags & GPIO_OPEN_DRAIN)
+               set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+       if (lflags & GPIO_OPEN_SOURCE)
+               set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
+       /* No particular flag request, return here... */
+       if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
+               pr_debug("no flags found for %s\n", con_id);
+               return 0;
+       }
+
+       /* Process flags */
+       if (dflags & GPIOD_FLAGS_BIT_DIR_OUT)
+               status = gpiod_direction_output(desc,
+                                             dflags & GPIOD_FLAGS_BIT_DIR_VAL);
+       else
+               status = gpiod_direction_input(desc);
+
+       return status;
+}
+
 /**
  * gpiod_get_index - obtain a GPIO from a multi-index GPIO function
  * @dev:       GPIO consumer, can be NULL for system-global GPIOs
@@ -1865,13 +1971,15 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
 
        dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
 
-       /* Using device tree? */
-       if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) {
-               dev_dbg(dev, "using device tree for GPIO lookup\n");
-               desc = of_find_gpio(dev, con_id, idx, &lookupflags);
-       } else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) {
-               dev_dbg(dev, "using ACPI for GPIO lookup\n");
-               desc = acpi_find_gpio(dev, con_id, idx, &lookupflags);
+       if (dev) {
+               /* Using device tree? */
+               if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+                       dev_dbg(dev, "using device tree for GPIO lookup\n");
+                       desc = of_find_gpio(dev, con_id, idx, &lookupflags);
+               } else if (ACPI_COMPANION(dev)) {
+                       dev_dbg(dev, "using ACPI for GPIO lookup\n");
+                       desc = acpi_find_gpio(dev, con_id, idx, &lookupflags);
+               }
        }
 
        /*
@@ -1889,28 +1997,10 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
        }
 
        status = gpiod_request(desc, con_id);
-
        if (status < 0)
                return ERR_PTR(status);
 
-       if (lookupflags & GPIO_ACTIVE_LOW)
-               set_bit(FLAG_ACTIVE_LOW, &desc->flags);
-       if (lookupflags & GPIO_OPEN_DRAIN)
-               set_bit(FLAG_OPEN_DRAIN, &desc->flags);
-       if (lookupflags & GPIO_OPEN_SOURCE)
-               set_bit(FLAG_OPEN_SOURCE, &desc->flags);
-
-       /* No particular flag request, return here... */
-       if (!(flags & GPIOD_FLAGS_BIT_DIR_SET))
-               return desc;
-
-       /* Process flags */
-       if (flags & GPIOD_FLAGS_BIT_DIR_OUT)
-               status = gpiod_direction_output(desc,
-                                             flags & GPIOD_FLAGS_BIT_DIR_VAL);
-       else
-               status = gpiod_direction_input(desc);
-
+       status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
        if (status < 0) {
                dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
                gpiod_put(desc);
@@ -2005,6 +2095,132 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(__gpiod_get_index_optional);
 
+/**
+ * gpiod_hog - Hog the specified GPIO desc given the provided flags
+ * @desc:      gpio whose value will be assigned
+ * @name:      gpio line name
+ * @lflags:    gpio_lookup_flags - returned from of_find_gpio() or
+ *             of_get_gpio_hog()
+ * @dflags:    gpiod_flags - optional GPIO initialization flags
+ */
+int gpiod_hog(struct gpio_desc *desc, const char *name,
+             unsigned long lflags, enum gpiod_flags dflags)
+{
+       struct gpio_chip *chip;
+       struct gpio_desc *local_desc;
+       int hwnum;
+       int status;
+
+       chip = gpiod_to_chip(desc);
+       hwnum = gpio_chip_hwgpio(desc);
+
+       local_desc = gpiochip_request_own_desc(chip, hwnum, name);
+       if (IS_ERR(local_desc)) {
+               pr_debug("requesting own GPIO %s failed\n", name);
+               return PTR_ERR(local_desc);
+       }
+
+       status = gpiod_configure_flags(desc, name, lflags, dflags);
+       if (status < 0) {
+               pr_debug("setup of GPIO %s failed\n", name);
+               gpiochip_free_own_desc(desc);
+               return status;
+       }
+
+       /* Mark GPIO as hogged so it can be identified and removed later */
+       set_bit(FLAG_IS_HOGGED, &desc->flags);
+
+       pr_info("GPIO line %d (%s) hogged as %s%s\n",
+               desc_to_gpio(desc), name,
+               (dflags&GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input",
+               (dflags&GPIOD_FLAGS_BIT_DIR_OUT) ?
+                 (dflags&GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low":"");
+
+       return 0;
+}
+
+/**
+ * gpiochip_free_hogs - Scan gpio-controller chip and release GPIO hog
+ * @chip:      gpio chip to act on
+ *
+ * This is only used by of_gpiochip_remove to free hogged gpios
+ */
+static void gpiochip_free_hogs(struct gpio_chip *chip)
+{
+       int id;
+
+       for (id = 0; id < chip->ngpio; id++) {
+               if (test_bit(FLAG_IS_HOGGED, &chip->desc[id].flags))
+                       gpiochip_free_own_desc(&chip->desc[id]);
+       }
+}
+
+/**
+ * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function
+ * @dev:       GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id:    function within the GPIO consumer
+ * @flags:     optional GPIO initialization flags
+ *
+ * This function acquires all the GPIOs defined under a given function.
+ *
+ * Return a struct gpio_descs containing an array of descriptors, -ENOENT if
+ * no GPIO has been assigned to the requested function, or another IS_ERR()
+ * code if an error occurred while trying to acquire the GPIOs.
+ */
+struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
+                                               const char *con_id,
+                                               enum gpiod_flags flags)
+{
+       struct gpio_desc *desc;
+       struct gpio_descs *descs;
+       int count;
+
+       count = gpiod_count(dev, con_id);
+       if (count < 0)
+               return ERR_PTR(count);
+
+       descs = kzalloc(sizeof(*descs) + sizeof(descs->desc[0]) * count,
+                       GFP_KERNEL);
+       if (!descs)
+               return ERR_PTR(-ENOMEM);
+
+       for (descs->ndescs = 0; descs->ndescs < count; ) {
+               desc = gpiod_get_index(dev, con_id, descs->ndescs, flags);
+               if (IS_ERR(desc)) {
+                       gpiod_put_array(descs);
+                       return ERR_CAST(desc);
+               }
+               descs->desc[descs->ndescs] = desc;
+               descs->ndescs++;
+       }
+       return descs;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array);
+
+/**
+ * gpiod_get_array_optional - obtain multiple GPIOs from a multi-index GPIO
+ *                            function
+ * @dev:       GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id:    function within the GPIO consumer
+ * @flags:     optional GPIO initialization flags
+ *
+ * This is equivalent to gpiod_get_array(), except that when no GPIO was
+ * assigned to the requested function it will return NULL.
+ */
+struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev,
+                                                       const char *con_id,
+                                                       enum gpiod_flags flags)
+{
+       struct gpio_descs *descs;
+
+       descs = gpiod_get_array(dev, con_id, flags);
+       if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT))
+               return NULL;
+
+       return descs;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array_optional);
+
 /**
  * gpiod_put - dispose of a GPIO descriptor
  * @desc:      GPIO descriptor to dispose of
@@ -2017,6 +2233,21 @@ void gpiod_put(struct gpio_desc *desc)
 }
 EXPORT_SYMBOL_GPL(gpiod_put);
 
+/**
+ * gpiod_put_array - dispose of multiple GPIO descriptors
+ * @descs:     struct gpio_descs containing an array of descriptors
+ */
+void gpiod_put_array(struct gpio_descs *descs)
+{
+       unsigned int i;
+
+       for (i = 0; i < descs->ndescs; i++)
+               gpiod_put(descs->desc[i]);
+
+       kfree(descs);
+}
+EXPORT_SYMBOL_GPL(gpiod_put_array);
+
 #ifdef CONFIG_DEBUG_FS
 
 static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)