summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>2026-05-04 12:58:57 +0200
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>2026-05-08 20:16:58 +0300
commit1448c2d2ca5cc7f4ea6694e6bc809946de0a751c (patch)
tree3224230a12546aa5a5376c7a60844e5822ec426b
parent083a59e05db9203c346e87d822c0c12a0f7a7c85 (diff)
platform/x86: x86-android-tablets: enable fwnode matching of GPIO chips
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>
-rw-r--r--drivers/platform/x86/x86-android-tablets/core.c64
1 files changed, 61 insertions, 3 deletions
diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c
index 021009e9085b..5db794d65eb5 100644
--- a/drivers/platform/x86/x86-android-tablets/core.c
+++ b/drivers/platform/x86/x86-android-tablets/core.c
@@ -11,8 +11,10 @@
#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) {