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

Sebastian Reichel <[email protected]>
Newsgroups org.kernel.vger.linux-m68k,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm
Message-ID <aiGseFwWJkjCZrfB@venus>
Hi,

On Tue, Jun 02, 2026 at 11:21:22AM +0200, Jean-Michel Hautbois wrote:
> 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 <[email protected]>
> ---
>  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 <[email protected]>
> +L:	[email protected]
> +S:	Maintained
> +F:	drivers/power/reset/mcf-rcm-reset.c
> +
>  FREESCALE DIU FRAMEBUFFER DRIVER
>  M:	Timur Tabi <[email protected]>
>  L:	[email protected]
> 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

If you describe the register layout in the driver, you
could add "|| COMPILE_TEST" resulting in much better
test coverage.

> +	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 <[email protected]>
> + */
> +
> +#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 const struct platform_device_id mcf_rcm_id[] = {
    { "mcf-rcm-reset", 0, },
    { }
};
MODULE_DEVICE_TABLE(platform, mcf_rcm_id);

> +static struct platform_driver mcf_rcm_driver = {
> +	.probe = mcf_rcm_probe,
> +	.driver = {
> +		.name = "mcf-rcm-reset",
> +		.dev_groups = mcf_rcm_groups,
> +	},

.id_table = mcf_rcm_id,

> +};
> +module_platform_driver(mcf_rcm_driver);
> +
> +MODULE_AUTHOR("Jean-Michel Hautbois <[email protected]>");
> +MODULE_DESCRIPTION("Freescale ColdFire RCM power-on reason driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:mcf-rcm-reset");

You can drop the MODULE_ALIAS with the platform ID table being
done properly.

Otherwise LGTM.

-- Sebastian
signature.asc (application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAmohr2gACgkQ2O7X88g7
+prA3xAAhtx7s9ZMrDvndLLu4dNHrOT72Dd8tdogegErykWXaQIf7Q83yb78wLG/
kjXnJqnmzS8Fv25syQPWIgQbxfzQzr4Y4wCMo0FFSGfN0fAezhokxJ1H/rxJ53h3
ZpiRaTGfwae4rfm/xaKaFabZoj2mSJYN4aZKQrqmg/3+73p8QZsWyInQViI0/Gah
eQ3c6i0oX3bkePnyx2wVMSUxLAifTxJG2/tj2q87D1QAcgnQm9xXiyd6A+uqxGIs
m6V9Xa6m5eIbSk6gD8LE9dHhGa2gpjeZpIjaMLKJhwqkQpWWUrplgOlSZRqc0xcl
ssFbSWvkUNJepZlD54z4pvHTvQLw2l3gtUjObzYSZEkaP0mPq/c+s3VFCl/DmnNX
evrH3hGaZUc7TJnk+6SDiyuk6sT7YbAsygcZKxeK783evgC+ZKy5TIlJ+NWAGTMu
g/KcvecrUEtINz7VJEtYwMqIZHCMb8wAzqcTd8KhWj4KlEqR9FiIVSGmBPVJ/L63
0a9AfnOgGWK0DpVzs0J2wFRo3EP0J3OXx1QQsZ8SkhigmGY0sxbeme8dHhpbjGPQ
wxrXKLUggFtaXze0qAApT+mtKOXwfTi6n5oNOikPOAlIUrYDqEyQ6Z7Z6+QuKcAJ
QkyqUKAmrSdGHfjfbLDvs/ck8mC2PjthApW+bR5gFxP10y1sElY=
=Eg/S
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.