]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
platform/x86: x86-android-tablets: enable fwnode matching of GPIO chips
authorBartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Mon, 4 May 2026 10:58:57 +0000 (12:58 +0200)
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Fri, 8 May 2026 17:16:58 +0000 (20:16 +0300)
In order to allow GPIOLIB to match cherryview and baytrail GPIO
controllers by their firmware nodes instead of their names, we need to
attach the - currently "dangling" - existing software nodes to their
target devices dynamically.

The driver uses platform_create_bundle() and expects all required
providers to be present before it itself is probed. We know the name of
the device we're waiting for so look them up and assign the appropriate
software node as the secondary firmware node of the underlying ACPI node.

Scheduling fine-grained devres actions allows for proper teardown and
unsetting of the secondary firmware nodes.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://patch.msgid.link/20260504-baytrail-real-swnode-v5-2-c7878b69e383@oss.qualcomm.com
[ij: added linux/bug.h include]
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
drivers/platform/x86/x86-android-tablets/core.c

index 021009e9085bec3db9c4daa1f6235600210a6099..5db794d65eb5f704a16759ea8ff8a149e5ed1ac5 100644 (file)
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/acpi.h>
+#include <linux/bug.h>
 #include <linux/device.h>
 #include <linux/dmi.h>
+#include <linux/fwnode.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/machine.h>
 #include <linux/irq.h>
@@ -360,6 +362,61 @@ static const struct software_node *cherryview_gpiochip_node_group[] = {
        NULL
 };
 
+static void gpio_secondary_unset(void *data)
+{
+       struct device *dev = data;
+
+       set_secondary_fwnode(dev, NULL);
+}
+
+static void gpio_secondary_unregister_node_group(void *data)
+{
+       const struct software_node **nodes = data;
+
+       software_node_unregister_node_group(nodes);
+}
+
+static int gpio_secondary_fwnode_init(struct device *parent)
+{
+       const struct software_node *const *swnode;
+       struct fwnode_handle *fwnode;
+       int ret;
+
+       if (!gpiochip_node_group)
+               return 0;
+
+       ret = software_node_register_node_group(gpiochip_node_group);
+       if (ret)
+               return ret;
+
+       ret = devm_add_action_or_reset(parent,
+                                      gpio_secondary_unregister_node_group,
+                                      gpiochip_node_group);
+       if (ret)
+               return ret;
+
+       for (swnode = gpiochip_node_group; *swnode; swnode++) {
+               struct device *dev __free(put_device) =
+                               acpi_bus_find_device_by_name((*swnode)->name);
+               if (!dev)
+                       return dev_err_probe(parent,
+                                            -ENODEV, "Failed to find the required GPIO controller: %s\n",
+                                            (*swnode)->name);
+
+               fwnode = software_node_fwnode(*swnode);
+               if (WARN_ON(!fwnode))
+                       return -ENOENT;
+
+               set_secondary_fwnode(dev, fwnode);
+
+               ret = devm_add_action_or_reset(parent, gpio_secondary_unset, dev);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static void x86_android_tablet_remove(struct platform_device *pdev)
 {
        int i;
@@ -391,7 +448,6 @@ static void x86_android_tablet_remove(struct platform_device *pdev)
 
        software_node_unregister_node_group(gpio_button_swnodes);
        software_node_unregister_node_group(swnode_group);
-       software_node_unregister_node_group(gpiochip_node_group);
 }
 
 static __init int x86_android_tablet_probe(struct platform_device *pdev)
@@ -427,9 +483,11 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev)
                break;
        }
 
-       ret = software_node_register_node_group(gpiochip_node_group);
-       if (ret)
+       ret = gpio_secondary_fwnode_init(&pdev->dev);
+       if (ret) {
+               x86_android_tablet_remove(pdev);
                return ret;
+       }
 
        ret = software_node_register_node_group(dev_info->swnode_group);
        if (ret) {