summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-05-21 21:32:02 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2024-05-21 21:32:02 +0300
commit3b1440380d5dd5d779db7a271b772d5c28bab0ee (patch)
treefc5f831c3b482a0c07806ca0c0537d045ea85f64
parentb9dd56e813af002f45f6a494414d4a05dfdaa30e (diff)
parentadbc49a5a8c6fcf7be154c2e30213bbf472940da (diff)
downloadlinux-3b1440380d5dd5d779db7a271b772d5c28bab0ee.tar.xz
Merge tag 'intel-gpio-v6.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel
Pull intel-gpio fixes from Andy Shevchenko: - NULL pointer dereference fix in GPIO APCI library - Restore ACPI handle matching for GPIO devices represented in banks * tag 'intel-gpio-v6.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel: gpiolib: acpi: Fix failed in acpi_gpiochip_find() by adding parent node match gpiolib: acpi: Move ACPI device NULL check to acpi_can_fallback_to_crs()
-rw-r--r--drivers/gpio/gpiolib-acpi.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 553a5f94c00a..bb063b81cee6 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -128,7 +128,24 @@ static bool acpi_gpio_deferred_req_irqs_done;
static int acpi_gpiochip_find(struct gpio_chip *gc, const void *data)
{
- return device_match_acpi_handle(&gc->gpiodev->dev, data);
+ /* First check the actual GPIO device */
+ if (device_match_acpi_handle(&gc->gpiodev->dev, data))
+ return true;
+
+ /*
+ * When the ACPI device is artificially split to the banks of GPIOs,
+ * where each of them is represented by a separate GPIO device,
+ * the firmware node of the physical device may not be shared among
+ * the banks as they may require different values for the same property,
+ * e.g., number of GPIOs in a certain bank. In such case the ACPI handle
+ * of a GPIO device is NULL and can not be used. Hence we have to check
+ * the parent device to be sure that there is no match before bailing
+ * out.
+ */
+ if (gc->parent)
+ return device_match_acpi_handle(gc->parent, data);
+
+ return false;
}
/**
@@ -938,6 +955,10 @@ static struct gpio_desc *acpi_get_gpiod_from_data(struct fwnode_handle *fwnode,
static bool acpi_can_fallback_to_crs(struct acpi_device *adev,
const char *con_id)
{
+ /* If there is no ACPI device, there is no _CRS to fall back to */
+ if (!adev)
+ return false;
+
/* Never allow fallback if the device has properties */
if (acpi_dev_has_props(adev) || adev->driver_gpios)
return false;
@@ -978,10 +999,10 @@ __acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id, unsigned int
}
/* Then from plain _CRS GPIOs */
- if (!adev || !can_fallback)
- return ERR_PTR(-ENOENT);
+ if (can_fallback)
+ return acpi_get_gpiod_by_index(adev, NULL, idx, info);
- return acpi_get_gpiod_by_index(adev, NULL, idx, info);
+ return ERR_PTR(-ENOENT);
}
struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,