[PATCH 2/3] power: reset: add MCF5441x RCM power-on reason driver

From: Jean-Michel Hautbois

Date: Tue Jun 02 2026 - 05:22:57 EST


Add a driver that decodes the Reset Status Register (RSR) of the
Freescale ColdFire MCF5441x Reset Controller Module at probe time
and exposes the cause via the power_on_reason sysfs ABI.

The RSR can latch several cause bits simultaneously (Reference
Manual chapter 12.3.2); the driver picks one cause per a priority
that favours the most explanatory diagnostic.

Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@xxxxxxxxxx>
---
MAINTAINERS | 6 ++
drivers/power/reset/Kconfig | 12 ++++
drivers/power/reset/Makefile | 1 +
drivers/power/reset/mcf-rcm-reset.c | 109 ++++++++++++++++++++++++++++++++++++
4 files changed, 128 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 461a3eed6129..1109bff23ec1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10195,6 +10195,12 @@ S: Maintained
F: drivers/mmc/host/sdhci-esdhc-mcf.c
F: include/linux/platform_data/mmc-esdhc-mcf.h

+FREESCALE COLDFIRE M5441X RCM POWER-ON REASON DRIVER
+M: Jean-Michel Hautbois <jeanmichel.hautbois@xxxxxxxxxx>
+L: linux-m68k@xxxxxxxxxxxxxxxxxxxx
+S: Maintained
+F: drivers/power/reset/mcf-rcm-reset.c
+
FREESCALE DIU FRAMEBUFFER DRIVER
M: Timur Tabi <timur@xxxxxxxxxx>
L: linux-fbdev@xxxxxxxxxxxxxxx
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 124afb99febe..003638f652fa 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -128,6 +128,18 @@ config POWER_RESET_LINKSTATION

Say Y here if you have a Buffalo LinkStation LS421D/E.

+config POWER_RESET_MCF_RCM
+ tristate "Freescale ColdFire RCM power-on reason driver"
+ depends on M5441x
+ depends on HAS_IOMEM
+ help
+ This driver exposes the cause of the last reset on Freescale
+ ColdFire 5441x SoCs through the standard power_on_reason sysfs
+ ABI. It reads the Reset Status Register (RSR) of the Reset
+ Controller Module once at probe time and reports a normalised
+ string (regular power-up, reset button action, software reset
+ or unknown reason).
+
config POWER_RESET_MACSMC
tristate "Apple SMC reset/power-off driver"
depends on MFD_MACSMC
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index d7ae97241a83..e31cab4ba78e 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
obj-$(CONFIG_POWER_RESET_LINKSTATION) += linkstation-poweroff.o
+obj-$(CONFIG_POWER_RESET_MCF_RCM) += mcf-rcm-reset.o
obj-$(CONFIG_POWER_RESET_MACSMC) += macsmc-reboot.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o
diff --git a/drivers/power/reset/mcf-rcm-reset.c b/drivers/power/reset/mcf-rcm-reset.c
new file mode 100644
index 000000000000..666ae1455be1
--- /dev/null
+++ b/drivers/power/reset/mcf-rcm-reset.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Freescale ColdFire MCF5441x RCM power-on reason driver
+ *
+ * Copyright (C) 2026 Jean-Michel Hautbois <jeanmichel.hautbois@xxxxxxxxxx>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power/power_on_reason.h>
+
+#include <asm/m5441xsim.h>
+
+#define MCF_RSR_KNOWN_CAUSES (MCF_RSR_POR | MCF_RSR_EXT | MCF_RSR_WDRCORE | \
+ MCF_RSR_LOC | MCF_RSR_LOL | MCF_RSR_SOFT)
+
+struct mcf_rcm {
+ const char *reason;
+};
+
+/*
+ * Decode RSR into a power_on_reason string.
+ *
+ * The MCF5441x Reset Status Register can latch several cause bits at the
+ * same time (Reference Manual chapter 12.3.2: "one or more status bits
+ * may be set at the same time"). A power-on, for example, also resets
+ * the PLL and may co-flag LOC and LOL during the boot sequence. The
+ * power_on_reason ABI carries a single string, so this routine picks
+ * one cause; the chosen priority surfaces the most explanatory one for
+ * diagnostics:
+ *
+ * POR cold boot dominates any spurious co-flagged cause
+ * EXT operator action via the RESET pin
+ * WDRCORE core watchdog timeout, a fault to investigate
+ * LOC, LOL PLL clock or lock failure, hardware fault
+ * SOFT explicit software-requested reset
+ */
+static const char *mcf_rcm_decode(u8 rsr)
+{
+ if (rsr & MCF_RSR_POR)
+ return POWER_ON_REASON_REGULAR;
+ if (rsr & MCF_RSR_EXT)
+ return POWER_ON_REASON_RST_BTN;
+ if (rsr & MCF_RSR_WDRCORE)
+ return POWER_ON_REASON_WATCHDOG;
+ if (rsr & (MCF_RSR_LOC | MCF_RSR_LOL))
+ return POWER_ON_REASON_CPU_CLK_FAIL;
+ if (rsr & MCF_RSR_SOFT)
+ return POWER_ON_REASON_SOFTWARE;
+ return POWER_ON_REASON_UNKNOWN;
+}
+
+static ssize_t power_on_reason_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mcf_rcm *rcm = platform_get_drvdata(to_platform_device(dev));
+
+ return sysfs_emit(buf, "%s\n", rcm->reason);
+}
+static DEVICE_ATTR_RO(power_on_reason);
+
+static struct attribute *mcf_rcm_attrs[] = {
+ &dev_attr_power_on_reason.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(mcf_rcm);
+
+static int mcf_rcm_probe(struct platform_device *pdev)
+{
+ struct mcf_rcm *rcm;
+ void __iomem *base;
+ u8 rsr;
+
+ rcm = devm_kzalloc(&pdev->dev, sizeof(*rcm), GFP_KERNEL);
+ if (!rcm)
+ return -ENOMEM;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rsr = readb_relaxed(base);
+ rcm->reason = mcf_rcm_decode(rsr);
+
+ platform_set_drvdata(pdev, rcm);
+
+ if (!(rsr & MCF_RSR_KNOWN_CAUSES))
+ dev_warn(&pdev->dev, "Unknown reset cause (RSR=0x%02x)\n", rsr);
+ else
+ dev_info(&pdev->dev, "Starting after %s (RSR=0x%02x)\n",
+ rcm->reason, rsr);
+
+ return 0;
+}
+
+static struct platform_driver mcf_rcm_driver = {
+ .probe = mcf_rcm_probe,
+ .driver = {
+ .name = "mcf-rcm-reset",
+ .dev_groups = mcf_rcm_groups,
+ },
+};
+module_platform_driver(mcf_rcm_driver);
+
+MODULE_AUTHOR("Jean-Michel Hautbois <jeanmichel.hautbois@xxxxxxxxxx>");
+MODULE_DESCRIPTION("Freescale ColdFire RCM power-on reason driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mcf-rcm-reset");

--
2.39.5