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>
This commit is contained in:
Bartosz Golaszewski 2026-05-04 12:58:57 +02:00 committed by Ilpo Järvinen
parent 083a59e05d
commit 1448c2d2ca
No known key found for this signature in database
GPG Key ID: 59AC4F6153E5CE31

View File

@ -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) {