The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v2 0/2] rtc: add a driver for the Freescale MCF5441x on-chip RTC
@ 2026-06-07  9:00 Jean-Michel Hautbois
  2026-06-07  9:00 ` [PATCH v2 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver Jean-Michel Hautbois
  2026-06-07  9:00 ` [PATCH v2 2/2] m68k: coldfire/m5441x: register the on-chip RTC Jean-Michel Hautbois
  0 siblings, 2 replies; 4+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-07  9:00 UTC (permalink / raw)
  To: Alexandre Belloni, Greg Ungerer, Geert Uytterhoeven
  Cc: linux-kernel, linux-rtc, linux-m68k, Jean-Michel Hautbois

This series adds support for the "robust" real time clock found on the
Freescale MCF5441x family of ColdFire SoCs.

Patch 1 adds the rtc-class driver. Besides the usual time/calendar and a
one-shot alarm, the block contains 2KB of battery-backed standby RAM that
survives a main-power loss while VSTBY_RTC is supplied; the driver exposes
it through the nvmem framework so userspace can persist data (for example a
reset/reboot counter) across power cycles. Register and standby-RAM writes
go through the RTC_CR[WE] knock sequence, the time counters are read under
the RTC_SR[INVAL] guard described in the reference manual, and the time/date
encoding is forced to binary at probe.

Patch 2 registers the platform device from the m5441x ColdFire SoC support
code so that every MCF5441x board gets the RTC. The MCFRTC_BASE, MCFRTC_SIZE
and MCF_IRQ_RTC definitions it relies on already exist in
arch/m68k/include/asm/m5441xsim.h.

The driver has been exercised on an MCF54418-based board: it registers
as an rtc device, exposes the standby RAM as an nvmem device, and a value
written to the standby RAM survives a mains power-cycle.

Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
Changes in v2:
- Patch 1: wait_valid() now uses read_poll_timeout_atomic() instead of an
  open-coded busy-wait. The atomic variant is required because it runs with
  p->lock held and interrupts off. (Geert Uytterhoeven)
- Patch 1: nvram_read()/nvram_write() use unsigned int rather than size_t
  for the chunk/index locals, and scoped_guard(spinlock_irqsave) instead of
  explicit spin_lock_irqsave()/spin_unlock_irqrestore(). (Geert Uytterhoeven)
- Link to v1: https://patch.msgid.link/20260602-jmh-upstream-coldfire-rtc-v1-0-1e129a177d2f@yoseli.org

---
Jean-Michel Hautbois (2):
      rtc: m5441x: add MCF5441x on-chip RTC driver
      m68k: coldfire/m5441x: register the on-chip RTC

 MAINTAINERS                 |   6 +
 arch/m68k/coldfire/m5441x.c |  29 +++
 drivers/rtc/Kconfig         |  12 +
 drivers/rtc/Makefile        |   1 +
 drivers/rtc/rtc-m5441x.c    | 579 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 627 insertions(+)
---
base-commit: 979c294509f9248fe1e7c358d582fb37dd5ca12d
change-id: 20260529-jmh-upstream-coldfire-rtc-88b095b2cf28

Best regards,
--  
Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver
  2026-06-07  9:00 [PATCH v2 0/2] rtc: add a driver for the Freescale MCF5441x on-chip RTC Jean-Michel Hautbois
@ 2026-06-07  9:00 ` Jean-Michel Hautbois
  2026-06-28 12:40   ` Alexandre Belloni
  2026-06-07  9:00 ` [PATCH v2 2/2] m68k: coldfire/m5441x: register the on-chip RTC Jean-Michel Hautbois
  1 sibling, 1 reply; 4+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-07  9:00 UTC (permalink / raw)
  To: Alexandre Belloni, Greg Ungerer, Geert Uytterhoeven
  Cc: linux-kernel, linux-rtc, linux-m68k, Jean-Michel Hautbois

Add an rtc-class driver for the Freescale MCF5441x on-chip "robust" RTC.
It provides the time/calendar and alarm, and exposes the 2KB
battery-backed standby RAM through the nvmem framework so userspace can
preserve data across a main-power loss (the RAM is retained while
VSTBY_RTC is supplied).

Register and standby-RAM writes go through the RTC_CR[WE] knock
sequence; the base-2112 year encoding and register map follow the
MCF54418 reference manual. Based on the out-of-tree Freescale 3.0.x
rtc-m5441x driver, rewritten for the current RTC and nvmem APIs.

Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
 MAINTAINERS              |   6 +
 drivers/rtc/Kconfig      |  12 +
 drivers/rtc/Makefile     |   1 +
 drivers/rtc/rtc-m5441x.c | 579 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 598 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e035a3be797c..44901a34499a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10196,6 +10196,12 @@ S:	Maintained
 F:	drivers/mmc/host/sdhci-esdhc-mcf.c
 F:	include/linux/platform_data/mmc-esdhc-mcf.h
 
+FREESCALE COLDFIRE M5441X RTC DRIVER
+M:	Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
+L:	linux-rtc@vger.kernel.org
+S:	Maintained
+F:	drivers/rtc/rtc-m5441x.c
+
 FREESCALE DIU FRAMEBUFFER DRIVER
 M:	Timur Tabi <timur@kernel.org>
 L:	linux-fbdev@vger.kernel.org
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 364afc73f8ab..45362247a56c 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1427,6 +1427,18 @@ config RTC_DRV_NTXEC
 
 comment "on-CPU RTC drivers"
 
+config RTC_DRV_M5441X
+	tristate "Freescale MCF5441x on-chip RTC"
+	depends on M5441x || COMPILE_TEST
+	help
+	  If you say yes here you get support for the on-chip "robust"
+	  real time clock found on Freescale MCF5441x ColdFire SoCs,
+	  including its 2KB battery-backed standby RAM exposed through the
+	  nvmem framework.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-m5441x.
+
 config RTC_DRV_ASM9260
 	tristate "Alphascale asm9260 RTC"
 	depends on MACH_ASM9260 || COMPILE_TEST
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6cf7e066314e..4c7cb67fbc3f 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_RTC_DRV_M41T94)	+= rtc-m41t94.o
 obj-$(CONFIG_RTC_DRV_M48T35)	+= rtc-m48t35.o
 obj-$(CONFIG_RTC_DRV_M48T59)	+= rtc-m48t59.o
 obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_M5441X)	+= rtc-m5441x.o
 obj-$(CONFIG_RTC_DRV_MA35D1)	+= rtc-ma35d1.o
 obj-$(CONFIG_RTC_DRV_MACSMC)	+= rtc-macsmc.o
 obj-$(CONFIG_RTC_DRV_MAX31335)	+= rtc-max31335.o
diff --git a/drivers/rtc/rtc-m5441x.c b/drivers/rtc/rtc-m5441x.c
new file mode 100644
index 000000000000..4e4834b2c956
--- /dev/null
+++ b/drivers/rtc/rtc-m5441x.c
@@ -0,0 +1,579 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * RTC driver for the Freescale MCF5441x on-chip "robust" RTC.
+ *
+ * Exposes the time/calendar and alarm, plus the 2KB battery-backed
+ * standby RAM as an nvmem device. The standby RAM survives main-power
+ * loss while VSTBY_RTC is supplied, which makes it usable to persist a
+ * reset/reboot counter across power cycles.
+ *
+ * Register layout and the base-2112 year encoding are taken from the
+ * MCF54418 reference manual (chapter "Robust Real Time Clock").
+ *
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2026 Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
+ *
+ * Based on the out-of-tree Freescale 3.0.x rtc-m5441x driver by
+ * Lanttor Guo <Lanttor.Guo@freescale.com>, rewritten for the current
+ * RTC and nvmem frameworks.
+ */
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+
+/* Register offsets from the RTC base. */
+#define M5441X_RTC_YEARMON	0x00
+#define M5441X_RTC_DAYS		0x02
+#define M5441X_RTC_HOURMIN	0x04
+#define M5441X_RTC_SECONDS	0x06
+#define M5441X_RTC_ALM_YRMON	0x08
+#define M5441X_RTC_ALM_DAYS	0x0a
+#define M5441X_RTC_ALM_HM	0x0c
+#define M5441X_RTC_ALM_SEC	0x0e
+#define M5441X_RTC_CR		0x10
+#define M5441X_RTC_SR		0x12
+#define M5441X_RTC_ISR		0x14
+#define M5441X_RTC_IER		0x16
+#define M5441X_RTC_CFG_DATA	0x20
+
+/* RTC_CR bits. Only WE is freely writable; the rest need the WE knock. */
+#define M5441X_RTC_CR_RSVD	0x8000	/* bit 15, reserved, must be set */
+#define M5441X_RTC_CR_BCDEN	0x0080	/* 0 = binary, 1 = BCD time/date */
+#define M5441X_RTC_CR_DSTEN	0x0040	/* daylight-saving auto-adjust */
+#define M5441X_RTC_CR_AM_MASK	0x000c	/* alarm match field */
+#define M5441X_RTC_CR_AM_FULL	0x000c	/* match s,m,h,day,month,year */
+#define M5441X_RTC_CR_WE_MASK	0x0003	/* write-enable knock field */
+
+#define M5441X_RTC_SR_INVAL	0x0001	/* time invalid / changing */
+#define M5441X_RTC_SR_WPE	0x0010	/* write protection enabled */
+#define M5441X_RTC_ISR_ALM	0x0004	/* alarm interrupt status/enable */
+#define M5441X_RTC_IER_RSVD	0x0001	/* IER/ISR bit 0 reserved, must be set */
+#define M5441X_RTC_CFG_OSCEN	0x0008	/* oscillator enable */
+
+/* Battery-backed standby RAM: 2KB at this offset within the block. */
+#define M5441X_RTC_SRAM_OFFSET	0x40
+#define M5441X_RTC_SRAM_SIZE	2048
+#define M5441X_RTC_SRAM_CHUNK	64	/* lock-drop granularity for SRAM I/O */
+
+#define M5441X_RTC_YEAR_BASE	2112
+
+struct m5441x_rtc {
+	struct rtc_device *rtc;
+	void __iomem *base;
+	spinlock_t lock;	/* serialises register access + WP window */
+	bool osc_dead;		/* 32kHz oscillator never started; no timekeeping */
+};
+
+static inline u16 rtc_rd(struct m5441x_rtc *p, unsigned int reg)
+{
+	return ioread16be(p->base + reg);
+}
+
+static inline void rtc_wr(struct m5441x_rtc *p, unsigned int reg, u16 val)
+{
+	iowrite16be(val, p->base + reg);
+}
+
+/*
+ * Issue the RTC_CR[WE] knock (00 -> 01 -> 11 -> 10) that opens the
+ * write-protection window. Writes to the registers and the standby RAM
+ * are rejected unless this sequence has been issued; the space then
+ * stays writable for ~2 seconds. Caller holds p->lock.
+ */
+static void m5441x_rtc_knock(struct m5441x_rtc *p)
+{
+	rtc_wr(p, M5441X_RTC_CR, 0x0000);
+	rtc_wr(p, M5441X_RTC_CR, 0x0001);
+	rtc_wr(p, M5441X_RTC_CR, 0x0003);
+	rtc_wr(p, M5441X_RTC_CR, 0x0002);
+}
+
+/* Open the write window only if protection is currently enabled. */
+static void m5441x_rtc_unlock(struct m5441x_rtc *p)
+{
+	if (rtc_rd(p, M5441X_RTC_SR) & M5441X_RTC_SR_WPE)
+		m5441x_rtc_knock(p);
+}
+
+/*
+ * Write the data bits of RTC_CR (BCDEN/DSTEN/AM). Caller holds p->lock
+ * and must have opened the write window first. The reserved bit 15 is
+ * kept set and the WE field kept clear so the write updates the data
+ * bits without re-arming write protection (a lone WE=10 would).
+ */
+static void m5441x_rtc_write_cr(struct m5441x_rtc *p, u16 val)
+{
+	val &= ~M5441X_RTC_CR_WE_MASK;
+	val |= M5441X_RTC_CR_RSVD;
+	rtc_wr(p, M5441X_RTC_CR, val);
+}
+
+/*
+ * The time counters are unstable for an oscillator cycle either side of
+ * the one-second boundary. RTC_SR[INVAL] flags this; reads during the
+ * window return 0xffff and writes are nullified. Poll until it clears.
+ * The window is only a couple of 32kHz cycles (~60us), so bound the
+ * busy-wait tightly. This runs with the lock held and interrupts off, so
+ * poll atomically (no sleeping). Caller holds p->lock.
+ */
+static int m5441x_rtc_wait_valid(struct m5441x_rtc *p)
+{
+	u16 sr;
+	int ret;
+
+	ret = read_poll_timeout_atomic(rtc_rd, sr, !(sr & M5441X_RTC_SR_INVAL),
+				       10, 100, false, p, M5441X_RTC_SR);
+
+	return ret ? -EIO : 0;
+}
+
+static int m5441x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct m5441x_rtc *p = dev_get_drvdata(dev);
+	u16 yearmon, days, hourmin, seconds;
+	unsigned int tries = 3;
+	unsigned long flags;
+	int ret;
+
+	/*
+	 * Without a running oscillator the counters are frozen; refuse the
+	 * read rather than hand userspace a stale time that hwclock --hctosys
+	 * would propagate into the system clock.
+	 */
+	if (p->osc_dead)
+		return -ENODATA;
+
+	/*
+	 * INVAL only guarantees the counters are stable at the moment it is
+	 * checked; it does not freeze them across the four reads. If a 1Hz
+	 * tick re-asserts INVAL mid-burst the fields can straddle a second
+	 * boundary (e.g. 23:59:59 -> 00:00:00), so re-check it afterwards and
+	 * retry the whole burst on observed re-entry.
+	 */
+	spin_lock_irqsave(&p->lock, flags);
+	do {
+		ret = m5441x_rtc_wait_valid(p);
+		if (ret)
+			break;
+		yearmon = rtc_rd(p, M5441X_RTC_YEARMON);
+		days    = rtc_rd(p, M5441X_RTC_DAYS);
+		hourmin = rtc_rd(p, M5441X_RTC_HOURMIN);
+		seconds = rtc_rd(p, M5441X_RTC_SECONDS);
+		/* Stable across the whole burst -> the snapshot is coherent. */
+		if (!(rtc_rd(p, M5441X_RTC_SR) & M5441X_RTC_SR_INVAL))
+			break;
+		ret = -EAGAIN;
+	} while (--tries);
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	if (ret)
+		return ret;
+
+	tm->tm_year = M5441X_RTC_YEAR_BASE + (s8)((yearmon >> 8) & 0xff) - 1900;
+	tm->tm_mon  = (yearmon & 0xff) - 1;
+	tm->tm_mday = days & 0xff;
+	tm->tm_wday = (days >> 8) & 0x7;
+	tm->tm_hour = (hourmin >> 8) & 0x1f;
+	tm->tm_min  = hourmin & 0x3f;
+	tm->tm_sec  = seconds & 0x3f;
+
+	return 0;
+}
+
+static int m5441x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct m5441x_rtc *p = dev_get_drvdata(dev);
+	s8 yoff = (tm->tm_year + 1900) - M5441X_RTC_YEAR_BASE;
+	unsigned int tries = 3;
+	unsigned long flags;
+	int ret;
+
+	/* A frozen oscillator would never latch the new time; reject it. */
+	if (p->osc_dead)
+		return -ENODATA;
+
+	/*
+	 * Writes are nullified while INVAL is asserted. wait_valid() clears
+	 * the path before the burst, but the knock plus four writes can cross
+	 * a second boundary on a slow RTC bus, silently dropping fields.
+	 * Re-check INVAL afterwards and rewrite on observed re-entry.
+	 */
+	spin_lock_irqsave(&p->lock, flags);
+	do {
+		ret = m5441x_rtc_wait_valid(p);
+		if (ret)
+			break;
+		m5441x_rtc_unlock(p);
+		rtc_wr(p, M5441X_RTC_YEARMON,
+		       ((u16)((u8)yoff) << 8) | ((tm->tm_mon + 1) & 0xff));
+		rtc_wr(p, M5441X_RTC_DAYS,
+		       ((tm->tm_wday & 0x7) << 8) | (tm->tm_mday & 0x1f));
+		rtc_wr(p, M5441X_RTC_HOURMIN,
+		       ((tm->tm_hour & 0x1f) << 8) | (tm->tm_min & 0x3f));
+		rtc_wr(p, M5441X_RTC_SECONDS, tm->tm_sec & 0x3f);
+		/* No boundary crossed mid-burst -> the writes all took. */
+		if (!(rtc_rd(p, M5441X_RTC_SR) & M5441X_RTC_SR_INVAL))
+			break;
+		ret = -EAGAIN;
+	} while (--tries);
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	return ret;
+}
+
+static int m5441x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct m5441x_rtc *p = dev_get_drvdata(dev);
+	u16 yearmon, days, hourmin, seconds, ier, isr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&p->lock, flags);
+	yearmon = rtc_rd(p, M5441X_RTC_ALM_YRMON);
+	days    = rtc_rd(p, M5441X_RTC_ALM_DAYS);
+	hourmin = rtc_rd(p, M5441X_RTC_ALM_HM);
+	seconds = rtc_rd(p, M5441X_RTC_ALM_SEC);
+	ier     = rtc_rd(p, M5441X_RTC_IER);
+	isr     = rtc_rd(p, M5441X_RTC_ISR);
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	alrm->time.tm_year = M5441X_RTC_YEAR_BASE +
+			     (s8)((yearmon >> 8) & 0xff) - 1900;
+	alrm->time.tm_mon  = (yearmon & 0xff) - 1;
+	alrm->time.tm_mday = days & 0xff;
+	alrm->time.tm_hour = (hourmin >> 8) & 0x1f;
+	alrm->time.tm_min  = hourmin & 0x3f;
+	alrm->time.tm_sec  = seconds & 0x3f;
+	alrm->enabled = !!(ier & M5441X_RTC_ISR_ALM);
+	alrm->pending = !!(isr & M5441X_RTC_ISR_ALM);
+
+	return 0;
+}
+
+static int m5441x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct m5441x_rtc *p = dev_get_drvdata(dev);
+	unsigned long flags;
+	u16 ier;
+
+	spin_lock_irqsave(&p->lock, flags);
+	m5441x_rtc_unlock(p);
+	ier = rtc_rd(p, M5441X_RTC_IER);
+	if (enabled) {
+		/*
+		 * The comparator latches ISR_ALM even while IER masks delivery,
+		 * so a match from a previous arming (or one surviving a reboot)
+		 * would fire the moment IER is unmasked. Clear it first.
+		 */
+		rtc_wr(p, M5441X_RTC_ISR, M5441X_RTC_ISR_ALM);
+		ier |= M5441X_RTC_ISR_ALM;
+	} else {
+		ier &= ~M5441X_RTC_ISR_ALM;
+	}
+	rtc_wr(p, M5441X_RTC_IER, ier);
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	return 0;
+}
+
+static int m5441x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct m5441x_rtc *p = dev_get_drvdata(dev);
+	s8 yoff = (alrm->time.tm_year + 1900) - M5441X_RTC_YEAR_BASE;
+	unsigned long flags;
+	u16 ier, cr;
+
+	spin_lock_irqsave(&p->lock, flags);
+	m5441x_rtc_unlock(p);
+	/* acknowledge any pending alarm (write-1-to-clear) */
+	rtc_wr(p, M5441X_RTC_ISR, M5441X_RTC_ISR_ALM);
+
+	/*
+	 * Match the full date so the alarm is a one-shot rather than the
+	 * hardware default of a daily hour:minute:second match.
+	 */
+	cr = rtc_rd(p, M5441X_RTC_CR);
+	m5441x_rtc_write_cr(p, (cr & ~M5441X_RTC_CR_AM_MASK) |
+				M5441X_RTC_CR_AM_FULL);
+
+	rtc_wr(p, M5441X_RTC_ALM_YRMON,
+	       ((u16)((u8)yoff) << 8) | ((alrm->time.tm_mon + 1) & 0xff));
+	/* RTC_ALM_DAYS has no day-of-week field; bits [15:8] are reserved. */
+	rtc_wr(p, M5441X_RTC_ALM_DAYS, alrm->time.tm_mday & 0x1f);
+	rtc_wr(p, M5441X_RTC_ALM_HM,
+	       ((alrm->time.tm_hour & 0x1f) << 8) | (alrm->time.tm_min & 0x3f));
+	rtc_wr(p, M5441X_RTC_ALM_SEC, alrm->time.tm_sec & 0x3f);
+
+	ier = rtc_rd(p, M5441X_RTC_IER);
+	if (alrm->enabled)
+		ier |= M5441X_RTC_ISR_ALM;
+	else
+		ier &= ~M5441X_RTC_ISR_ALM;
+	rtc_wr(p, M5441X_RTC_IER, ier);
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	return 0;
+}
+
+static irqreturn_t m5441x_rtc_irq(int irq, void *dev_id)
+{
+	struct m5441x_rtc *p = dev_id;
+	u16 status;
+
+	spin_lock(&p->lock);
+	/*
+	 * Mask the reserved bit 0 (always reads set) so only a real source
+	 * can claim the interrupt.
+	 */
+	status = rtc_rd(p, M5441X_RTC_ISR) & rtc_rd(p, M5441X_RTC_IER) &
+		 ~M5441X_RTC_IER_RSVD;
+	if (status) {
+		m5441x_rtc_unlock(p);
+		rtc_wr(p, M5441X_RTC_ISR, status);	/* write-1-to-clear */
+	}
+	spin_unlock(&p->lock);
+
+	if (!status)
+		return IRQ_NONE;
+
+	if (status & M5441X_RTC_ISR_ALM)
+		rtc_update_irq(p->rtc, 1, RTC_AF | RTC_IRQF);
+
+	/*
+	 * A hardware source was acknowledged above; claim the IRQ even when it
+	 * was not the alarm so genirq's spurious detector does not disable the
+	 * shared line.
+	 */
+	return IRQ_HANDLED;
+}
+
+static int m5441x_rtc_nvram_read(void *priv, unsigned int offset,
+				 void *val, size_t bytes)
+{
+	struct m5441x_rtc *p = priv;
+	u8 *buf = val;
+	size_t done;
+
+	/*
+	 * In-kernel nvmem_device_read() forwards offset/bytes verbatim, so
+	 * range-check here rather than trust the caller.
+	 */
+	if (offset >= M5441X_RTC_SRAM_SIZE ||
+	    bytes > M5441X_RTC_SRAM_SIZE - offset)
+		return -EINVAL;
+
+	/*
+	 * Process the transfer in chunks, releasing the lock between them, so
+	 * a full 2KB access does not keep hard interrupts disabled across
+	 * thousands of slow on-chip MMIO cycles and wreck IRQ latency.
+	 */
+	for (done = 0; done < bytes; done += M5441X_RTC_SRAM_CHUNK) {
+		unsigned int chunk = min_t(unsigned int, bytes - done,
+					   M5441X_RTC_SRAM_CHUNK);
+		unsigned int i;
+
+		scoped_guard(spinlock_irqsave, &p->lock)
+			for (i = 0; i < chunk; i++)
+				buf[done + i] = ioread8(p->base + M5441X_RTC_SRAM_OFFSET +
+							offset + done + i);
+	}
+
+	return 0;
+}
+
+static int m5441x_rtc_nvram_write(void *priv, unsigned int offset,
+				  void *val, size_t bytes)
+{
+	struct m5441x_rtc *p = priv;
+	u8 *buf = val;
+	size_t done;
+
+	/* See the read path: validate the range, the core does not. */
+	if (offset >= M5441X_RTC_SRAM_SIZE ||
+	    bytes > M5441X_RTC_SRAM_SIZE - offset)
+		return -EINVAL;
+
+	/*
+	 * Chunk the write and drop the lock between chunks (see the read
+	 * path). The write window stays open for ~2 seconds, far longer than
+	 * one chunk takes, so re-knock at the start of each chunk to keep it
+	 * open across the lock-drop.
+	 */
+	for (done = 0; done < bytes; done += M5441X_RTC_SRAM_CHUNK) {
+		unsigned int chunk = min_t(unsigned int, bytes - done,
+					   M5441X_RTC_SRAM_CHUNK);
+		unsigned int i;
+
+		scoped_guard(spinlock_irqsave, &p->lock) {
+			m5441x_rtc_knock(p);
+			for (i = 0; i < chunk; i++)
+				iowrite8(buf[done + i], p->base + M5441X_RTC_SRAM_OFFSET +
+					 offset + done + i);
+		}
+	}
+
+	return 0;
+}
+
+static const struct rtc_class_ops m5441x_rtc_ops = {
+	.read_time		= m5441x_rtc_read_time,
+	.set_time		= m5441x_rtc_set_time,
+	.read_alarm		= m5441x_rtc_read_alarm,
+	.set_alarm		= m5441x_rtc_set_alarm,
+	.alarm_irq_enable	= m5441x_rtc_alarm_irq_enable,
+};
+
+static int m5441x_rtc_probe(struct platform_device *pdev)
+{
+	struct nvmem_config nvmem_cfg = {
+		.name		= "m5441x_rtc_sram",
+		.type		= NVMEM_TYPE_BATTERY_BACKED,
+		.word_size	= 1,
+		.stride		= 1,
+		.size		= M5441X_RTC_SRAM_SIZE,
+		.reg_read	= m5441x_rtc_nvram_read,
+		.reg_write	= m5441x_rtc_nvram_write,
+	};
+	struct m5441x_rtc *p;
+	unsigned long flags;
+	bool osc_dead = false;
+	int irq, ret;
+	u16 cr, cfg;
+
+	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+	spin_lock_init(&p->lock);
+
+	p->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(p->base))
+		return PTR_ERR(p->base);
+
+	platform_set_drvdata(pdev, p);
+
+	/* Enable the oscillator if needed and mask/clear stale interrupts. */
+	spin_lock_irqsave(&p->lock, flags);
+	m5441x_rtc_unlock(p);
+	/*
+	 * Force binary, DST-free time/date encoding. The driver does not
+	 * handle the BCD format, and Linux expects the RTC to keep monotonic
+	 * time with local-time/DST conversion done in userspace, so clear
+	 * BCDEN and DSTEN in case a bootloader or prior OS left them set. Also
+	 * default the alarm match field to a full one-shot match: the reset
+	 * value (AM=00) is a daily hh:mm:ss match, which would fire on the
+	 * wrong day if userspace enables the alarm via RTC_AIE_ON without
+	 * first programming it through set_alarm().
+	 */
+	cr = rtc_rd(p, M5441X_RTC_CR);
+	cr &= ~(M5441X_RTC_CR_BCDEN | M5441X_RTC_CR_DSTEN | M5441X_RTC_CR_AM_MASK);
+	cr |= M5441X_RTC_CR_AM_FULL;
+	m5441x_rtc_write_cr(p, cr);
+
+	/*
+	 * The alarm registers are battery-backed and survive a power cycle,
+	 * so a previously armed match could re-fire before set_alarm() runs.
+	 * Clear them now (the write window is open).
+	 */
+	rtc_wr(p, M5441X_RTC_ALM_YRMON, 0);
+	rtc_wr(p, M5441X_RTC_ALM_DAYS, 0);
+	rtc_wr(p, M5441X_RTC_ALM_HM, 0);
+	rtc_wr(p, M5441X_RTC_ALM_SEC, 0);
+
+	/*
+	 * Enable the 32kHz oscillator that drives the time counters. This only
+	 * checks that the OSCEN enable bit latches: when it reads back clear
+	 * the oscillator block rejected the enable, which in practice means no
+	 * RTC crystal is fitted and the counters will never advance. It cannot
+	 * tell a dead crystal from one still starting up, so it is a best-
+	 * effort hint, not a liveness guarantee. Warn but keep probing, since
+	 * the battery-backed standby RAM stays usable without the oscillator.
+	 */
+	cfg = rtc_rd(p, M5441X_RTC_CFG_DATA);
+	if (!(cfg & M5441X_RTC_CFG_OSCEN)) {
+		rtc_wr(p, M5441X_RTC_CFG_DATA, cfg | M5441X_RTC_CFG_OSCEN);
+		if (!(rtc_rd(p, M5441X_RTC_CFG_DATA) & M5441X_RTC_CFG_OSCEN))
+			osc_dead = true;
+	}
+
+	/* Mask every source but keep the reserved bit 0 set as required. */
+	rtc_wr(p, M5441X_RTC_IER, M5441X_RTC_IER_RSVD);
+	rtc_wr(p, M5441X_RTC_ISR, rtc_rd(p, M5441X_RTC_ISR));
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	/*
+	 * Keep the device (and its standby-RAM nvmem) usable, but record the
+	 * dead oscillator so read_time/set_time refuse to expose a clock that
+	 * cannot tick.
+	 */
+	p->osc_dead = osc_dead;
+	if (osc_dead)
+		dev_warn(&pdev->dev,
+			 "RTC oscillator enable did not latch; timekeeping unavailable (no 32kHz crystal?)\n");
+
+	p->rtc = devm_rtc_allocate_device(&pdev->dev);
+	if (IS_ERR(p->rtc))
+		return PTR_ERR(p->rtc);
+
+	p->rtc->ops = &m5441x_rtc_ops;
+	p->rtc->range_min = mktime64(1984, 1, 1, 0, 0, 0);
+	p->rtc->range_max = mktime64(2239, 12, 31, 23, 59, 59);
+
+	irq = platform_get_irq_optional(pdev, 0);
+	if (irq > 0) {
+		ret = devm_request_irq(&pdev->dev, irq, m5441x_rtc_irq, 0,
+				       dev_name(&pdev->dev), p);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"failed to request IRQ %d: %d, alarm disabled\n",
+				irq, ret);
+			clear_bit(RTC_FEATURE_ALARM, p->rtc->features);
+		} else {
+			/*
+			 * The alarm comparator runs on standby power, so let it
+			 * wake a suspended system. The PM core keeps the IRQ
+			 * enabled across suspend once it is the device's wake
+			 * IRQ; both are device-managed.
+			 */
+			devm_device_init_wakeup(&pdev->dev);
+			devm_pm_set_wake_irq(&pdev->dev, irq);
+		}
+	} else {
+		clear_bit(RTC_FEATURE_ALARM, p->rtc->features);
+	}
+
+	/*
+	 * Register the RTC device before the nvmem provider:
+	 * devm_rtc_nvmem_register() copies rtc->owner into the nvmem config,
+	 * and that field is only assigned by devm_rtc_register_device().
+	 * Registering nvmem first would leave its owner NULL and fail to pin
+	 * this module while standby-RAM consumers hold references.
+	 */
+	ret = devm_rtc_register_device(p->rtc);
+	if (ret)
+		return ret;
+
+	nvmem_cfg.priv = p;
+	ret = devm_rtc_nvmem_register(p->rtc, &nvmem_cfg);
+	if (ret)
+		dev_warn(&pdev->dev, "standby RAM nvmem unavailable: %d\n", ret);
+
+	return 0;
+}
+
+static struct platform_driver m5441x_rtc_driver = {
+	.driver = {
+		.name = "rtc-m5441x",
+	},
+	.probe = m5441x_rtc_probe,
+};
+module_platform_driver(m5441x_rtc_driver);
+
+MODULE_DESCRIPTION("Freescale MCF5441x on-chip RTC driver");
+MODULE_AUTHOR("Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rtc-m5441x");

-- 
2.39.5


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/2] m68k: coldfire/m5441x: register the on-chip RTC
  2026-06-07  9:00 [PATCH v2 0/2] rtc: add a driver for the Freescale MCF5441x on-chip RTC Jean-Michel Hautbois
  2026-06-07  9:00 ` [PATCH v2 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver Jean-Michel Hautbois
@ 2026-06-07  9:00 ` Jean-Michel Hautbois
  1 sibling, 0 replies; 4+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-07  9:00 UTC (permalink / raw)
  To: Alexandre Belloni, Greg Ungerer, Geert Uytterhoeven
  Cc: linux-kernel, linux-rtc, linux-m68k, Jean-Michel Hautbois

Register the MCF5441x on-chip RTC platform device from the SoC code so
every MCF5441x board gets the rtc-m5441x driver (time/calendar plus the
battery-backed standby RAM via nvmem) without a per-board file.

Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
 arch/m68k/coldfire/m5441x.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/arch/m68k/coldfire/m5441x.c b/arch/m68k/coldfire/m5441x.c
index 7a25cfc7ac07..b79aebdfd567 100644
--- a/arch/m68k/coldfire/m5441x.c
+++ b/arch/m68k/coldfire/m5441x.c
@@ -10,6 +10,7 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
@@ -239,6 +240,34 @@ static void __init m5441x_fec_init(void)
 	__raw_writeb(0x03, MCFGPIO_PAR_FEC);
 }
 
+/*
+ * On-chip "robust" RTC. Exposes the time/calendar and the 2KB
+ * battery-backed standby RAM (rtc-m5441x driver).
+ */
+static struct resource m5441x_rtc_resource[] = {
+	{
+		.start	= MCFRTC_BASE,
+		.end	= MCFRTC_BASE + MCFRTC_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MCF_IRQ_RTC,
+		.end	= MCF_IRQ_RTC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static int __init m5441x_rtc_init(void)
+{
+	struct platform_device *pdev;
+
+	pdev = platform_device_register_simple("rtc-m5441x", -1,
+					       m5441x_rtc_resource,
+					       ARRAY_SIZE(m5441x_rtc_resource));
+	return PTR_ERR_OR_ZERO(pdev);
+}
+arch_initcall(m5441x_rtc_init);
+
 void __init config_BSP(char *commandp, int size)
 {
 	m5441x_clk_init();

-- 
2.39.5


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver
  2026-06-07  9:00 ` [PATCH v2 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver Jean-Michel Hautbois
@ 2026-06-28 12:40   ` Alexandre Belloni
  0 siblings, 0 replies; 4+ messages in thread
From: Alexandre Belloni @ 2026-06-28 12:40 UTC (permalink / raw)
  To: Jean-Michel Hautbois
  Cc: Greg Ungerer, Geert Uytterhoeven, linux-kernel, linux-rtc,
	linux-m68k

Hello,

On 07/06/2026 11:00:40+0200, Jean-Michel Hautbois wrote:
> +static int m5441x_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct m5441x_rtc *p = dev_get_drvdata(dev);
> +	u16 yearmon, days, hourmin, seconds;
> +	unsigned int tries = 3;
> +	unsigned long flags;
> +	int ret;
> +
> +	/*
> +	 * Without a running oscillator the counters are frozen; refuse the
> +	 * read rather than hand userspace a stale time that hwclock --hctosys
> +	 * would propagate into the system clock.
> +	 */
> +	if (p->osc_dead)
> +		return -ENODATA;

While not ideal, the current standard is to return -EINVAL in this case.

> +
> +static int m5441x_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct m5441x_rtc *p = dev_get_drvdata(dev);
> +	s8 yoff = (tm->tm_year + 1900) - M5441X_RTC_YEAR_BASE;
> +	unsigned int tries = 3;
> +	unsigned long flags;
> +	int ret;
> +
> +	/* A frozen oscillator would never latch the new time; reject it. */
> +	if (p->osc_dead)
> +		return -ENODATA;

set_time is a good location to actually restart the oscillator instead
of failing.


> +
> +	/*
> +	 * Writes are nullified while INVAL is asserted. wait_valid() clears
> +	 * the path before the burst, but the knock plus four writes can cross
> +	 * a second boundary on a slow RTC bus, silently dropping fields.
> +	 * Re-check INVAL afterwards and rewrite on observed re-entry.
> +	 */
> +	spin_lock_irqsave(&p->lock, flags);
> +	do {
> +		ret = m5441x_rtc_wait_valid(p);
> +		if (ret)
> +			break;
> +		m5441x_rtc_unlock(p);
> +		rtc_wr(p, M5441X_RTC_YEARMON,
> +		       ((u16)((u8)yoff) << 8) | ((tm->tm_mon + 1) & 0xff));
> +		rtc_wr(p, M5441X_RTC_DAYS,
> +		       ((tm->tm_wday & 0x7) << 8) | (tm->tm_mday & 0x1f));
> +		rtc_wr(p, M5441X_RTC_HOURMIN,
> +		       ((tm->tm_hour & 0x1f) << 8) | (tm->tm_min & 0x3f));
> +		rtc_wr(p, M5441X_RTC_SECONDS, tm->tm_sec & 0x3f);
> +		/* No boundary crossed mid-burst -> the writes all took. */
> +		if (!(rtc_rd(p, M5441X_RTC_SR) & M5441X_RTC_SR_INVAL))
> +			break;
> +		ret = -EAGAIN;
> +	} while (--tries);
> +	spin_unlock_irqrestore(&p->lock, flags);
> +
> +	return ret;
> +}
> +
> +



> +static int m5441x_rtc_probe(struct platform_device *pdev)
> +{
> +	struct nvmem_config nvmem_cfg = {
> +		.name		= "m5441x_rtc_sram",
> +		.type		= NVMEM_TYPE_BATTERY_BACKED,
> +		.word_size	= 1,
> +		.stride		= 1,
> +		.size		= M5441X_RTC_SRAM_SIZE,
> +		.reg_read	= m5441x_rtc_nvram_read,
> +		.reg_write	= m5441x_rtc_nvram_write,
> +	};
> +	struct m5441x_rtc *p;
> +	unsigned long flags;
> +	bool osc_dead = false;
> +	int irq, ret;
> +	u16 cr, cfg;
> +
> +	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
> +	if (!p)
> +		return -ENOMEM;
> +	spin_lock_init(&p->lock);
> +
> +	p->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(p->base))
> +		return PTR_ERR(p->base);
> +
> +	platform_set_drvdata(pdev, p);
> +
> +	/* Enable the oscillator if needed and mask/clear stale interrupts. */
> +	spin_lock_irqsave(&p->lock, flags);
> +	m5441x_rtc_unlock(p);
> +	/*
> +	 * Force binary, DST-free time/date encoding. The driver does not
> +	 * handle the BCD format, and Linux expects the RTC to keep monotonic
> +	 * time with local-time/DST conversion done in userspace, so clear
> +	 * BCDEN and DSTEN in case a bootloader or prior OS left them set. Also
> +	 * default the alarm match field to a full one-shot match: the reset
> +	 * value (AM=00) is a daily hh:mm:ss match, which would fire on the
> +	 * wrong day if userspace enables the alarm via RTC_AIE_ON without
> +	 * first programming it through set_alarm().
> +	 */
> +	cr = rtc_rd(p, M5441X_RTC_CR);
> +	cr &= ~(M5441X_RTC_CR_BCDEN | M5441X_RTC_CR_DSTEN | M5441X_RTC_CR_AM_MASK);
> +	cr |= M5441X_RTC_CR_AM_FULL;
> +	m5441x_rtc_write_cr(p, cr);

You must not enable the oscillator in probe as then you lose the
important information of whether the RTC has ever been set. Also,
forcefully setting DST here may destroy the existing date/time, don't do
this unless you know what is the current time (i.e. in set_time)

> +
> +	/*
> +	 * The alarm registers are battery-backed and survive a power cycle,
> +	 * so a previously armed match could re-fire before set_alarm() runs.
> +	 * Clear them now (the write window is open).
> +	 */
> +	rtc_wr(p, M5441X_RTC_ALM_YRMON, 0);
> +	rtc_wr(p, M5441X_RTC_ALM_DAYS, 0);
> +	rtc_wr(p, M5441X_RTC_ALM_HM, 0);
> +	rtc_wr(p, M5441X_RTC_ALM_SEC, 0);

Why wouldn't you want an existing alarm to fire? The registers are
battery backed exactly for this purpose.

> +
> +	/*
> +	 * Enable the 32kHz oscillator that drives the time counters. This only
> +	 * checks that the OSCEN enable bit latches: when it reads back clear
> +	 * the oscillator block rejected the enable, which in practice means no
> +	 * RTC crystal is fitted and the counters will never advance. It cannot
> +	 * tell a dead crystal from one still starting up, so it is a best-
> +	 * effort hint, not a liveness guarantee. Warn but keep probing, since
> +	 * the battery-backed standby RAM stays usable without the oscillator.
> +	 */
> +	cfg = rtc_rd(p, M5441X_RTC_CFG_DATA);
> +	if (!(cfg & M5441X_RTC_CFG_OSCEN)) {
> +		rtc_wr(p, M5441X_RTC_CFG_DATA, cfg | M5441X_RTC_CFG_OSCEN);
> +		if (!(rtc_rd(p, M5441X_RTC_CFG_DATA) & M5441X_RTC_CFG_OSCEN))
> +			osc_dead = true;
> +	}
> +
> +	/* Mask every source but keep the reserved bit 0 set as required. */
> +	rtc_wr(p, M5441X_RTC_IER, M5441X_RTC_IER_RSVD);
> +	rtc_wr(p, M5441X_RTC_ISR, rtc_rd(p, M5441X_RTC_ISR));

An existing alarm needs to be kept enabled.

> +	spin_unlock_irqrestore(&p->lock, flags);

I'm pretty sure locking here is useless until you register the interrupt.

> +
> +	/*
> +	 * Keep the device (and its standby-RAM nvmem) usable, but record the
> +	 * dead oscillator so read_time/set_time refuse to expose a clock that
> +	 * cannot tick.
> +	 */
> +	p->osc_dead = osc_dead;
> +	if (osc_dead)
> +		dev_warn(&pdev->dev,
> +			 "RTC oscillator enable did not latch; timekeeping unavailable (no 32kHz crystal?)\n");
> +
> +	p->rtc = devm_rtc_allocate_device(&pdev->dev);
> +	if (IS_ERR(p->rtc))
> +		return PTR_ERR(p->rtc);
> +
> +	p->rtc->ops = &m5441x_rtc_ops;
> +	p->rtc->range_min = mktime64(1984, 1, 1, 0, 0, 0);
> +	p->rtc->range_max = mktime64(2239, 12, 31, 23, 59, 59);
> +
> +	irq = platform_get_irq_optional(pdev, 0);
> +	if (irq > 0) {
> +		ret = devm_request_irq(&pdev->dev, irq, m5441x_rtc_irq, 0,
> +				       dev_name(&pdev->dev), p);

If this interrupt can be threaded, the spinlock becomes useless as long
as you lock the RTC with rtc_lock/rtc_unlock in the interrupt handler.

> +		if (ret) {
> +			dev_err(&pdev->dev,
> +				"failed to request IRQ %d: %d, alarm disabled\n",
> +				irq, ret);
> +			clear_bit(RTC_FEATURE_ALARM, p->rtc->features);
> +		} else {
> +			/*
> +			 * The alarm comparator runs on standby power, so let it
> +			 * wake a suspended system. The PM core keeps the IRQ
> +			 * enabled across suspend once it is the device's wake
> +			 * IRQ; both are device-managed.
> +			 */
> +			devm_device_init_wakeup(&pdev->dev);
> +			devm_pm_set_wake_irq(&pdev->dev, irq);
> +		}
> +	} else {
> +		clear_bit(RTC_FEATURE_ALARM, p->rtc->features);
> +	}
> +
> +	/*
> +	 * Register the RTC device before the nvmem provider:
> +	 * devm_rtc_nvmem_register() copies rtc->owner into the nvmem config,
> +	 * and that field is only assigned by devm_rtc_register_device().
> +	 * Registering nvmem first would leave its owner NULL and fail to pin
> +	 * this module while standby-RAM consumers hold references.
> +	 */
> +	ret = devm_rtc_register_device(p->rtc);
> +	if (ret)
> +		return ret;
> +
> +	nvmem_cfg.priv = p;
> +	ret = devm_rtc_nvmem_register(p->rtc, &nvmem_cfg);
> +	if (ret)
> +		dev_warn(&pdev->dev, "standby RAM nvmem unavailable: %d\n", ret);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver m5441x_rtc_driver = {
> +	.driver = {
> +		.name = "rtc-m5441x",
> +	},
> +	.probe = m5441x_rtc_probe,
> +};
> +module_platform_driver(m5441x_rtc_driver);
> +
> +MODULE_DESCRIPTION("Freescale MCF5441x on-chip RTC driver");
> +MODULE_AUTHOR("Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:rtc-m5441x");
> 
> -- 
> 2.39.5
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-28 12:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-07  9:00 [PATCH v2 0/2] rtc: add a driver for the Freescale MCF5441x on-chip RTC Jean-Michel Hautbois
2026-06-07  9:00 ` [PATCH v2 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver Jean-Michel Hautbois
2026-06-28 12:40   ` Alexandre Belloni
2026-06-07  9:00 ` [PATCH v2 2/2] m68k: coldfire/m5441x: register the on-chip RTC Jean-Michel Hautbois

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox