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

chengwei
2022-10-19T02:27:11Z

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

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