gpiolib: consolidate GPIO lookups
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 11 Nov 2022 22:19:07 +0000 (14:19 -0800)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Tue, 15 Nov 2022 10:21:30 +0000 (11:21 +0100)
Ensure that all paths to obtain/look up GPIOD from generic
consumer-visible APIs go through the new gpiod_find_and_request()
helper, so that we can easily extend it with support for new firmware
mechanisms.

The only exception is OF-specific [devm_]gpiod_get_from_of_node() API
that is still being used by a couple of drivers and will be removed as
soon as patches converting them to use generic fwnode/device APIs are
accepted.

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-acpi.h
drivers/gpio/gpiolib.c

index 1d69b70..c99c94e 100644 (file)
@@ -1025,45 +1025,6 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
 }
 
 /**
- * acpi_node_get_gpiod() - get a GPIO descriptor from ACPI resources
- * @fwnode: pointer to an ACPI firmware node to get the GPIO information from
- * @propname: Property name of the GPIO
- * @index: index of GpioIo/GpioInt resource (starting from %0)
- * @lflags: bitmask of gpio_lookup_flags GPIO_* values
- * @dflags: gpiod initialization flags
- *
- * If @fwnode is an ACPI device object, call acpi_get_gpiod_by_index() for it.
- * Otherwise (i.e. it is a data-only non-device object), use the property-based
- * GPIO lookup to get to the GPIO resource with the relevant information and use
- * that to obtain the GPIO descriptor to return.
- *
- * If the GPIO cannot be translated or there is an error an ERR_PTR is
- * returned.
- */
-struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
-                                     const char *propname, int index,
-                                     unsigned long *lflags,
-                                     enum gpiod_flags *dflags)
-{
-       struct acpi_gpio_info info;
-       struct acpi_device *adev;
-       struct gpio_desc *desc;
-
-       adev = to_acpi_device_node(fwnode);
-       if (adev)
-               desc = acpi_get_gpiod_by_index(adev, propname, index, &info);
-       else
-               desc = acpi_get_gpiod_from_data(fwnode, propname, index, &info);
-
-       if (!IS_ERR(desc)) {
-               acpi_gpio_update_gpiod_flags(dflags, &info);
-               acpi_gpio_update_gpiod_lookup_flags(lflags, &info);
-       }
-
-       return desc;
-}
-
-/**
  * acpi_dev_gpio_irq_wake_get_by() - Find GpioInt and translate it to Linux IRQ number
  * @adev: pointer to a ACPI device to get IRQ from
  * @name: optional name of GpioInt resource
index 42adaab..d2b5dab 100644 (file)
@@ -24,10 +24,6 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
                                 unsigned int idx,
                                 enum gpiod_flags *dflags,
                                 unsigned long *lookupflags);
-struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
-                                     const char *propname, int index,
-                                     unsigned long *lflags,
-                                     enum gpiod_flags *dflags);
 
 int acpi_gpio_count(struct device *dev, const char *con_id);
 #else
@@ -49,12 +45,6 @@ acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id,
 {
        return ERR_PTR(-ENOENT);
 }
-static inline struct gpio_desc *
-acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
-                   int index, unsigned long *lflags, enum gpiod_flags *dflags)
-{
-       return ERR_PTR(-ENXIO);
-}
 static inline int acpi_gpio_count(struct device *dev, const char *con_id)
 {
        return -ENODEV;
index b213f5f..7f73909 100644 (file)
@@ -366,7 +366,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
 static int devprop_gpiochip_set_names(struct gpio_chip *chip)
 {
        struct gpio_device *gdev = chip->gpiodev;
-       struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
+       const struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
        const char **names;
        int ret, i;
        int count;
@@ -3853,58 +3853,84 @@ static int platform_gpio_count(struct device *dev, const char *con_id)
        return count;
 }
 
-/**
- * fwnode_get_named_gpiod - obtain a GPIO from firmware node
- * @fwnode:    handle of the firmware node
- * @propname:  name of the firmware property representing the GPIO
- * @index:     index of the GPIO to obtain for the consumer
- * @dflags:    GPIO initialization flags
- * @label:     label to attach to the requested GPIO
- *
- * This function can be used for drivers that get their configuration
- * from opaque firmware.
- *
- * The function properly finds the corresponding GPIO using whatever is the
- * underlying firmware interface and then makes sure that the GPIO
- * descriptor is requested before it is returned to the caller.
- *
- * Returns:
- * On successful request the GPIO pin is configured in accordance with
- * provided @dflags.
- *
- * In case of error an ERR_PTR() is returned.
- */
-static struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
-                                               const char *propname, int index,
-                                               enum gpiod_flags dflags,
-                                               const char *label)
+static struct gpio_desc *gpiod_find_by_fwnode(struct fwnode_handle *fwnode,
+                                             struct device *consumer,
+                                             const char *con_id,
+                                             unsigned int idx,
+                                             enum gpiod_flags *flags,
+                                             unsigned long *lookupflags)
 {
-       unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
-       struct gpio_desc *desc = ERR_PTR(-ENODEV);
-       int ret;
+       struct gpio_desc *desc = ERR_PTR(-ENOENT);
 
        if (is_of_node(fwnode)) {
-               desc = gpiod_get_from_of_node(to_of_node(fwnode),
-                                             propname, index,
-                                             dflags,
-                                             label);
-               return desc;
+               dev_dbg(consumer, "using DT '%pfw' for '%s' GPIO lookup\n",
+                       fwnode, con_id);
+               desc = of_find_gpio(to_of_node(fwnode), con_id, idx, lookupflags);
        } else if (is_acpi_node(fwnode)) {
-               desc = acpi_node_get_gpiod(fwnode, propname, index,
-                                          &lflags, &dflags);
-               if (IS_ERR(desc))
-                       return desc;
-       } else {
-               return ERR_PTR(-EINVAL);
+               dev_dbg(consumer, "using ACPI '%pfw' for '%s' GPIO lookup\n",
+                       fwnode, con_id);
+               desc = acpi_find_gpio(fwnode, con_id, idx, flags, lookupflags);
        }
 
-       /* Currently only ACPI takes this path */
+       return desc;
+}
+
+static struct gpio_desc *gpiod_find_and_request(struct device *consumer,
+                                               struct fwnode_handle *fwnode,
+                                               const char *con_id,
+                                               unsigned int idx,
+                                               enum gpiod_flags flags,
+                                               const char *label,
+                                               bool platform_lookup_allowed)
+{
+       struct gpio_desc *desc = ERR_PTR(-ENOENT);
+       unsigned long lookupflags;
+       int ret;
+
+       if (!IS_ERR_OR_NULL(fwnode))
+               desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx,
+                                           &flags, &lookupflags);
+
+       if (gpiod_not_found(desc) && platform_lookup_allowed) {
+               /*
+                * Either we are not using DT or ACPI, or their lookup did not
+                * return a result. In that case, use platform lookup as a
+                * fallback.
+                */
+               dev_dbg(consumer, "using lookup tables for GPIO lookup\n");
+               desc = gpiod_find(consumer, con_id, idx, &lookupflags);
+       }
+
+       if (IS_ERR(desc)) {
+               dev_dbg(consumer, "No GPIO consumer %s found\n", con_id);
+               return desc;
+       }
+
+       /*
+        * If a connection label was passed use that, else attempt to use
+        * the device name as label
+        */
        ret = gpiod_request(desc, label);
-       if (ret)
-               return ERR_PTR(ret);
+       if (ret) {
+               if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
+                       return ERR_PTR(ret);
+
+               /*
+                * This happens when there are several consumers for
+                * the same GPIO line: we just return here without
+                * further initialization. It is a bit of a hack.
+                * This is necessary to support fixed regulators.
+                *
+                * FIXME: Make this more sane and safe.
+                */
+               dev_info(consumer,
+                        "nonexclusive access to GPIO for %s\n", con_id);
+               return desc;
+       }
 
-       ret = gpiod_configure_flags(desc, propname, lflags, dflags);
+       ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
        if (ret < 0) {
+               dev_dbg(consumer, "setup of GPIO %s failed\n", con_id);
                gpiod_put(desc);
                return ERR_PTR(ret);
        }
@@ -3937,29 +3963,12 @@ static struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
  * In case of error an ERR_PTR() is returned.
  */
 struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
-                                        const char *con_id, int index,
+                                        const char *con_id,
+                                        int index,
                                         enum gpiod_flags flags,
                                         const char *label)
 {
-       struct gpio_desc *desc;
-       char prop_name[32]; /* 32 is max size of property name */
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id)
-                       snprintf(prop_name, sizeof(prop_name), "%s-%s",
-                                           con_id, gpio_suffixes[i]);
-               else
-                       snprintf(prop_name, sizeof(prop_name), "%s",
-                                           gpio_suffixes[i]);
-
-               desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags,
-                                             label);
-               if (!gpiod_not_found(desc))
-                       break;
-       }
-
-       return desc;
+       return gpiod_find_and_request(NULL, fwnode, con_id, index, flags, label, false);
 }
 EXPORT_SYMBOL_GPL(fwnode_gpiod_get_index);
 
@@ -4113,72 +4122,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
                                               unsigned int idx,
                                               enum gpiod_flags flags)
 {
-       unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
-       struct gpio_desc *desc = NULL;
-       int ret;
-       /* Maybe we have a device name, maybe not */
-       const char *devname = dev ? dev_name(dev) : "?";
        struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
+       const char *devname = dev ? dev_name(dev) : "?";
+       const char *label = con_id ?: devname;
 
-       dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
-
-       /* Using device tree? */
-       if (is_of_node(fwnode)) {
-               dev_dbg(dev, "using device tree for GPIO lookup\n");
-               desc = of_find_gpio(to_of_node(fwnode),
-                                   con_id, idx, &lookupflags);
-       } else if (is_acpi_node(fwnode)) {
-               dev_dbg(dev, "using ACPI for GPIO lookup\n");
-               desc = acpi_find_gpio(fwnode,
-                                     con_id, idx, &flags, &lookupflags);
-       }
-
-       /*
-        * Either we are not using DT or ACPI, or their lookup did not return
-        * a result. In that case, use platform lookup as a fallback.
-        */
-       if (!desc || gpiod_not_found(desc)) {
-               dev_dbg(dev, "using lookup tables for GPIO lookup\n");
-               desc = gpiod_find(dev, con_id, idx, &lookupflags);
-       }
-
-       if (IS_ERR(desc)) {
-               dev_dbg(dev, "No GPIO consumer %s found\n", con_id);
-               return desc;
-       }
-
-       /*
-        * If a connection label was passed use that, else attempt to use
-        * the device name as label
-        */
-       ret = gpiod_request(desc, con_id ?: devname);
-       if (ret) {
-               if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
-                       return ERR_PTR(ret);
-
-               /*
-                * This happens when there are several consumers for
-                * the same GPIO line: we just return here without
-                * further initialization. It is a bit of a hack.
-                * This is necessary to support fixed regulators.
-                *
-                * FIXME: Make this more sane and safe.
-                */
-               dev_info(dev, "nonexclusive access to GPIO for %s\n", con_id ?: devname);
-               return desc;
-       }
-
-       ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
-       if (ret < 0) {
-               dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
-               gpiod_put(desc);
-               return ERR_PTR(ret);
-       }
-
-       blocking_notifier_call_chain(&desc->gdev->notifier,
-                                    GPIOLINE_CHANGED_REQUESTED, desc);
-
-       return desc;
+       return gpiod_find_and_request(dev, fwnode, con_id, idx, flags, label, true);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_index);