Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: shared: propagate configuration to pinctrl

Just toggling the descriptor's "requested" flag is not enough. We need
to properly request it in order to potentially propagate any
configuration to pinctrl via the .request() callback.

We must not take the reference to the device at this point (the device
is not ready but we're also requesting the device's own descriptor) so
make the _commit() variants of request and free functions available to
GPIO core in order to use them instead of their regular counterparts.

This fixes an audio issue reported on one of the Qualcomm platforms.

Fixes: a060b8c511ab ("gpiolib: implement low-level, shared GPIO support")
Reviewed-by: Linus Walleij <linusw@kernel.org>
Tested-by: Ravi Hothi <ravi.hothi@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260120154913.61991-1-bartosz.golaszewski@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

+15 -7
+11 -5
drivers/gpio/gpiolib-shared.c
··· 515 515 { 516 516 struct gpio_shared_entry *entry; 517 517 struct gpio_shared_ref *ref; 518 - unsigned long *flags; 518 + struct gpio_desc *desc; 519 519 int ret; 520 520 521 521 list_for_each_entry(entry, &gpio_shared_list, list) { ··· 543 543 if (list_count_nodes(&entry->refs) <= 1) 544 544 continue; 545 545 546 - flags = &gdev->descs[entry->offset].flags; 546 + desc = &gdev->descs[entry->offset]; 547 547 548 - __set_bit(GPIOD_FLAG_SHARED, flags); 548 + __set_bit(GPIOD_FLAG_SHARED, &desc->flags); 549 549 /* 550 550 * Shared GPIOs are not requested via the normal path. Make 551 551 * them inaccessible to anyone even before we register the 552 552 * chip. 553 553 */ 554 - __set_bit(GPIOD_FLAG_REQUESTED, flags); 554 + ret = gpiod_request_commit(desc, "shared"); 555 + if (ret) 556 + return ret; 555 557 556 558 pr_debug("GPIO %u owned by %s is shared by multiple consumers\n", 557 559 entry->offset, gpio_device_get_label(gdev)); ··· 564 562 ref->con_id ?: "(none)"); 565 563 566 564 ret = gpio_shared_make_adev(gdev, entry, ref); 567 - if (ret) 565 + if (ret) { 566 + gpiod_free_commit(desc); 568 567 return ret; 568 + } 569 569 } 570 570 } 571 571 ··· 582 578 list_for_each_entry(entry, &gpio_shared_list, list) { 583 579 if (!device_match_fwnode(&gdev->dev, entry->fwnode)) 584 580 continue; 581 + 582 + gpiod_free_commit(&gdev->descs[entry->offset]); 585 583 586 584 list_for_each_entry(ref, &entry->refs, list) { 587 585 guard(mutex)(&ref->lock);
+2 -2
drivers/gpio/gpiolib.c
··· 2453 2453 * on each other, and help provide better diagnostics in debugfs. 2454 2454 * They're called even less than the "set direction" calls. 2455 2455 */ 2456 - static int gpiod_request_commit(struct gpio_desc *desc, const char *label) 2456 + int gpiod_request_commit(struct gpio_desc *desc, const char *label) 2457 2457 { 2458 2458 unsigned int offset; 2459 2459 int ret; ··· 2515 2515 return ret; 2516 2516 } 2517 2517 2518 - static void gpiod_free_commit(struct gpio_desc *desc) 2518 + void gpiod_free_commit(struct gpio_desc *desc) 2519 2519 { 2520 2520 unsigned long flags; 2521 2521
+2
drivers/gpio/gpiolib.h
··· 244 244 struct gpio_desc *desc) 245 245 246 246 int gpiod_request(struct gpio_desc *desc, const char *label); 247 + int gpiod_request_commit(struct gpio_desc *desc, const char *label); 247 248 void gpiod_free(struct gpio_desc *desc); 249 + void gpiod_free_commit(struct gpio_desc *desc); 248 250 249 251 static inline int gpiod_request_user(struct gpio_desc *desc, const char *label) 250 252 {