diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 16a7b6816744..7ab7bc3c9300 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -922,3 +922,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id) } return count; } + +struct acpi_crs_lookup { + struct list_head node; + struct acpi_device *adev; + const char *con_id; +}; + +static DEFINE_MUTEX(acpi_crs_lookup_lock); +static LIST_HEAD(acpi_crs_lookup_list); + +bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id) +{ + struct acpi_crs_lookup *l, *lookup = NULL; + + /* Never allow fallback if the device has properties */ + if (adev->data.properties || adev->driver_gpios) + return false; + + mutex_lock(&acpi_crs_lookup_lock); + + list_for_each_entry(l, &acpi_crs_lookup_list, node) { + if (l->adev == adev) { + lookup = l; + break; + } + } + + if (!lookup) { + lookup = kmalloc(sizeof(*lookup), GFP_KERNEL); + if (lookup) { + lookup->adev = adev; + lookup->con_id = con_id; + list_add_tail(&lookup->node, &acpi_crs_lookup_list); + } + } + + mutex_unlock(&acpi_crs_lookup_lock); + + return lookup && + ((!lookup->con_id && !con_id) || + (lookup->con_id && con_id && + strcmp(lookup->con_id, con_id) == 0)); +} diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a18f00fc1bb8..3ca6c9f4391e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1868,6 +1868,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, /* Then from plain _CRS GPIOs */ if (IS_ERR(desc)) { + if (!acpi_can_fallback_to_crs(adev, con_id)) + return ERR_PTR(-ENOENT); + desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); if (IS_ERR(desc)) return desc; diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 98ab08c0aa2d..2b87cbd68478 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -47,6 +47,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, struct acpi_gpio_info *info); int acpi_gpio_count(struct device *dev, const char *con_id); + +bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id); #else static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } @@ -73,6 +75,12 @@ static inline int acpi_gpio_count(struct device *dev, const char *con_id) { return -ENODEV; } + +static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev, + const char *con_id) +{ + return false; +} #endif struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,