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

gpio: shared: handle pins shared by child nodes of devices

Shared GPIOs may be assigned to child nodes of device nodes which don't
themselves bind to any struct device. We need to pass the firmware node
that is the actual consumer to gpiolib-shared and compare against it
instead of unconditionally using the fwnode of the consumer device.

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/
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Link: https://patch.msgid.link/20260318-gpio-shared-xlate-v2-2-0ce34c707e81@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

+10 -7
+3 -3
drivers/gpio/gpiolib-shared.c
··· 443 443 } 444 444 #endif /* CONFIG_RESET_GPIO */ 445 445 446 - int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, 447 - unsigned long lflags) 446 + int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle *fwnode, 447 + const char *con_id, unsigned long lflags) 448 448 { 449 449 const char *dev_id = dev_name(consumer); 450 450 struct gpiod_lookup_table *lookup; ··· 458 458 if (!ref->fwnode && device_is_compatible(consumer, "reset-gpio")) { 459 459 if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref)) 460 460 continue; 461 - } else if (!device_match_fwnode(consumer, ref->fwnode)) { 461 + } else if (fwnode != ref->fwnode) { 462 462 continue; 463 463 } 464 464
+5 -2
drivers/gpio/gpiolib-shared.h
··· 11 11 struct gpio_device; 12 12 struct gpio_desc; 13 13 struct device; 14 + struct fwnode_handle; 14 15 15 16 #if IS_ENABLED(CONFIG_GPIO_SHARED) 16 17 17 18 int gpiochip_setup_shared(struct gpio_chip *gc); 18 19 void gpio_device_teardown_shared(struct gpio_device *gdev); 19 - int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, 20 - unsigned long lflags); 20 + int gpio_shared_add_proxy_lookup(struct device *consumer, 21 + struct fwnode_handle *fwnode, 22 + const char *con_id, unsigned long lflags); 21 23 22 24 #else 23 25 ··· 31 29 static inline void gpio_device_teardown_shared(struct gpio_device *gdev) { } 32 30 33 31 static inline int gpio_shared_add_proxy_lookup(struct device *consumer, 32 + struct fwnode_handle *fwnode, 34 33 const char *con_id, 35 34 unsigned long lflags) 36 35 {
+2 -2
drivers/gpio/gpiolib.c
··· 4714 4714 * lookup table for the proxy device as previously 4715 4715 * we only knew the consumer's fwnode. 4716 4716 */ 4717 - ret = gpio_shared_add_proxy_lookup(consumer, con_id, 4718 - lookupflags); 4717 + ret = gpio_shared_add_proxy_lookup(consumer, fwnode, 4718 + con_id, lookupflags); 4719 4719 if (ret) 4720 4720 return ERR_PTR(ret); 4721 4721