Skip to content

Commit 10cf489

Browse files
dtorlinusw
authored andcommitted
gpiolib: tighten up ACPI legacy gpio lookups
We should not fall back to the legacy unnamed gpio lookup style if the driver requests gpios with different names, because we'll give out the same gpio twice. Let's keep track of the names that were used for the device and only do the fallback for the first name used. Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent 8005c49 commit 10cf489

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

drivers/gpio/gpiolib-acpi.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,3 +922,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
922922
}
923923
return count;
924924
}
925+
926+
struct acpi_crs_lookup {
927+
struct list_head node;
928+
struct acpi_device *adev;
929+
const char *con_id;
930+
};
931+
932+
static DEFINE_MUTEX(acpi_crs_lookup_lock);
933+
static LIST_HEAD(acpi_crs_lookup_list);
934+
935+
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
936+
{
937+
struct acpi_crs_lookup *l, *lookup = NULL;
938+
939+
/* Never allow fallback if the device has properties */
940+
if (adev->data.properties || adev->driver_gpios)
941+
return false;
942+
943+
mutex_lock(&acpi_crs_lookup_lock);
944+
945+
list_for_each_entry(l, &acpi_crs_lookup_list, node) {
946+
if (l->adev == adev) {
947+
lookup = l;
948+
break;
949+
}
950+
}
951+
952+
if (!lookup) {
953+
lookup = kmalloc(sizeof(*lookup), GFP_KERNEL);
954+
if (lookup) {
955+
lookup->adev = adev;
956+
lookup->con_id = con_id;
957+
list_add_tail(&lookup->node, &acpi_crs_lookup_list);
958+
}
959+
}
960+
961+
mutex_unlock(&acpi_crs_lookup_lock);
962+
963+
return lookup &&
964+
((!lookup->con_id && !con_id) ||
965+
(lookup->con_id && con_id &&
966+
strcmp(lookup->con_id, con_id) == 0));
967+
}

drivers/gpio/gpiolib.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,6 +1868,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
18681868

18691869
/* Then from plain _CRS GPIOs */
18701870
if (IS_ERR(desc)) {
1871+
if (!acpi_can_fallback_to_crs(adev, con_id))
1872+
return ERR_PTR(-ENOENT);
1873+
18711874
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
18721875
if (IS_ERR(desc))
18731876
return desc;

drivers/gpio/gpiolib.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
4747
struct acpi_gpio_info *info);
4848

4949
int acpi_gpio_count(struct device *dev, const char *con_id);
50+
51+
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
5052
#else
5153
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
5254
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)
7375
{
7476
return -ENODEV;
7577
}
78+
79+
static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
80+
const char *con_id)
81+
{
82+
return false;
83+
}
7684
#endif
7785

7886
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,

0 commit comments

Comments
 (0)