Sometimes a GPIO needs to be taken from a node without
a device associated with it. The fwnode accessor does this,
let's however break out the DT code for now.

Signed-off-by: Linus Walleij <[email protected]>
---
 drivers/gpio/gpiolib.c | 117 +++++++++++++++++++++++++++++++++++--------------
 1 file changed, 83 insertions(+), 34 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index aad84a6306c4..294c255e6227 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3629,18 +3629,83 @@ struct gpio_desc *__must_check gpiod_get_index(struct 
device *dev,
 }
 EXPORT_SYMBOL_GPL(gpiod_get_index);
 
+/**
+ * gpiod_get_from_of_node() - obtain a GPIO from an OF node
+ * @node:      handle of the OF node
+ * @propname:  name of the DT 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
+ *
+ * Returns:
+ * On successful request the GPIO pin is configured in accordance with
+ * provided @dflags. If the node does not have the requested GPIO
+ * property, NULL is returned.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+static struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
+                                               const char *propname, int index,
+                                               enum gpiod_flags dflags,
+                                               const char *label)
+{
+       struct gpio_desc *desc = ERR_PTR(-ENODEV);
+       unsigned long lflags = 0;
+       enum of_gpio_flags flags;
+       bool active_low = false;
+       bool single_ended = false;
+       bool open_drain = false;
+       int ret;
+
+       desc = of_get_named_gpiod_flags(node, propname,
+                                       index, &flags);
+
+       if (!desc || IS_ERR(desc)) {
+               /* If it is not there, just return NULL */
+               if (PTR_ERR(desc) == -ENOENT)
+                       return NULL;
+               return desc;
+       }
+
+       active_low = flags & OF_GPIO_ACTIVE_LOW;
+       single_ended = flags & OF_GPIO_SINGLE_ENDED;
+       open_drain = flags & OF_GPIO_OPEN_DRAIN;
+
+       ret = gpiod_request(desc, label);
+       if (ret)
+               return ERR_PTR(ret);
+
+       if (active_low)
+               lflags |= GPIO_ACTIVE_LOW;
+
+       if (single_ended) {
+               if (open_drain)
+                       lflags |= GPIO_OPEN_DRAIN;
+               else
+                       lflags |= GPIO_OPEN_SOURCE;
+       }
+
+       ret = gpiod_configure_flags(desc, propname, lflags, dflags);
+       if (ret < 0) {
+               gpiod_put(desc);
+               return ERR_PTR(ret);
+       }
+
+       return desc;
+}
+
 /**
  * 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 in the consumer
+ * @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 firmware.
+ * from opaque firmware.
  *
- * Function properly finds the corresponding GPIO using whatever is the
+ * 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.
  *
@@ -3657,53 +3722,37 @@ struct gpio_desc *fwnode_get_named_gpiod(struct 
fwnode_handle *fwnode,
 {
        struct gpio_desc *desc = ERR_PTR(-ENODEV);
        unsigned long lflags = 0;
-       bool active_low = false;
-       bool single_ended = false;
-       bool open_drain = false;
        int ret;
 
        if (!fwnode)
                return ERR_PTR(-EINVAL);
 
        if (is_of_node(fwnode)) {
-               enum of_gpio_flags flags;
-
-               desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname,
-                                               index, &flags);
-               if (!IS_ERR(desc)) {
-                       active_low = flags & OF_GPIO_ACTIVE_LOW;
-                       single_ended = flags & OF_GPIO_SINGLE_ENDED;
-                       open_drain = flags & OF_GPIO_OPEN_DRAIN;
-               }
+               desc = gpiod_get_from_of_node(to_of_node(fwnode),
+                                             propname, index,
+                                             dflags,
+                                             label);
+               return desc;
        } else if (is_acpi_node(fwnode)) {
                struct acpi_gpio_info info;
 
                desc = acpi_node_get_gpiod(fwnode, propname, index, &info);
-               if (!IS_ERR(desc)) {
-                       active_low = info.polarity == GPIO_ACTIVE_LOW;
-                       ret = acpi_gpio_update_gpiod_flags(&dflags, info.flags);
-                       if (ret)
-                               pr_debug("Override GPIO initialization 
flags\n");
-               }
-       }
+               if (IS_ERR(desc))
+                       return desc;
 
-       if (IS_ERR(desc))
-               return desc;
+               ret = acpi_gpio_update_gpiod_flags(&dflags, info.flags);
+               if (ret)
+                       pr_debug("Override GPIO initialization flags\n");
 
+               if (info.polarity == GPIO_ACTIVE_LOW)
+                       lflags |= GPIO_ACTIVE_LOW;
+       }
+
+       /* Currently only ACPI takes this path */
        ret = gpiod_request(desc, label);
        if (ret)
                return ERR_PTR(ret);
 
-       if (active_low)
-               lflags |= GPIO_ACTIVE_LOW;
-
-       if (single_ended) {
-               if (open_drain)
-                       lflags |= GPIO_OPEN_DRAIN;
-               else
-                       lflags |= GPIO_OPEN_SOURCE;
-       }
-
        ret = gpiod_configure_flags(desc, propname, lflags, dflags);
        if (ret < 0) {
                gpiod_put(desc);
-- 
2.14.3

Reply via email to