diff options
| author | Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com> | 2026-03-18 15:00:53 +0100 |
|---|---|---|
| committer | Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com> | 2026-03-23 09:54:24 +0100 |
| commit | 710abda58055ed5eaa8958107633cc12a365c328 (patch) | |
| tree | 9e33d548834d3336c55ade7efe1f34efc892cca0 /drivers | |
| parent | 09c8ef6236004601b930965dfed432ac0e683b7e (diff) | |
gpio: shared: call gpio_chip::of_xlate() if set
OF-based GPIO controller drivers may provide a translation function that
calculates the real chip offset from whatever devicetree sources
provide. We need to take this into account in the shared GPIO management
and call of_xlate() if it's provided and adjust the entry->offset we
initially set when scanning the tree.
To that end: modify the shared GPIO API to take the GPIO chip as
argument on setup (to avoid having to rcu_dereference() it from the GPIO
device) and protect the access to entry->offset with the existing lock.
Fixes: a060b8c511ab ("gpiolib: implement low-level, shared GPIO support")
Reported-by: Jon Hunter <jonathanh@nvidia.com>
Closes: https://lore.kernel.org/all/921ba8ce-b18e-4a99-966d-c763d22081e2@nvidia.com/
Reviewed-by: Linus Walleij <linusw@kernel.org>
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Link: https://patch.msgid.link/20260318-gpio-shared-xlate-v2-1-0ce34c707e81@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpio/gpiolib-shared.c | 27 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib-shared.h | 4 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib.c | 2 |
3 files changed, 29 insertions, 4 deletions
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 17a7128b6bd9..3a8db9bf456d 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -506,8 +506,9 @@ static void gpio_shared_remove_adev(struct auxiliary_device *adev) auxiliary_device_uninit(adev); } -int gpio_device_setup_shared(struct gpio_device *gdev) +int gpiochip_setup_shared(struct gpio_chip *gc) { + struct gpio_device *gdev = gc->gpiodev; struct gpio_shared_entry *entry; struct gpio_shared_ref *ref; struct gpio_desc *desc; @@ -532,12 +533,34 @@ int gpio_device_setup_shared(struct gpio_device *gdev) * exposing shared pins. Find them and create the proxy devices. */ list_for_each_entry(entry, &gpio_shared_list, list) { + guard(mutex)(&entry->lock); + if (!device_match_fwnode(&gdev->dev, entry->fwnode)) continue; if (list_count_nodes(&entry->refs) <= 1) continue; +#if IS_ENABLED(CONFIG_OF) + if (is_of_node(entry->fwnode) && gc->of_xlate) { + /* + * This is the earliest that we can tranlate the + * devicetree offset to the chip offset. + */ + struct of_phandle_args gpiospec = { }; + + gpiospec.np = to_of_node(entry->fwnode); + gpiospec.args_count = 2; + gpiospec.args[0] = entry->offset; + + ret = gc->of_xlate(gc, &gpiospec, NULL); + if (ret < 0) + return ret; + + entry->offset = ret; + } +#endif /* CONFIG_OF */ + desc = &gdev->descs[entry->offset]; __set_bit(GPIOD_FLAG_SHARED, &desc->flags); @@ -575,6 +598,8 @@ void gpio_device_teardown_shared(struct gpio_device *gdev) struct gpio_shared_ref *ref; list_for_each_entry(entry, &gpio_shared_list, list) { + guard(mutex)(&entry->lock); + if (!device_match_fwnode(&gdev->dev, entry->fwnode)) continue; diff --git a/drivers/gpio/gpiolib-shared.h b/drivers/gpio/gpiolib-shared.h index 40568ef7364c..e11e260e1f59 100644 --- a/drivers/gpio/gpiolib-shared.h +++ b/drivers/gpio/gpiolib-shared.h @@ -14,14 +14,14 @@ struct device; #if IS_ENABLED(CONFIG_GPIO_SHARED) -int gpio_device_setup_shared(struct gpio_device *gdev); +int gpiochip_setup_shared(struct gpio_chip *gc); void gpio_device_teardown_shared(struct gpio_device *gdev); int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, unsigned long lflags); #else -static inline int gpio_device_setup_shared(struct gpio_device *gdev) +static inline int gpiochip_setup_shared(struct gpio_chip *gc) { return 0; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f52d2d3efac4..d82fcf3fb458 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1211,7 +1211,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, if (ret) goto err_remove_irqchip_mask; - ret = gpio_device_setup_shared(gdev); + ret = gpiochip_setup_shared(gc); if (ret) goto err_remove_irqchip; |
