From 6f7194a10bdba1588357342c6daaaeef98e0004f Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 21 Oct 2016 17:21:29 +0300 Subject: ACPI / gpio: Allow holes in list of GPIOs for a device Make it possible to have an empty GPIOs in a GPIO list for device. For example a SPI master may use both GPIOs and native pins as chip selects and we need to be able to distinguish between the two. This makes it mandatory to have exactly 3 arguments for GPIOs and then converts gpiolib to use of __acpi_node_get_property_reference() instead. In addition we make acpi_gpio_package_count() to handle holes as well (this matches the DT version). Signed-off-by: Mika Westerberg Acked-by: Rafael J. Wysocki Signed-off-by: Linus Walleij --- Documentation/acpi/gpio-properties.txt | 15 +++++++++++++++ drivers/gpio/gpiolib-acpi.c | 32 +++++++++++++++++++++----------- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/Documentation/acpi/gpio-properties.txt b/Documentation/acpi/gpio-properties.txt index 5aafe0b351a1..09cff657b82c 100644 --- a/Documentation/acpi/gpio-properties.txt +++ b/Documentation/acpi/gpio-properties.txt @@ -51,6 +51,21 @@ it to 1 marks the GPIO as active low. In our Bluetooth example the "reset-gpios" refers to the second GpioIo() resource, second pin in that resource with the GPIO number of 31. +It is possible to leave holes in the array of GPIOs. This is useful in +cases like with SPI host controllers where some chip selects may be +implemented as GPIOs and some as native signals. For example a SPI host +controller can have chip selects 0 and 2 implemented as GPIOs and 1 as +native: + + Package () { + "cs-gpios", + Package () { + ^GPIO, 19, 0, 0, // chip select 0: GPIO + 0, // chip select 1: native signal + ^GPIO, 20, 0, 0, // chip select 2: GPIO + } + } + ACPI GPIO Mappings Provided by Drivers -------------------------------------- diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 58ece201b8e6..700ea6ad609b 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -468,7 +468,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, int ret; memset(&args, 0, sizeof(args)); - ret = acpi_node_get_property_reference(fwnode, propname, index, &args); + ret = __acpi_node_get_property_reference(fwnode, propname, index, 3, + &args); if (ret) { struct acpi_device *adev = to_acpi_device_node(fwnode); @@ -483,13 +484,13 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, * on returned args. */ lookup->adev = args.adev; - if (args.nargs >= 2) { - lookup->index = args.args[0]; - lookup->pin_index = args.args[1]; - /* 3rd argument, if present is used to specify active_low. */ - if (args.nargs >= 3) - lookup->active_low = !!args.args[2]; - } + if (args.nargs != 3) + return -EPROTO; + + lookup->index = args.args[0]; + lookup->pin_index = args.args[1]; + lookup->active_low = !!args.args[2]; + return 0; } @@ -915,18 +916,27 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) kfree(acpi_gpio); } -static unsigned int acpi_gpio_package_count(const union acpi_object *obj) +static int acpi_gpio_package_count(const union acpi_object *obj) { const union acpi_object *element = obj->package.elements; const union acpi_object *end = element + obj->package.count; unsigned int count = 0; while (element < end) { - if (element->type == ACPI_TYPE_LOCAL_REFERENCE) + switch (element->type) { + case ACPI_TYPE_LOCAL_REFERENCE: + element += 3; + /* Fallthrough */ + case ACPI_TYPE_INTEGER: + element++; count++; + break; - element++; + default: + return -EPROTO; + } } + return count; } -- cgit v1.2.3-58-ga151