[PATCH 5/6] gpiolib: consolidate GPIO lookups

Dmitry Torokhov
2022-11-04T06:11:08Z

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.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/gpio/gpiolib-acpi.c | 39 ---------
drivers/gpio/gpiolib-acpi.h | 10 ---
drivers/gpio/gpiolib-of.c | 45 ----------
drivers/gpio/gpiolib-of.h | 12 ---
drivers/gpio/gpiolib.c | 206 +++++++++++++++++---------------------------
5 files changed, 80 insertions(+), 232 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 1bc386032ca8..bed0380c5136 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -1024,45 +1024,6 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
return desc;
}

-/**
- * 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
diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h
index 8880615327ac..9475f99a9694 100644
--- a/drivers/gpio/gpiolib-acpi.h
+++ b/drivers/gpio/gpiolib-acpi.h
@@ -36,10 +36,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
@@ -61,12 +57,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;
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 607bf4358ff7..7508628b9f6e 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -390,51 +390,6 @@ static unsigned long of_convert_gpio_flags(enum of_gpio_flags flags)
return lflags;
}

-/**
- * 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.
- *
- * In case of error an ERR_PTR() is returned.
- */
-struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
- const char *propname, int index,
- enum gpiod_flags dflags,
- const char *label)
-{
- unsigned long lflags;
- struct gpio_desc *desc;
- enum of_gpio_flags of_flags;
- int ret;
-
- desc = of_get_named_gpiod_flags(node, propname, index, &of_flags);
- if (!desc || IS_ERR(desc))
- return desc;
-
- ret = gpiod_request(desc, label);
- if (ret == -EBUSY && (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
- return desc;
- if (ret)
- return ERR_PTR(ret);
-
- lflags = of_convert_gpio_flags(of_flags);
-
- ret = gpiod_configure_flags(desc, propname, lflags, dflags);
- if (ret < 0) {
- gpiod_put(desc);
- return ERR_PTR(ret);
- }
-
- return desc;
-}
-
static struct gpio_desc *of_find_gpio_rename(struct device_node *np,
const char *con_id,
unsigned int idx,
diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h
index c44be0f285f3..16c0848c9a25 100644
--- a/drivers/gpio/gpiolib-of.h
+++ b/drivers/gpio/gpiolib-of.h
@@ -26,10 +26,6 @@ void of_gpiochip_remove(struct gpio_chip *gc);
int of_gpio_get_count(struct device *dev, const char *con_id);
bool of_gpio_need_valid_mask(const struct gpio_chip *gc);
void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
-struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
- const char *propname, int index,
- enum gpiod_flags dflags,
- const char *label);
#else
static inline struct gpio_desc *of_find_gpio(struct device_node *np,
const char *con_id,
@@ -52,14 +48,6 @@ static inline void of_gpio_dev_init(struct gpio_chip *gc,
struct gpio_device *gdev)
{
}
-static inline
-struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
- const char *propname, int index,
- enum gpiod_flags dflags,
- const char *label)
-{
- return ERR_PTR(-ENOSYS);
-}
#endif /* CONFIG_OF_GPIO */

extern struct notifier_block gpio_of_notifier;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f0a7a59ac630..79aaba693c4f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3801,58 +3801,87 @@ 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);

+ dev_dbg(consumer, "GPIO lookup for consumer %s in node '%s'\n",
+ con_id, fwnode_get_name(fwnode));
+
+ /* Using device tree? */
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 device tree for GPIO lookup\n");
+ 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 for GPIO lookup\n");
+ 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 (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);
}
@@ -3885,29 +3914,14 @@ 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);

@@ -4061,72 +4075,12 @@ 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);

--
b4 0.11.0-dev-28747