[PATCH 4/5] GPIO ACPI: Add support to map GPIO resources to ranges

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add a function to gpiolib to facilitate registering a pin controller for
a range of GPIO pins, but using ACPI resource references and without
claiming the GPIO resource.

Signed-off-by: chengwei <larry.lai@xxxxxxxxxxxxxxx>
---
 drivers/gpio/gpiolib-acpi.c | 88 ++++++++++++++++++++++++++++++-------
 1 file changed, 71 insertions(+), 17 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 9be1376f9a62..d25c6cb610e3 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -1385,6 +1385,32 @@ static int acpi_find_gpio_count(struct acpi_resource *ares, void *data)
 	return 1;
 }
 
+static int acpi_gpio_count_from_property(struct acpi_device *adev,
+					 const char *propname)
+{
+	const struct acpi_gpio_mapping *gm;
+	const union acpi_object *obj;
+	int count = -ENOENT;
+	int ret;
+
+	ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+				    &obj);
+	if (ret == 0) {
+		if (obj->type == ACPI_TYPE_LOCAL_REFERENCE)
+			count = 1;
+		else if (obj->type == ACPI_TYPE_PACKAGE)
+			count = acpi_gpio_package_count(obj);
+	} else if (adev->driver_gpios) {
+		for (gm = adev->driver_gpios; gm->name; gm++)
+			if (strcmp(propname, gm->name) == 0) {
+				count = gm->size;
+				break;
+			}
+	}
+
+	return count;
+}
+
 /**
  * acpi_gpio_count - count the GPIOs associated with a device / function
  * @dev:	GPIO consumer, can be %NULL for system-global GPIOs
@@ -1397,10 +1423,7 @@ static int acpi_find_gpio_count(struct acpi_resource *ares, void *data)
 int acpi_gpio_count(struct device *dev, const char *con_id)
 {
 	struct acpi_device *adev = ACPI_COMPANION(dev);
-	const union acpi_object *obj;
-	const struct acpi_gpio_mapping *gm;
 	int count = -ENOENT;
-	int ret;
 	char propname[32];
 	unsigned int i;
 
@@ -1413,20 +1436,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
 			snprintf(propname, sizeof(propname), "%s",
 				 gpio_suffixes[i]);
 
-		ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
-					    &obj);
-		if (ret == 0) {
-			if (obj->type == ACPI_TYPE_LOCAL_REFERENCE)
-				count = 1;
-			else if (obj->type == ACPI_TYPE_PACKAGE)
-				count = acpi_gpio_package_count(obj);
-		} else if (adev->driver_gpios) {
-			for (gm = adev->driver_gpios; gm->name; gm++)
-				if (strcmp(propname, gm->name) == 0) {
-					count = gm->size;
-					break;
-				}
-		}
+		count = acpi_gpio_count_from_property(adev, propname);
 		if (count > 0)
 			break;
 	}
@@ -1449,6 +1459,50 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
 	return count ? count : -ENOENT;
 }
 
+/**
+ * acpi_node_add_pin_mapping - add a pin mapping for named GPIO resources
+ * @fwnode: pointer to an ACPI firmware node to get the GPIO information from
+ * @propname: Property name of the GPIO
+ * @pinctrl_name: the dev_name() of the pin controller to map to
+ * @pin_offset: the start offset in the pin controller number space
+ * @npins: the maximum number of pins from the offset of each pin space (GPIO
+ *         and pin controller) to map
+ *
+ * Lookup the GPIO resources and map them individually to the specified pins.
+ */
+int acpi_node_add_pin_mapping(struct fwnode_handle *fwnode,
+			      const char *propname,
+			      const char *pinctl_name,
+			      unsigned int pin_offset,
+			      unsigned int npins)
+{
+	struct acpi_device *adev = to_acpi_device_node(fwnode);
+	int count, i;
+
+	count = acpi_gpio_count_from_property(adev, propname);
+	if (count < 0)
+		return count;
+
+	for (i = 0; i < count && i < npins; i++) {
+		struct gpio_desc *desc;
+		int ret;
+
+		desc = acpi_node_get_gpiod(fwnode, propname, i, NULL);
+		if (IS_ERR(desc))
+			return PTR_ERR(desc);
+
+		/* The GPIOs may not be contiguous, so add them 1-by-1 */
+		ret = gpiochip_add_pin_range(gpiod_to_chip(desc), pinctl_name,
+					     gpio_chip_hwgpio(desc),
+					     pin_offset + i, 1);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_node_add_pin_mapping);
+
 /* Run deferred acpi_gpiochip_request_irqs() */
 static int __init acpi_gpio_handle_deferred_request_irqs(void)
 {
-- 
2.17.1




[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux