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

Message ID 20221019022450.16851-5-larry.lai@yunjingtech.com
State New
Headers
Series Add support control UP board CPLD/FPGA pin control |

Commit Message

chengwei Oct. 19, 2022, 2:24 a.m. UTC
  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@yunjingtech.com>
---
 drivers/gpio/gpiolib-acpi.c | 88 ++++++++++++++++++++++++++++++-------
 1 file changed, 71 insertions(+), 17 deletions(-)
  

Comments

Andy Shevchenko Oct. 19, 2022, 1:36 p.m. UTC | #1
On Wed, Oct 19, 2022 at 10:24:49AM +0800, chengwei wrote:
> 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.

This is quite under explained.

First of all, why do you need all these?

Second, where is the link to ACPI DSDT excerpt of the device node
which needs that?

Third, is the BIOS for these platforms is already in wild or
can be amended?

...

> +		count = acpi_gpio_count_from_property(adev, propname);
>  		if (count > 0)
>  			break;

This part can be split to a separate change as a prerequisite.
  

Patch

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)
 {