]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
gpio: shared: handle pins shared by child nodes of devices
authorBartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Wed, 18 Mar 2026 14:00:54 +0000 (15:00 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Mon, 23 Mar 2026 08:54:24 +0000 (09:54 +0100)
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>
drivers/gpio/gpiolib-shared.c
drivers/gpio/gpiolib-shared.h
drivers/gpio/gpiolib.c

index 3a8db9bf456daaf021d3c691677a90fc6da15889..e257212fa5e3df249de0d06eebdb2165ae734ebc 100644 (file)
@@ -443,8 +443,8 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
 }
 #endif /* CONFIG_RESET_GPIO */
 
-int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
-                                unsigned long lflags)
+int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle *fwnode,
+                                const char *con_id, unsigned long lflags)
 {
        const char *dev_id = dev_name(consumer);
        struct gpiod_lookup_table *lookup;
@@ -458,7 +458,7 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
                        if (!ref->fwnode && device_is_compatible(consumer, "reset-gpio")) {
                                if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
                                        continue;
-                       } else if (!device_match_fwnode(consumer, ref->fwnode)) {
+                       } else if (fwnode != ref->fwnode) {
                                continue;
                        }
 
index e11e260e1f590c46c5e575d3bb8f3b5a2240892d..15e72a8dcdb138f19ce000a33d3f53cb8f140bce 100644 (file)
 struct gpio_device;
 struct gpio_desc;
 struct device;
+struct fwnode_handle;
 
 #if IS_ENABLED(CONFIG_GPIO_SHARED)
 
 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);
+int gpio_shared_add_proxy_lookup(struct device *consumer,
+                                struct fwnode_handle *fwnode,
+                                const char *con_id, unsigned long lflags);
 
 #else
 
@@ -29,6 +31,7 @@ static inline int gpiochip_setup_shared(struct gpio_chip *gc)
 static inline void gpio_device_teardown_shared(struct gpio_device *gdev) { }
 
 static inline int gpio_shared_add_proxy_lookup(struct device *consumer,
+                                              struct fwnode_handle *fwnode,
                                               const char *con_id,
                                               unsigned long lflags)
 {
index d82fcf3fb458637447363e0871954bc47cf136fe..300de30fd92021bed2b20263f2585d00a5ee78b4 100644 (file)
@@ -4714,8 +4714,8 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer,
                         * lookup table for the proxy device as previously
                         * we only knew the consumer's fwnode.
                         */
-                       ret = gpio_shared_add_proxy_lookup(consumer, con_id,
-                                                          lookupflags);
+                       ret = gpio_shared_add_proxy_lookup(consumer, fwnode,
+                                                          con_id, lookupflags);
                        if (ret)
                                return ERR_PTR(ret);