Skip to content

Commit 710abda

Browse files
author
Bartosz Golaszewski
committed
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: a060b8c ("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>
1 parent 09c8ef6 commit 710abda

3 files changed

Lines changed: 29 additions & 4 deletions

File tree

drivers/gpio/gpiolib-shared.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,8 +506,9 @@ static void gpio_shared_remove_adev(struct auxiliary_device *adev)
506506
auxiliary_device_uninit(adev);
507507
}
508508

509-
int gpio_device_setup_shared(struct gpio_device *gdev)
509+
int gpiochip_setup_shared(struct gpio_chip *gc)
510510
{
511+
struct gpio_device *gdev = gc->gpiodev;
511512
struct gpio_shared_entry *entry;
512513
struct gpio_shared_ref *ref;
513514
struct gpio_desc *desc;
@@ -532,12 +533,34 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
532533
* exposing shared pins. Find them and create the proxy devices.
533534
*/
534535
list_for_each_entry(entry, &gpio_shared_list, list) {
536+
guard(mutex)(&entry->lock);
537+
535538
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
536539
continue;
537540

538541
if (list_count_nodes(&entry->refs) <= 1)
539542
continue;
540543

544+
#if IS_ENABLED(CONFIG_OF)
545+
if (is_of_node(entry->fwnode) && gc->of_xlate) {
546+
/*
547+
* This is the earliest that we can tranlate the
548+
* devicetree offset to the chip offset.
549+
*/
550+
struct of_phandle_args gpiospec = { };
551+
552+
gpiospec.np = to_of_node(entry->fwnode);
553+
gpiospec.args_count = 2;
554+
gpiospec.args[0] = entry->offset;
555+
556+
ret = gc->of_xlate(gc, &gpiospec, NULL);
557+
if (ret < 0)
558+
return ret;
559+
560+
entry->offset = ret;
561+
}
562+
#endif /* CONFIG_OF */
563+
541564
desc = &gdev->descs[entry->offset];
542565

543566
__set_bit(GPIOD_FLAG_SHARED, &desc->flags);
@@ -575,6 +598,8 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
575598
struct gpio_shared_ref *ref;
576599

577600
list_for_each_entry(entry, &gpio_shared_list, list) {
601+
guard(mutex)(&entry->lock);
602+
578603
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
579604
continue;
580605

drivers/gpio/gpiolib-shared.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ struct device;
1414

1515
#if IS_ENABLED(CONFIG_GPIO_SHARED)
1616

17-
int gpio_device_setup_shared(struct gpio_device *gdev);
17+
int gpiochip_setup_shared(struct gpio_chip *gc);
1818
void gpio_device_teardown_shared(struct gpio_device *gdev);
1919
int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
2020
unsigned long lflags);
2121

2222
#else
2323

24-
static inline int gpio_device_setup_shared(struct gpio_device *gdev)
24+
static inline int gpiochip_setup_shared(struct gpio_chip *gc)
2525
{
2626
return 0;
2727
}

drivers/gpio/gpiolib.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1211,7 +1211,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
12111211
if (ret)
12121212
goto err_remove_irqchip_mask;
12131213

1214-
ret = gpio_device_setup_shared(gdev);
1214+
ret = gpiochip_setup_shared(gc);
12151215
if (ret)
12161216
goto err_remove_irqchip;
12171217

0 commit comments

Comments
 (0)