aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2014-10-21 13:33:59 +0200
committerMihai Serban <mihai.serban@intel.com>2016-01-07 17:55:00 +0200
commit9b4ea31bc0cac00a4de8e44f4847737c797083ce (patch)
treed50b3cbe02c3bf6aeeac5a49fc324a9528c60b00
parentdb55f76e98586ed4666f1be7d1689be3988946fc (diff)
downloadminnowboard-v3.14-9b4ea31bc0cac00a4de8e44f4847737c797083ce.tar.gz
BACKPORT: gpio: Support for unified device properties interface
Some drivers need to deal with only firmware representation of its GPIOs. An example would be a GPIO button array driver where each button is described as a separate firmware node in device tree. Typically these child nodes do not have physical representation in the Linux device model. In order to help device drivers to handle such firmware child nodes we add dev[m]_get_named_gpiod_from_child() that takes a child firmware node pointer as its second argument (the first one is the parent device itself), finds the GPIO using whatever is the underlying firmware method, and requests the GPIO properly. Change-Id: I128f9012b8b95f356cc0767ebcd30ae4bca5224d Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Acked-by: Alexandre Courbot <acourbot@nvidia.com> Acked-by: Grant Likely <grant.likely@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Robert Dolca <robert.dolca@intel.com>
-rw-r--r--drivers/gpio/devres.c32
-rw-r--r--drivers/gpio/gpiolib.c55
-rw-r--r--include/linux/gpio/consumer.h7
3 files changed, 94 insertions, 0 deletions
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 307464fd015..3581bac4931 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -86,6 +86,38 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
}
EXPORT_SYMBOL(devm_gpiod_get_index);
+ /**
+ * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node
+ * @dev: GPIO consumer
+ * @child: firmware node (child of @dev)
+ *
+ * GPIO descriptors returned from this function are automatically disposed on
+ * driver detach.
+ */
+struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
+ struct fwnode_handle *child)
+{
+ struct gpio_desc **dr;
+ struct gpio_desc *desc;
+
+ dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
+ GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ desc = fwnode_get_named_gpiod(child, "gpios");
+ if (IS_ERR(desc)) {
+ devres_free(dr);
+ return desc;
+ }
+
+ *dr = desc;
+ devres_add(dev, dr);
+
+ return desc;
+}
+EXPORT_SYMBOL(devm_get_gpiod_from_child);
+
/**
* devm_gpiod_put - Resource-managed gpiod_put()
* @desc: GPIO descriptor to dispose of
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 3a5e6c8b87b..8196e1a4b8e 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2578,6 +2578,61 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
EXPORT_SYMBOL_GPL(gpiod_get_index);
/**
+ * 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
+ *
+ * This function can be used for drivers that get their configuration
+ * from firmware.
+ *
+ * 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.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname)
+{
+ struct gpio_desc *desc = ERR_PTR(-ENODEV);
+ bool active_low = 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(of_node(fwnode), propname, 0,
+ &flags);
+ if (!IS_ERR(desc))
+ active_low = flags & OF_GPIO_ACTIVE_LOW;
+ } else if (is_acpi_node(fwnode)) {
+ struct acpi_gpio_info info;
+
+ desc = acpi_get_gpiod_by_index(acpi_node(fwnode), propname, 0,
+ &info);
+ if (!IS_ERR(desc))
+ active_low = info.active_low;
+ }
+
+ if (IS_ERR(desc))
+ return desc;
+
+ ret = gpiod_request(desc, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Only value flag can be set from both DT and ACPI is active_low */
+ if (active_low)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
+
+/**
* gpiod_put - dispose of a GPIO descriptor
* @desc: GPIO descriptor to dispose of
*
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index f6a9cc36bfd..845bd2b3c1f 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -59,6 +59,13 @@ int gpiod_to_irq(const struct gpio_desc *desc);
struct gpio_desc *gpio_to_desc(unsigned gpio);
int desc_to_gpio(const struct gpio_desc *desc);
+/* Child properties interface */
+struct fwnode_handle;
+
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname);
+struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
+ struct fwnode_handle *child);
#else /* CONFIG_GPIOLIB */
static inline struct gpio_desc *__must_check gpiod_get(struct device *dev,