[PATCH 1/4] MIPS: alchemy: mtx1: attach software nodes to GPIO chips
From: Dmitry Torokhov
Date: Tue Mar 10 2026 - 02:13:04 EST
GPIO subsystem is switching the way it locates GPIO chip instances for
GPIO references in software nodes from matching on node names to
identity matching, which necessitates assigning firmware nodes
(software nodes) to GPIO chips.
Move the node definitions for alchemy-gpio1 and alchemy-gpio2 to
arch/misp/alchemy/common/gpiolib.c, register them there, and attach
them to gpio_chip instances. Adjust MTX1 board file to use these nodes.
Note that because nodes need to be registered before they can be used in
PROPERTY_ENTRY_GPIO() we have to do the registration at
postcore_initcall level, otherwise (due to the link order) MTX1 board
initialization code will run first.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>
---
arch/mips/alchemy/board-mtx1.c | 79 +++++++++++--------------
arch/mips/alchemy/common/gpiolib.c | 39 +++++++++++-
arch/mips/include/asm/mach-au1x00/gpio-au1000.h | 4 ++
3 files changed, 75 insertions(+), 47 deletions(-)
diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c
index cb6be58808a0..740b38c0b81e 100644
--- a/arch/mips/alchemy/board-mtx1.c
+++ b/arch/mips/alchemy/board-mtx1.c
@@ -9,6 +9,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
#include <linux/input.h>
@@ -78,27 +79,22 @@ void __init board_setup(void)
/******************************************************************************/
-static const struct software_node mtx1_gpiochip_node = {
- .name = "alchemy-gpio2",
-};
-
static const struct software_node mtx1_gpio_keys_node = {
.name = "mtx1-gpio-keys",
};
-static const struct property_entry mtx1_button_props[] = {
- PROPERTY_ENTRY_U32("linux,code", BTN_0),
- PROPERTY_ENTRY_GPIO("gpios", &mtx1_gpiochip_node, 7, GPIO_ACTIVE_HIGH),
- PROPERTY_ENTRY_STRING("label", "System button"),
- { }
-};
-
static const struct software_node mtx1_button_node = {
.parent = &mtx1_gpio_keys_node,
- .properties = mtx1_button_props,
+ .properties = (const struct property_entry[]){
+ PROPERTY_ENTRY_U32("linux,code", BTN_0),
+ PROPERTY_ENTRY_GPIO("gpios", &alchemy_gpio2_node, 7,
+ GPIO_ACTIVE_HIGH),
+ PROPERTY_ENTRY_STRING("label", "System button"),
+ { }
+ },
};
-static const struct software_node *mtx1_gpio_keys_swnodes[] __initconst = {
+static const struct software_node * const mtx1_gpio_keys_swnodes[] __initconst = {
&mtx1_gpio_keys_node,
&mtx1_button_node,
NULL
@@ -127,16 +123,15 @@ static void __init mtx1_keys_init(void)
pr_err("failed to create gpio-keys device: %d\n", err);
}
-/* Global number 215 is offset 15 on Alchemy GPIO 2 */
-static const struct property_entry mtx1_wdt_props[] = {
- PROPERTY_ENTRY_GPIO("gpios", &mtx1_gpiochip_node, 15, GPIO_ACTIVE_HIGH),
- { }
-};
-
-static struct platform_device_info mtx1_wdt_info __initconst = {
+static const struct platform_device_info mtx1_wdt_info __initconst = {
.name = "mtx1-wdt",
.id = 0,
- .properties = mtx1_wdt_props,
+ .properties = (const struct property_entry[]){
+ /* Global number 215 is offset 15 on Alchemy GPIO 2 */
+ PROPERTY_ENTRY_GPIO("gpios", &alchemy_gpio2_node, 15,
+ GPIO_ACTIVE_HIGH),
+ { }
+ },
};
static void __init mtx1_wdt_init(void)
@@ -147,36 +142,34 @@ static void __init mtx1_wdt_init(void)
pd = platform_device_register_full(&mtx1_wdt_info);
err = PTR_ERR_OR_ZERO(pd);
if (err)
- pr_err("failed to create gpio-keys device: %d\n", err);
+ pr_err("failed to create watchdog device: %d\n", err);
}
static const struct software_node mtx1_gpio_leds_node = {
.name = "mtx1-leds",
};
-static const struct property_entry mtx1_green_led_props[] = {
- PROPERTY_ENTRY_GPIO("gpios", &mtx1_gpiochip_node, 11, GPIO_ACTIVE_HIGH),
- { }
-};
-
static const struct software_node mtx1_green_led_node = {
.name = "mtx1:green",
.parent = &mtx1_gpio_leds_node,
- .properties = mtx1_green_led_props,
-};
-
-static const struct property_entry mtx1_red_led_props[] = {
- PROPERTY_ENTRY_GPIO("gpios", &mtx1_gpiochip_node, 12, GPIO_ACTIVE_HIGH),
- { }
+ .properties = (const struct property_entry[]){
+ PROPERTY_ENTRY_GPIO("gpios", &alchemy_gpio2_node, 11,
+ GPIO_ACTIVE_HIGH),
+ { }
+ },
};
static const struct software_node mtx1_red_led_node = {
.name = "mtx1:red",
.parent = &mtx1_gpio_leds_node,
- .properties = mtx1_red_led_props,
+ .properties = (const struct property_entry[]){
+ PROPERTY_ENTRY_GPIO("gpios", &alchemy_gpio2_node, 12,
+ GPIO_ACTIVE_HIGH),
+ { }
+ },
};
-static const struct software_node *mtx1_gpio_leds_swnodes[] = {
+static const struct software_node * const mtx1_gpio_leds_swnodes[] __initconst = {
&mtx1_gpio_leds_node,
&mtx1_green_led_node,
&mtx1_red_led_node,
@@ -185,10 +178,6 @@ static const struct software_node *mtx1_gpio_leds_swnodes[] = {
static void __init mtx1_leds_init(void)
{
- struct platform_device_info led_info = {
- .name = "leds-gpio",
- .id = PLATFORM_DEVID_NONE,
- };
struct platform_device *led_dev;
int err;
@@ -198,9 +187,11 @@ static void __init mtx1_leds_init(void)
return;
}
- led_info.fwnode = software_node_fwnode(&mtx1_gpio_leds_node);
-
- led_dev = platform_device_register_full(&led_info);
+ led_dev = platform_device_register_full(&(struct platform_device_info){
+ .name = "leds-gpio",
+ .id = PLATFORM_DEVID_NONE,
+ .fwnode = software_node_fwnode(&mtx1_gpio_leds_node),
+ });
err = PTR_ERR_OR_ZERO(led_dev);
if (err)
pr_err("failed to create LED device: %d\n", err);
@@ -335,10 +326,6 @@ static int __init mtx1_register_devices(void)
au1xxx_override_eth_cfg(0, &mtx1_au1000_eth0_pdata);
- rc = software_node_register(&mtx1_gpiochip_node);
- if (rc)
- return rc;
-
rc = platform_add_devices(mtx1_devs, ARRAY_SIZE(mtx1_devs));
if (rc)
return rc;
diff --git a/arch/mips/alchemy/common/gpiolib.c b/arch/mips/alchemy/common/gpiolib.c
index e79e26ffac99..2141eae5ce45 100644
--- a/arch/mips/alchemy/common/gpiolib.c
+++ b/arch/mips/alchemy/common/gpiolib.c
@@ -30,6 +30,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/property.h>
#include <linux/types.h>
#include <linux/gpio/driver.h>
#include <asm/mach-au1x00/gpio-au1000.h>
@@ -95,7 +96,21 @@ static int gpio1_to_irq(struct gpio_chip *chip, unsigned offset)
return alchemy_gpio1_to_irq(offset + ALCHEMY_GPIO1_BASE);
}
-struct gpio_chip alchemy_gpio_chip[] = {
+const struct software_node alchemy_gpio1_node = {
+ .name = "alchemy-gpio1",
+};
+
+const struct software_node alchemy_gpio2_node = {
+ .name = "alchemy-gpio2",
+};
+
+static const struct software_node *alchemy_gpio_node_group[] = {
+ &alchemy_gpio1_node,
+ &alchemy_gpio2_node,
+ NULL
+};
+
+static struct gpio_chip alchemy_gpio_chip[] = {
[0] = {
.label = "alchemy-gpio1",
.direction_input = gpio1_direction_input,
@@ -157,6 +172,28 @@ static struct gpio_chip au1300_gpiochip = {
.ngpio = AU1300_GPIO_NUM,
};
+/*
+ * Software nodes must be registered before board-specific code (that runs
+ * at arch_initcall level) attempts to use them as GPIO targets or as fwnodes
+ * for registered devices. We can not do registration in alchemy_gpiochip_init
+ * because it also runs as arch_initcall and runs after board-specific code
+ * because of the link order, and so we do it at postcore_initcall level.
+ */
+static int __init alchemy_gpio_nodes_init(void)
+{
+ int ret;
+
+ ret = software_node_register_node_group(alchemy_gpio_node_group);
+ if (ret)
+ return ret;
+
+ alchemy_gpio_chip[0].fwnode = software_node_fwnode(&alchemy_gpio1_node);
+ alchemy_gpio_chip[1].fwnode = software_node_fwnode(&alchemy_gpio2_node);
+
+ return 0;
+}
+postcore_initcall(alchemy_gpio_nodes_init);
+
static int __init alchemy_gpiochip_init(void)
{
int ret = 0;
diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
index d820b481ac56..a0eebc24c4a8 100644
--- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
@@ -41,6 +41,10 @@
#define AU1000_GPIO2_ENABLE 0x14
struct gpio;
+struct software_node;
+
+extern const struct software_node alchemy_gpio1_node;
+extern const struct software_node alchemy_gpio2_node;
static inline int au1000_gpio1_to_irq(int gpio)
{
--
2.53.0.473.g4a7958ca14-goog