drivers: gpio: Add a managed API to get a GPIO from the device-tree
authorJean-Jacques Hiblot <jjhiblot@ti.com>
Fri, 11 Sep 2020 08:13:34 +0000 (13:43 +0530)
committerTom Rini <trini@konsulko.com>
Wed, 30 Sep 2020 15:55:22 +0000 (11:55 -0400)
Add managed functions to get a gpio from the devce-tree, based on a
property name (minus the '-gpios' suffix) and optionally an index.

When the device is unbound, the GPIO is automatically released and the
data structure is freed.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
drivers/gpio/gpio-uclass.c
include/asm-generic/gpio.h

index 9c53299..0c01413 100644 (file)
@@ -6,6 +6,8 @@
 #include <common.h>
 #include <dm.h>
 #include <log.h>
+#include <dm/devres.h>
+#include <dm/device_compat.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
 #include <dm/uclass-internal.h>
@@ -1209,6 +1211,75 @@ int gpio_dev_request_index(struct udevice *dev, const char *nodename,
                                 flags, 0, dev);
 }
 
+static void devm_gpiod_release(struct udevice *dev, void *res)
+{
+       dm_gpio_free(dev, res);
+}
+
+static int devm_gpiod_match(struct udevice *dev, void *res, void *data)
+{
+       return res == data;
+}
+
+struct gpio_desc *devm_gpiod_get_index(struct udevice *dev, const char *id,
+                                      unsigned int index, int flags)
+{
+       int rc;
+       struct gpio_desc *desc;
+       char *propname;
+       static const char suffix[] = "-gpios";
+
+       propname = malloc(strlen(id) + sizeof(suffix));
+       if (!propname) {
+               rc = -ENOMEM;
+               goto end;
+       }
+
+       strcpy(propname, id);
+       strcat(propname, suffix);
+
+       desc = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc),
+                           __GFP_ZERO);
+       if (unlikely(!desc)) {
+               rc = -ENOMEM;
+               goto end;
+       }
+
+       rc = gpio_request_by_name(dev, propname, index, desc, flags);
+
+end:
+       if (propname)
+               free(propname);
+
+       if (rc)
+               return ERR_PTR(rc);
+
+       devres_add(dev, desc);
+
+       return desc;
+}
+
+struct gpio_desc *devm_gpiod_get_index_optional(struct udevice *dev,
+                                               const char *id,
+                                               unsigned int index,
+                                               int flags)
+{
+       struct gpio_desc *desc = devm_gpiod_get_index(dev, id, index, flags);
+
+       if (IS_ERR(desc))
+               return NULL;
+
+       return desc;
+}
+
+void devm_gpiod_put(struct udevice *dev, struct gpio_desc *desc)
+{
+       int rc;
+
+       rc = devres_release(dev, devm_gpiod_release, devm_gpiod_match, desc);
+       WARN_ON(rc);
+}
+
 static int gpio_post_bind(struct udevice *dev)
 {
        struct udevice *child;
index a57dd26..3ae1894 100644 (file)
@@ -701,4 +701,51 @@ int gpio_get_number(const struct gpio_desc *desc);
  */
 int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio);
 
+/**
+ * devm_gpiod_get_index - Resource-managed gpiod_get()
+ * @dev:       GPIO consumer
+ * @con_id:    function within the GPIO consumer
+ * @index:     index of the GPIO to obtain in the consumer
+ * @flags:     optional GPIO initialization flags
+ *
+ * Managed gpiod_get(). GPIO descriptors returned from this function are
+ * automatically disposed on device unbind.
+ * Return the GPIO descriptor corresponding to the function con_id of device
+ * dev, -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 GPIO.
+ */
+struct gpio_desc *devm_gpiod_get_index(struct udevice *dev, const char *id,
+                                      unsigned int index, int flags);
+
+#define devm_gpiod_get(dev, id, flags) devm_gpiod_get_index(dev, id, 0, flags)
+/**
+ * gpiod_get_optional - obtain an optional GPIO for a given GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @index:     index of the GPIO to obtain in the consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This is equivalent to devm_gpiod_get(), except that when no GPIO was
+ * assigned to the requested function it will return NULL. This is convenient
+ * for drivers that need to handle optional GPIOs.
+ */
+struct gpio_desc *devm_gpiod_get_index_optional(struct udevice *dev,
+                                               const char *id,
+                                               unsigned int index,
+                                               int flags);
+
+#define devm_gpiod_get_optional(dev, id, flags) \
+       devm_gpiod_get_index_optional(dev, id, 0, flags)
+
+/**
+ * devm_gpiod_put - Resource-managed gpiod_put()
+ * @dev:       GPIO consumer
+ * @desc:      GPIO descriptor to dispose of
+ *
+ * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or
+ * devm_gpiod_get_index(). Normally this function will not be called as the GPIO
+ * will be disposed of by the resource management code.
+ */
+void devm_gpiod_put(struct udevice *dev, struct gpio_desc *desc);
+
 #endif /* _ASM_GENERIC_GPIO_H_ */