diff --git a/src/acpi/device.c b/src/acpi/device.c index 450427d47c..5de31b7776 100644 --- a/src/acpi/device.c +++ b/src/acpi/device.c @@ -1019,33 +1019,72 @@ struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name, return dp_array; } +struct acpi_dp *acpi_dp_add_gpio_array(struct acpi_dp *dp, const char *name, + const struct acpi_gpio_res_params *params, + size_t param_count) +{ + struct acpi_dp *gpio; + uint32_t i; + + if (!dp || !param_count) + return NULL; + + gpio = acpi_dp_new_table(name); + if (!gpio) + return NULL; + + /* + * Generate ACPI identifiers as follows: + * Package () { + * name, // e.g. cs-gpios + * Package() { + * ref, index, pin, active_low, // GPIO-0 (params[0]) + * ref, index, pin, active_low, // GPIO-1 (params[1]) + * ... + * } + * } + */ + for (i = 0; i < param_count; i++, params++) { + /* + * If refs is NULL, leave a hole in the gpio array. This can be used in + * conditions where some controllers use both GPIOs and native signals. + */ + if (!params->ref) { + acpi_dp_add_integer(gpio, NULL, 0); + continue; + } + + /* The device that has _CRS containing GpioIO()/GpioInt() */ + acpi_dp_add_reference(gpio, NULL, params->ref); + + /* Index of the GPIO resource in _CRS starting from zero */ + acpi_dp_add_integer(gpio, NULL, params->index); + + /* Pin in the GPIO resource, typically zero */ + acpi_dp_add_integer(gpio, NULL, params->pin); + + /* Set if pin is active low */ + acpi_dp_add_integer(gpio, NULL, params->active_low); + } + acpi_dp_add_array(dp, gpio); + + return gpio; + +} + + struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name, const char *ref, int index, int pin, int active_low) { - if (!dp) - return NULL; + struct acpi_gpio_res_params param = { + .ref = ref, + .index = index, + .pin = pin, + .active_low = active_low, + }; - struct acpi_dp *gpio = acpi_dp_new_table(name); - - if (!gpio) - return NULL; - - /* The device that has _CRS containing GpioIO()/GpioInt() */ - acpi_dp_add_reference(gpio, NULL, ref); - - /* Index of the GPIO resource in _CRS starting from zero */ - acpi_dp_add_integer(gpio, NULL, index); - - /* Pin in the GPIO resource, typically zero */ - acpi_dp_add_integer(gpio, NULL, pin); - - /* Set if pin is active low */ - acpi_dp_add_integer(gpio, NULL, active_low); - - acpi_dp_add_array(dp, gpio); - - return gpio; + return acpi_dp_add_gpio_array(dp, name, ¶m, 1); } /* diff --git a/src/include/acpi/acpi_device.h b/src/include/acpi/acpi_device.h index be13bd7ec8..301f9b0156 100644 --- a/src/include/acpi/acpi_device.h +++ b/src/include/acpi/acpi_device.h @@ -545,6 +545,22 @@ struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name, const char *ref, int index, int pin, int active_low); +struct acpi_gpio_res_params { + /* Reference to the parent device. */ + const char *ref; + /* Index to the GpioIo resource within the _CRS. */ + int index; + /* Index to the pin within the GpioIo resource, usually 0. */ + int pin; + /* Flag to indicate if pin is active low. */ + int active_low; +}; + +/* Add a GPIO binding device property for array of GPIOs */ +struct acpi_dp *acpi_dp_add_gpio_array(struct acpi_dp *dp, const char *name, + const struct acpi_gpio_res_params *params, + size_t param_count); + /* Add a child table of Device Properties */ struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name, struct acpi_dp *child);