Linux RTC
 help / color / mirror / Atom feed
* [PATCH v2 5/5] rtc: renesas-rtca3: Factor out year decoding helper
From: Prabhakar @ 2026-06-02 19:25 UTC (permalink / raw)
  To: Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven, linux-rtc
  Cc: linux-renesas-soc, linux-kernel, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar
In-Reply-To: <20260602192559.1791344-1-prabhakar.mahadev-lad.rj@bp.renesas.com>

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

The logic to decode the year value from the hardware registers is
duplicated in both rtca3_read_time() and rtca3_read_alarm().

Introduce a helper rtca3_decode_year() to centralize this conversion.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S
---
 drivers/rtc/rtc-renesas-rtca3.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c
index 97e7e65f59a5..b3875d041de5 100644
--- a/drivers/rtc/rtc-renesas-rtca3.c
+++ b/drivers/rtc/rtc-renesas-rtca3.c
@@ -228,12 +228,19 @@ static void rtca3_prepare_cntalrm_regs_for_read(struct rtca3_priv *priv, bool cn
 	}
 }
 
+static u32 rtca3_decode_year(u8 mask, u16 year)
+{
+	u8 y = FIELD_GET(mask, year);
+	u32 century = bcd2bin((y == 0x99) ? 0x19 : 0x20);
+
+	return (century * 100 + bcd2bin(y)) - 1900;
+}
+
 static int rtca3_read_time(struct device *dev, struct rtc_time *tm)
 {
 	struct rtca3_priv *priv = dev_get_drvdata(dev);
 	u8 sec, min, hour, wday, mday, month, tmp;
 	u8 trials = 0;
-	u32 year100;
 	u16 year;
 
 	guard(spinlock_irqsave)(&priv->lock);
@@ -274,9 +281,7 @@ static int rtca3_read_time(struct device *dev, struct rtc_time *tm)
 	tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKCNT_WK, wday));
 	tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYCNT_DAY, mday));
 	tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONCNT_MONTH, month)) - 1;
-	year = FIELD_GET(RTCA3_RYRCNT_YEAR, year);
-	year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
-	tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
+	tm->tm_year = rtca3_decode_year(RTCA3_RYRCNT_YEAR, year);
 
 	return 0;
 }
@@ -354,7 +359,6 @@ static int rtca3_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 	struct rtca3_priv *priv = dev_get_drvdata(dev);
 	u8 sec, min, hour, wday, mday, month;
 	struct rtc_time *tm = &wkalrm->time;
-	u32 year100;
 	u16 year;
 
 	guard(spinlock_irqsave)(&priv->lock);
@@ -373,9 +377,7 @@ static int rtca3_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 	tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKAR_DAYW, wday));
 	tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYAR_DATE, mday));
 	tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONAR_MON, month)) - 1;
-	year = FIELD_GET(RTCA3_RYRAR_YR, year);
-	year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
-	tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
+	tm->tm_year = rtca3_decode_year(RTCA3_RYRAR_YR, year);
 
 	wkalrm->enabled = !!(readb(priv->base + RTCA3_RCR1) & RTCA3_RCR1_AIE);
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 4/5] rtc: renesas-rtca3: Fix typo in rtca3_ppb_per_cycle documentation
From: Prabhakar @ 2026-06-02 19:25 UTC (permalink / raw)
  To: Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven, linux-rtc
  Cc: linux-renesas-soc, linux-kernel, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar
In-Reply-To: <20260602192559.1791344-1-prabhakar.mahadev-lad.rj@bp.renesas.com>

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Correct a typo in the kernel-doc comment for struct
rtca3_ppb_per_cycle by fixing "adjutment" to "adjustment".

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S
---
 drivers/rtc/rtc-renesas-rtca3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c
index 8763745b9172..97e7e65f59a5 100644
--- a/drivers/rtc/rtc-renesas-rtca3.c
+++ b/drivers/rtc/rtc-renesas-rtca3.c
@@ -103,7 +103,7 @@ enum rtca3_alrm_set_step {
 
 /**
  * struct rtca3_ppb_per_cycle - PPB per cycle
- * @ten_sec: PPB per cycle in 10 seconds adjutment mode
+ * @ten_sec: PPB per cycle in 10 seconds adjustment mode
  * @sixty_sec: PPB per cycle in 60 seconds adjustment mode
  */
 struct rtca3_ppb_per_cycle {
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 3/5] rtc: renesas-rtca3: Fix incorrect error message for reset assert
From: Prabhakar @ 2026-06-02 19:25 UTC (permalink / raw)
  To: Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven, linux-rtc
  Cc: linux-renesas-soc, linux-kernel, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar
In-Reply-To: <20260602192559.1791344-1-prabhakar.mahadev-lad.rj@bp.renesas.com>

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Update the message to "assert reset" to accurately reflect the
operation being performed.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S
---
 drivers/rtc/rtc-renesas-rtca3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c
index af2a3878289e..8763745b9172 100644
--- a/drivers/rtc/rtc-renesas-rtca3.c
+++ b/drivers/rtc/rtc-renesas-rtca3.c
@@ -702,7 +702,7 @@ static void rtca3_action(void *data)
 
 	ret = reset_control_assert(priv->rstc);
 	if (ret)
-		dev_err(dev, "Failed to de-assert reset!");
+		dev_err(dev, "Failed to assert reset!");
 
 	ret = pm_runtime_put_sync(dev);
 	if (ret < 0)
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 2/5] rtc: renesas-rtca3: Check RADJ poll result during initial setup
From: Prabhakar @ 2026-06-02 19:25 UTC (permalink / raw)
  To: Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven, linux-rtc
  Cc: linux-renesas-soc, linux-kernel, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar
In-Reply-To: <20260602192559.1791344-1-prabhakar.mahadev-lad.rj@bp.renesas.com>

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

In rtca3_initial_setup(), the driver clears the RTCA3_RADJ register and
waits for it to reach zero using readb_poll_timeout(). Check the return
value of readb_poll_timeout() and propagate the error if the poll fails.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S
---
 drivers/rtc/rtc-renesas-rtca3.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c
index 2dc080d0eb6c..af2a3878289e 100644
--- a/drivers/rtc/rtc-renesas-rtca3.c
+++ b/drivers/rtc/rtc-renesas-rtca3.c
@@ -634,6 +634,8 @@ static int rtca3_initial_setup(struct clk *clk, struct rtca3_priv *priv)
 	writeb(0, priv->base + RTCA3_RADJ);
 	ret = readb_poll_timeout(priv->base + RTCA3_RADJ, tmp, !tmp, 10,
 				 RTCA3_DEFAULT_TIMEOUT_US);
+	if (ret)
+		return ret;
 
 	/* Start the RTC and enable automatic time error adjustment. */
 	mask = RTCA3_RCR2_START | RTCA3_RCR2_AADJE;
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 1/5] rtc: renesas-rtca3: Fix PIE clear polling condition in alarm setup error path
From: Prabhakar @ 2026-06-02 19:25 UTC (permalink / raw)
  To: Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven, linux-rtc
  Cc: linux-renesas-soc, linux-kernel, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar, stable
In-Reply-To: <20260602192559.1791344-1-prabhakar.mahadev-lad.rj@bp.renesas.com>

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

In rtca3_set_alarm(), the setup_failed path attempts to disable the
Periodic Interrupt Enable (PIE) bit and wait until it is cleared.
However, the polling condition passed to readb_poll_timeout_atomic()
uses an incorrect expression:

    !(tmp & ~RTCA3_RCR1_PIE)

As ~RTCA3_RCR1_PIE evaluates to a mask of all bits except PIE, the
condition effectively waits for all non-PIE bits to become zero, which
is unrelated to the intended operation and is unlikely to ever be true.
This causes the poll to time out unnecessarily.

Fix the condition to check for the PIE bit itself being cleared:

    !(tmp & RTCA3_RCR1_PIE)

This correctly waits until PIE is deasserted after being cleared.

Fixes: d4488377609e3 ("rtc: renesas-rtca3: Add driver for RTCA-3 available on Renesas RZ/G3S SoC")
Cc: stable@vger.kernel.org
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S
---
 drivers/rtc/rtc-renesas-rtca3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c
index cbabaa4dc96a..2dc080d0eb6c 100644
--- a/drivers/rtc/rtc-renesas-rtca3.c
+++ b/drivers/rtc/rtc-renesas-rtca3.c
@@ -455,7 +455,7 @@ static int rtca3_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 		 * specified timeout for setup.
 		 */
 		writeb(rcr1 & ~RTCA3_RCR1_PIE, priv->base + RTCA3_RCR1);
-		readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & ~RTCA3_RCR1_PIE),
+		readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & RTCA3_RCR1_PIE),
 					  10, RTCA3_DEFAULT_TIMEOUT_US);
 		atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
 	}
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 0/5] rtc: renesas-rtca3: Various fixes and improvements
From: Prabhakar @ 2026-06-02 19:25 UTC (permalink / raw)
  To: Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven, linux-rtc
  Cc: linux-renesas-soc, linux-kernel, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Hi all,

This patch series includes various fixes and improvements for the
Renesas RTCA-3 RTC driver, including:
- Fixing the polling condition when clearing the PIE bit during alarm
  setup error handling.
- Checking the result of the RADJ polling during initial setup and
  propagating errors.
- Correcting an error message related to reset control.
- Fixing a typo in the documentation for the rtca3_ppb_per_cycle struct.
- Refactoring year decoding logic into a helper function for better
  readability.

v1->v2:
- Added Fixes tag for patch #1
- Added RB/TB tags from Claudiu
- Rebased the patches on top of next-20260602

Cheers,
Prabhakar

Lad Prabhakar (5):
  rtc: renesas-rtca3: Fix PIE clear polling condition in alarm setup
    error path
  rtc: renesas-rtca3: Check RADJ poll result during initial setup
  rtc: renesas-rtca3: Fix incorrect error message for reset assert
  rtc: renesas-rtca3: Fix typo in rtca3_ppb_per_cycle documentation
  rtc: renesas-rtca3: Factor out year decoding helper

 drivers/rtc/rtc-renesas-rtca3.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

-- 
2.54.0


^ permalink raw reply

* Re: [PATCH 1/5] rtc: renesas-rtca3: Fix PIE clear polling condition in alarm setup error path
From: Lad, Prabhakar @ 2026-06-02 19:16 UTC (permalink / raw)
  To: Claudiu Beznea
  Cc: Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven, linux-rtc,
	linux-renesas-soc, linux-kernel, Biju Das, Fabrizio Castro,
	Lad Prabhakar
In-Reply-To: <7f6fe294-582d-4668-aa77-ad9ab47cce2e@tuxon.dev>

Hi Claudiu,

Thank you for the review.

On Tue, Jun 2, 2026 at 9:31 AM Claudiu Beznea <claudiu.beznea@tuxon.dev> wrote:
>
> Hi, Prabhakar,
>
> On 5/6/26 19:49, Prabhakar wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > In rtca3_set_alarm(), the setup_failed path attempts to disable the
> > Periodic Interrupt Enable (PIE) bit and wait until it is cleared.
> > However, the polling condition passed to readb_poll_timeout_atomic()
> > uses an incorrect expression:
> >
> >      !(tmp & ~RTCA3_RCR1_PIE)
> >
> > As ~RTCA3_RCR1_PIE evaluates to a mask of all bits except PIE, the
> > condition effectively waits for all non-PIE bits to become zero, which
> > is unrelated to the intended operation and is unlikely to ever be true.
> > This causes the poll to time out unnecessarily.
> >
> > Fix the condition to check for the PIE bit itself being cleared:
> >
> >      !(tmp & RTCA3_RCR1_PIE)
> >
> > This correctly waits until PIE is deasserted after being cleared.
> >
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S
>
> I think it also deserves a Fixes tag?
>
Ok, I will add (and also CC to stable).

Cheers,
Prabhakar

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: rtc: add ASPEED AST2700 compatible
From: Conor Dooley @ 2026-06-02 16:59 UTC (permalink / raw)
  To: Tommy Huang
  Cc: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Joel Stanley, Andrew Jeffery, linux-rtc, devicetree, linux-kernel,
	linux-arm-kernel, linux-aspeed
In-Reply-To: <20260601-ast2700-rtc-v1-1-15d4ca46500a@aspeedtech.com>

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH v1] rtc: mpfs: fix counter upload completion condition
From: Valentina.FernandezAlanis @ 2026-06-02 13:14 UTC (permalink / raw)
  To: conor, linux-riscv
  Cc: Conor.Dooley, stable, Daire.McNamara, alexandre.belloni,
	linux-rtc, linux-kernel, Valentina.FernandezAlanis
In-Reply-To: <20260513-panhandle-ashy-70c6abf84d59@spud>

On 13/05/2026 18:55, Conor Dooley wrote:
> From: Conor Dooley <conor.dooley@microchip.com>
>
> The condition that needs to be checked for upload completion is the
> UPLOAD bit in the completion register going low. The original iterations
> of this driver used a do-while and this was converted to a
> read_poll_timeout() during upstreaming without the condition being
> inverted as it should have been.
>
> I suspect that this went unnoticed until now because a) the first read
> was done when the bit was still set, immediately completing the
> read_poll_timeout() and b) because the RTC doesn't hold time when power
> is removed from the SoC reducing its utility (I for one keep it
> disabled). If my first suspicion was true when the driver was
> upstreamed, it's not true any longer though, hence the detection of the
> problem.
>
> Fixes: 0b31d703598dc ("rtc: Add driver for Microchip PolarFire SoC")
> CC: stable@vger.kernel.org
> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Tested-by: Valentina Fernandez <valentina.fernandezalanis@microchip.com>
> ---
> CC: Valentina.FernandezAlanis@microchip.com
> CC: Conor Dooley <conor.dooley@microchip.com>
> CC: Daire McNamara <daire.mcnamara@microchip.com>
> CC: Alexandre Belloni <alexandre.belloni@bootlin.com>
> CC: linux-riscv@lists.infradead.org
> CC: linux-rtc@vger.kernel.org
> CC: linux-kernel@vger.kernel.org
> ---
>   drivers/rtc/rtc-mpfs.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c
> index 6aa3eae575d2a..ece6de4a6adbd 100644
> --- a/drivers/rtc/rtc-mpfs.c
> +++ b/drivers/rtc/rtc-mpfs.c
> @@ -112,7 +112,7 @@ static int mpfs_rtc_settime(struct device *dev, struct rtc_time *tm)
>   	ctrl |= CONTROL_UPLOAD_BIT;
>   	writel(ctrl, rtcdev->base + CONTROL_REG);
>   
> -	ret = read_poll_timeout(readl, prog, prog & CONTROL_UPLOAD_BIT, 0, UPLOAD_TIMEOUT_US,
> +	ret = read_poll_timeout(readl, prog, !(prog & CONTROL_UPLOAD_BIT), 0, UPLOAD_TIMEOUT_US,
>   				false, rtcdev->base + CONTROL_REG);
>   	if (ret) {
>   		dev_err(dev, "timed out uploading time to rtc");



^ permalink raw reply

* Re: [PATCH 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver
From: Geert Uytterhoeven @ 2026-06-02 11:08 UTC (permalink / raw)
  To: Jean-Michel Hautbois
  Cc: Alexandre Belloni, Greg Ungerer, linux-kernel, linux-rtc,
	linux-m68k
In-Reply-To: <42ab8311-0bd1-4094-aca7-0ca108c3a919@yoseli.org>

Hi Jean-Michel,

On Tue, 2 Jun 2026 at 13:05, Jean-Michel Hautbois
<jeanmichel.hautbois@yoseli.org> wrote:
> Le 02/06/2026 à 12:04, Geert Uytterhoeven a écrit :
> > On Tue, 2 Jun 2026 at 10:36, Jean-Michel Hautbois
> > <jeanmichel.hautbois@yoseli.org> wrote:
> >> 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>
> >
> > Thanks for your patch!
> >
> >> +/*
> >> + * 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. Spin until it clears.
> >> + * The window is only a couple of 32kHz cycles (~60us), so bound the
> >> + * busy-wait tightly: it runs with the lock held and interrupts off.
> >> + * Caller holds p->lock.
> >> + */
> >> +static int m5441x_rtc_wait_valid(struct m5441x_rtc *p)
> >> +{
> >> +       unsigned int tries = 10;
> >> +
> >> +       while (rtc_rd(p, M5441X_RTC_SR) & M5441X_RTC_SR_INVAL) {
> >> +               if (!--tries)
> >> +                       return -EIO;
> >> +               udelay(10);
> >> +       }
> >
> > Please use read_poll_timeout().
>
> As wait_valid() is called after spin_lock_irqsave() is called, I suppose
> I should use read_poll_timeout_atomic() ? Because read_poll_timeout()
> sleeps ?

Sorry, I copy and pasted the wrong function name, so you're right.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver
From: Jean-Michel Hautbois @ 2026-06-02 11:05 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Alexandre Belloni, Greg Ungerer, linux-kernel, linux-rtc,
	linux-m68k
In-Reply-To: <CAMuHMdX=njpXOQu=LZCba0PjHRKbcbpCDMHjat-e+atMtNmSRQ@mail.gmail.com>

Hi Geert,

Le 02/06/2026 à 12:04, Geert Uytterhoeven a écrit :
> Hi Jean-Michel,
> 
> On Tue, 2 Jun 2026 at 10:36, Jean-Michel Hautbois
> <jeanmichel.hautbois@yoseli.org> wrote:
>> 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>
> 
> Thanks for your patch!
> 
>> +/*
>> + * 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. Spin until it clears.
>> + * The window is only a couple of 32kHz cycles (~60us), so bound the
>> + * busy-wait tightly: it runs with the lock held and interrupts off.
>> + * Caller holds p->lock.
>> + */
>> +static int m5441x_rtc_wait_valid(struct m5441x_rtc *p)
>> +{
>> +       unsigned int tries = 10;
>> +
>> +       while (rtc_rd(p, M5441X_RTC_SR) & M5441X_RTC_SR_INVAL) {
>> +               if (!--tries)
>> +                       return -EIO;
>> +               udelay(10);
>> +       }
> 
> Please use read_poll_timeout().

As wait_valid() is called after spin_lock_irqsave() is called, I suppose 
I should use read_poll_timeout_atomic() ? Because read_poll_timeout() 
sleeps ?

> 
>> +
>> +       return 0;
>> +}
> 
>> +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) {
>> +               size_t chunk = min_t(size_t, bytes - done, M5441X_RTC_SRAM_CHUNK);
> 
> size_t looks like overkill to me.
> 
>> +               unsigned long flags;
>> +               size_t i;
> 
> Likewise
> 

Done.

>> +
>> +               spin_lock_irqsave(&p->lock, flags);
> 
> scoped_guard(spinlock, &p->lock)?

Sure, thanks !

> 
>> +               for (i = 0; i < chunk; i++)
>> +                       buf[done + i] = ioread8(p->base + M5441X_RTC_SRAM_OFFSET +
>> +                                               offset + done + i);
>> +               spin_unlock_irqrestore(&p->lock, flags);
>> +       }
>> +
>> +       return 0;
>> +}
> 
> Gr{oetje,eeting}s,
> 
>                          Geert
> 


^ permalink raw reply

* Re: [PATCH 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver
From: Geert Uytterhoeven @ 2026-06-02 10:04 UTC (permalink / raw)
  To: Jean-Michel Hautbois
  Cc: Alexandre Belloni, Greg Ungerer, linux-kernel, linux-rtc,
	linux-m68k
In-Reply-To: <20260602-jmh-upstream-coldfire-rtc-v1-1-1e129a177d2f@yoseli.org>

Hi Jean-Michel,

On Tue, 2 Jun 2026 at 10:36, Jean-Michel Hautbois
<jeanmichel.hautbois@yoseli.org> wrote:
> 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>

Thanks for your patch!

> +/*
> + * 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. Spin until it clears.
> + * The window is only a couple of 32kHz cycles (~60us), so bound the
> + * busy-wait tightly: it runs with the lock held and interrupts off.
> + * Caller holds p->lock.
> + */
> +static int m5441x_rtc_wait_valid(struct m5441x_rtc *p)
> +{
> +       unsigned int tries = 10;
> +
> +       while (rtc_rd(p, M5441X_RTC_SR) & M5441X_RTC_SR_INVAL) {
> +               if (!--tries)
> +                       return -EIO;
> +               udelay(10);
> +       }

Please use read_poll_timeout().

> +
> +       return 0;
> +}

> +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) {
> +               size_t chunk = min_t(size_t, bytes - done, M5441X_RTC_SRAM_CHUNK);

size_t looks like overkill to me.

> +               unsigned long flags;
> +               size_t i;

Likewise

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

scoped_guard(spinlock, &p->lock)?

> +               for (i = 0; i < chunk; i++)
> +                       buf[done + i] = ioread8(p->base + M5441X_RTC_SRAM_OFFSET +
> +                                               offset + done + i);
> +               spin_unlock_irqrestore(&p->lock, flags);
> +       }
> +
> +       return 0;
> +}

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH v1] rtc: mpfs: fix counter upload completion condition
From: Conor Dooley @ 2026-06-02  9:16 UTC (permalink / raw)
  To: linux-riscv
  Cc: Conor Dooley, stable, Valentina.FernandezAlanis, Daire McNamara,
	Alexandre Belloni, linux-rtc, linux-kernel
In-Reply-To: <20260513-panhandle-ashy-70c6abf84d59@spud>

[-- Attachment #1: Type: text/plain, Size: 2269 bytes --]

Hey Alexandrew,

On Wed, May 13, 2026 at 06:55:55PM +0100, Conor Dooley wrote:
> From: Conor Dooley <conor.dooley@microchip.com>
> 
> The condition that needs to be checked for upload completion is the
> UPLOAD bit in the completion register going low. The original iterations
> of this driver used a do-while and this was converted to a
> read_poll_timeout() during upstreaming without the condition being
> inverted as it should have been.
> 
> I suspect that this went unnoticed until now because a) the first read
> was done when the bit was still set, immediately completing the
> read_poll_timeout() and b) because the RTC doesn't hold time when power
> is removed from the SoC reducing its utility (I for one keep it
> disabled). If my first suspicion was true when the driver was
> upstreamed, it's not true any longer though, hence the detection of the
> problem.
> 
> Fixes: 0b31d703598dc ("rtc: Add driver for Microchip PolarFire SoC")
> CC: stable@vger.kernel.org
> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>

Any chance this could be applied as 7.1 fixes material?

Apologies if I missed an application mail somewhere,
Conor.

> ---
> CC: Valentina.FernandezAlanis@microchip.com
> CC: Conor Dooley <conor.dooley@microchip.com>
> CC: Daire McNamara <daire.mcnamara@microchip.com>
> CC: Alexandre Belloni <alexandre.belloni@bootlin.com>
> CC: linux-riscv@lists.infradead.org
> CC: linux-rtc@vger.kernel.org
> CC: linux-kernel@vger.kernel.org
> ---
>  drivers/rtc/rtc-mpfs.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c
> index 6aa3eae575d2a..ece6de4a6adbd 100644
> --- a/drivers/rtc/rtc-mpfs.c
> +++ b/drivers/rtc/rtc-mpfs.c
> @@ -112,7 +112,7 @@ static int mpfs_rtc_settime(struct device *dev, struct rtc_time *tm)
>  	ctrl |= CONTROL_UPLOAD_BIT;
>  	writel(ctrl, rtcdev->base + CONTROL_REG);
>  
> -	ret = read_poll_timeout(readl, prog, prog & CONTROL_UPLOAD_BIT, 0, UPLOAD_TIMEOUT_US,
> +	ret = read_poll_timeout(readl, prog, !(prog & CONTROL_UPLOAD_BIT), 0, UPLOAD_TIMEOUT_US,
>  				false, rtcdev->base + CONTROL_REG);
>  	if (ret) {
>  		dev_err(dev, "timed out uploading time to rtc");
> -- 
> 2.53.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* [PATCH 1/2] rtc: m5441x: add MCF5441x on-chip RTC driver
From: Jean-Michel Hautbois @ 2026-06-02  8:36 UTC (permalink / raw)
  To: Alexandre Belloni, Greg Ungerer, Geert Uytterhoeven
  Cc: linux-kernel, linux-rtc, linux-m68k, Jean-Michel Hautbois
In-Reply-To: <20260602-jmh-upstream-coldfire-rtc-v1-0-1e129a177d2f@yoseli.org>

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 | 582 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 601 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9ec290e38b44..e8001adfb6ca 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..b3d1bf4c1153
--- /dev/null
+++ b/drivers/rtc/rtc-m5441x.c
@@ -0,0 +1,582 @@
+// 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/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.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. Spin until it clears.
+ * The window is only a couple of 32kHz cycles (~60us), so bound the
+ * busy-wait tightly: it runs with the lock held and interrupts off.
+ * Caller holds p->lock.
+ */
+static int m5441x_rtc_wait_valid(struct m5441x_rtc *p)
+{
+	unsigned int tries = 10;
+
+	while (rtc_rd(p, M5441X_RTC_SR) & M5441X_RTC_SR_INVAL) {
+		if (!--tries)
+			return -EIO;
+		udelay(10);
+	}
+
+	return 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) {
+		size_t chunk = min_t(size_t, bytes - done, M5441X_RTC_SRAM_CHUNK);
+		unsigned long flags;
+		size_t i;
+
+		spin_lock_irqsave(&p->lock, flags);
+		for (i = 0; i < chunk; i++)
+			buf[done + i] = ioread8(p->base + M5441X_RTC_SRAM_OFFSET +
+						offset + done + i);
+		spin_unlock_irqrestore(&p->lock, flags);
+	}
+
+	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) {
+		size_t chunk = min_t(size_t, bytes - done, M5441X_RTC_SRAM_CHUNK);
+		unsigned long flags;
+		size_t i;
+
+		spin_lock_irqsave(&p->lock, flags);
+		m5441x_rtc_knock(p);
+		for (i = 0; i < chunk; i++)
+			iowrite8(buf[done + i], p->base + M5441X_RTC_SRAM_OFFSET +
+				 offset + done + i);
+		spin_unlock_irqrestore(&p->lock, flags);
+	}
+
+	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

* [PATCH 0/2] rtc: add a driver for the Freescale MCF5441x on-chip RTC
From: Jean-Michel Hautbois @ 2026-06-02  8:36 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>
---
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    | 582 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 630 insertions(+)
---
base-commit: 6f3ed7fec72fc8979b2a8c7219c0a9fcfc8d07b5
change-id: 20260529-jmh-upstream-coldfire-rtc-88b095b2cf28

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


^ permalink raw reply

* [PATCH 2/2] m68k: coldfire/m5441x: register the on-chip RTC
From: Jean-Michel Hautbois @ 2026-06-02  8:36 UTC (permalink / raw)
  To: Alexandre Belloni, Greg Ungerer, Geert Uytterhoeven
  Cc: linux-kernel, linux-rtc, linux-m68k, Jean-Michel Hautbois
In-Reply-To: <20260602-jmh-upstream-coldfire-rtc-v1-0-1e129a177d2f@yoseli.org>

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

* Re: [PATCH 5/5] rtc: renesas-rtca3: Factor out year decoding helper
From: Claudiu Beznea @ 2026-06-02  8:32 UTC (permalink / raw)
  To: Prabhakar, Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven
  Cc: linux-rtc, linux-renesas-soc, linux-kernel, Biju Das,
	Fabrizio Castro, Lad Prabhakar
In-Reply-To: <20260506164914.3987293-6-prabhakar.mahadev-lad.rj@bp.renesas.com>



On 5/6/26 19:49, Prabhakar wrote:
> From: Lad Prabhakar<prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> The logic to decode the year value from the hardware registers is
> duplicated in both rtca3_read_time() and rtca3_read_alarm().
> 
> Introduce a helper rtca3_decode_year() to centralize this conversion.
> 
> Signed-off-by: Lad Prabhakar<prabhakar.mahadev-lad.rj@bp.renesas.com>

Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S

^ permalink raw reply

* Re: [PATCH 4/5] rtc: renesas-rtca3: Fix typo in rtca3_ppb_per_cycle documentation
From: Claudiu Beznea @ 2026-06-02  8:32 UTC (permalink / raw)
  To: Prabhakar, Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven
  Cc: linux-rtc, linux-renesas-soc, linux-kernel, Biju Das,
	Fabrizio Castro, Lad Prabhakar
In-Reply-To: <20260506164914.3987293-5-prabhakar.mahadev-lad.rj@bp.renesas.com>



On 5/6/26 19:49, Prabhakar wrote:
> From: Lad Prabhakar<prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> Correct a typo in the kernel-doc comment for struct
> rtca3_ppb_per_cycle by fixing "adjutment" to "adjustment".
> 
> Signed-off-by: Lad Prabhakar<prabhakar.mahadev-lad.rj@bp.renesas.com>

Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S

^ permalink raw reply

* Re: [PATCH 3/5] rtc: renesas-rtca3: Fix incorrect error message for reset assert
From: Claudiu Beznea @ 2026-06-02  8:32 UTC (permalink / raw)
  To: Prabhakar, Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven
  Cc: linux-rtc, linux-renesas-soc, linux-kernel, Biju Das,
	Fabrizio Castro, Lad Prabhakar
In-Reply-To: <20260506164914.3987293-4-prabhakar.mahadev-lad.rj@bp.renesas.com>



On 5/6/26 19:49, Prabhakar wrote:
> From: Lad Prabhakar<prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> Update the message to "assert reset" to accurately reflect the
> operation being performed.
> 
> Signed-off-by: Lad Prabhakar<prabhakar.mahadev-lad.rj@bp.renesas.com>

Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S

^ permalink raw reply

* Re: [PATCH 2/5] rtc: renesas-rtca3: Check RADJ poll result during initial setup
From: Claudiu Beznea @ 2026-06-02  8:32 UTC (permalink / raw)
  To: Prabhakar, Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven
  Cc: linux-rtc, linux-renesas-soc, linux-kernel, Biju Das,
	Fabrizio Castro, Lad Prabhakar
In-Reply-To: <20260506164914.3987293-3-prabhakar.mahadev-lad.rj@bp.renesas.com>



On 5/6/26 19:49, Prabhakar wrote:
> From: Lad Prabhakar<prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> In rtca3_initial_setup(), the driver clears the RTCA3_RADJ register and
> waits for it to reach zero using readb_poll_timeout(). Check the return
> value of readb_poll_timeout() and propagate the error if the poll fails.
> 
> Signed-off-by: Lad Prabhakar<prabhakar.mahadev-lad.rj@bp.renesas.com>

Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S

^ permalink raw reply

* Re: [PATCH 1/5] rtc: renesas-rtca3: Fix PIE clear polling condition in alarm setup error path
From: Claudiu Beznea @ 2026-06-02  8:31 UTC (permalink / raw)
  To: Prabhakar, Alexandre Belloni, Claudiu Beznea, Geert Uytterhoeven
  Cc: linux-rtc, linux-renesas-soc, linux-kernel, Biju Das,
	Fabrizio Castro, Lad Prabhakar
In-Reply-To: <20260506164914.3987293-2-prabhakar.mahadev-lad.rj@bp.renesas.com>

Hi, Prabhakar,

On 5/6/26 19:49, Prabhakar wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> In rtca3_set_alarm(), the setup_failed path attempts to disable the
> Periodic Interrupt Enable (PIE) bit and wait until it is cleared.
> However, the polling condition passed to readb_poll_timeout_atomic()
> uses an incorrect expression:
> 
>      !(tmp & ~RTCA3_RCR1_PIE)
> 
> As ~RTCA3_RCR1_PIE evaluates to a mask of all bits except PIE, the
> condition effectively waits for all non-PIE bits to become zero, which
> is unrelated to the intended operation and is unlikely to ever be true.
> This causes the poll to time out unnecessarily.
> 
> Fix the condition to check for the PIE bit itself being cleared:
> 
>      !(tmp & RTCA3_RCR1_PIE)
> 
> This correctly waits until PIE is deasserted after being cleared.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S

I think it also deserves a Fixes tag?

Thank you,
Claudiu

^ permalink raw reply

* [PATCH] rtc: mpc5121: replace in_8/out_8 with generic accessors
From: Rosen Penev @ 2026-06-02  4:00 UTC (permalink / raw)
  To: linux-rtc; +Cc: Alexandre Belloni, chleroy, open list

Convert ppc4xx-specific in_8/out_8, in_be16/out_be16 and in_be32/
out_be32 to the portable ioread8/iowrite8, ioread16be/iowrite16be
and ioread32be/iowrite32be respectively.

Add COMPILE_TEST as a result for greater compile coverage.

Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/rtc/Kconfig       |  2 +-
 drivers/rtc/rtc-mpc5121.c | 80 +++++++++++++++++++--------------------
 2 files changed, 41 insertions(+), 41 deletions(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 364afc73f8ab..6d8935250c82 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1779,7 +1779,7 @@ config RTC_DRV_MC13XXX
 
 config RTC_DRV_MPC5121
 	tristate "Freescale MPC5121 built-in RTC"
-	depends on PPC_MPC512x || PPC_MPC52xx
+	depends on PPC_MPC512x || PPC_MPC52xx || COMPILE_TEST
 	help
 	  If you say yes here you will get support for the
 	  built-in RTC on MPC5121 or on MPC5200.
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index b90f8337a7e6..c038301fb86b 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -87,15 +87,15 @@ struct mpc5121_rtc_data {
 static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs,
 				   struct rtc_time *tm)
 {
-	out_8(&regs->second_set, tm->tm_sec);
-	out_8(&regs->minute_set, tm->tm_min);
-	out_8(&regs->hour_set, tm->tm_hour);
+	iowrite8(tm->tm_sec, &regs->second_set);
+	iowrite8(tm->tm_min, &regs->minute_set);
+	iowrite8(tm->tm_hour, &regs->hour_set);
 
 	/* set time sequence */
-	out_8(&regs->set_time, 0x1);
-	out_8(&regs->set_time, 0x3);
-	out_8(&regs->set_time, 0x1);
-	out_8(&regs->set_time, 0x0);
+	iowrite8(0x1, &regs->set_time);
+	iowrite8(0x3, &regs->set_time);
+	iowrite8(0x1, &regs->set_time);
+	iowrite8(0x0, &regs->set_time);
 }
 
 static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -107,7 +107,7 @@ static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
 	/*
 	 * linux time is actual_time plus the offset saved in target_time
 	 */
-	now = in_be32(&regs->actual_time) + in_be32(&regs->target_time);
+	now = ioread32be(&regs->actual_time) + ioread32be(&regs->target_time);
 
 	rtc_time64_to_tm(now, tm);
 
@@ -131,7 +131,7 @@ static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	 * between it and linux time to the target_time register.
 	 */
 	now = rtc_tm_to_time64(tm);
-	out_be32(&regs->target_time, now - in_be32(&regs->actual_time));
+	iowrite32be(now - ioread32be(&regs->actual_time), &regs->target_time);
 
 	/*
 	 * update second minute hour registers
@@ -148,20 +148,20 @@ static int mpc5200_rtc_read_time(struct device *dev, struct rtc_time *tm)
 	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 	int tmp;
 
-	tm->tm_sec = in_8(&regs->second);
-	tm->tm_min = in_8(&regs->minute);
+	tm->tm_sec = ioread8(&regs->second);
+	tm->tm_min = ioread8(&regs->minute);
 
 	/* 12 hour format? */
-	if (in_8(&regs->hour) & 0x20)
-		tm->tm_hour = (in_8(&regs->hour) >> 1) +
-			(in_8(&regs->hour) & 1 ? 12 : 0);
+	if (ioread8(&regs->hour) & 0x20)
+		tm->tm_hour = (ioread8(&regs->hour) >> 1) +
+			(ioread8(&regs->hour) & 1 ? 12 : 0);
 	else
-		tm->tm_hour = in_8(&regs->hour);
+		tm->tm_hour = ioread8(&regs->hour);
 
-	tmp = in_8(&regs->wday_mday);
+	tmp = ioread8(&regs->wday_mday);
 	tm->tm_mday = tmp & 0x1f;
-	tm->tm_mon = in_8(&regs->month) - 1;
-	tm->tm_year = in_be16(&regs->year) - 1900;
+	tm->tm_mon = ioread8(&regs->month) - 1;
+	tm->tm_year = ioread16be(&regs->year) - 1900;
 	tm->tm_wday = (tmp >> 5) % 7;
 	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
 	tm->tm_isdst = 0;
@@ -177,16 +177,16 @@ static int mpc5200_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	mpc5121_rtc_update_smh(regs, tm);
 
 	/* date */
-	out_8(&regs->month_set, tm->tm_mon + 1);
-	out_8(&regs->weekday_set, tm->tm_wday ? tm->tm_wday : 7);
-	out_8(&regs->date_set, tm->tm_mday);
-	out_be16(&regs->year_set, tm->tm_year + 1900);
+	iowrite8(tm->tm_mon + 1, &regs->month_set);
+	iowrite8(tm->tm_wday ? tm->tm_wday : 7, &regs->weekday_set);
+	iowrite8(tm->tm_mday, &regs->date_set);
+	iowrite16be(tm->tm_year + 1900, &regs->year_set);
 
 	/* set date sequence */
-	out_8(&regs->set_date, 0x1);
-	out_8(&regs->set_date, 0x3);
-	out_8(&regs->set_date, 0x1);
-	out_8(&regs->set_date, 0x0);
+	iowrite8(0x1, &regs->set_date);
+	iowrite8(0x3, &regs->set_date);
+	iowrite8(0x1, &regs->set_date);
+	iowrite8(0x0, &regs->set_date);
 
 	return 0;
 }
@@ -198,7 +198,7 @@ static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 
 	*alarm = rtc->wkalarm;
 
-	alarm->pending = in_8(&regs->alm_status);
+	alarm->pending = ioread8(&regs->alm_status);
 
 	return 0;
 }
@@ -212,10 +212,10 @@ static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 	alarm->time.tm_mon = -1;
 	alarm->time.tm_year = -1;
 
-	out_8(&regs->alm_min_set, alarm->time.tm_min);
-	out_8(&regs->alm_hour_set, alarm->time.tm_hour);
+	iowrite8(alarm->time.tm_min, &regs->alm_min_set);
+	iowrite8(alarm->time.tm_hour, &regs->alm_hour_set);
 
-	out_8(&regs->alm_enable, alarm->enabled);
+	iowrite8(alarm->enabled, &regs->alm_enable);
 
 	rtc->wkalarm = *alarm;
 	return 0;
@@ -226,10 +226,10 @@ static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
 	struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
 	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 
-	if (in_8(&regs->int_alm)) {
+	if (ioread8(&regs->int_alm)) {
 		/* acknowledge and clear status */
-		out_8(&regs->int_alm, 1);
-		out_8(&regs->alm_status, 1);
+		iowrite8(1, &regs->int_alm);
+		iowrite8(1, &regs->alm_status);
 
 		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
 		return IRQ_HANDLED;
@@ -243,9 +243,9 @@ static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
 	struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
 	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 
-	if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)) {
+	if (ioread8(&regs->int_sec) && (ioread8(&regs->int_enable) & 0x1)) {
 		/* acknowledge */
-		out_8(&regs->int_sec, 1);
+		iowrite8(1, &regs->int_sec);
 
 		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
 		return IRQ_HANDLED;
@@ -266,7 +266,7 @@ static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
 	else
 		val = 0;
 
-	out_8(&regs->alm_enable, val);
+	iowrite8(val, &regs->alm_enable);
 	rtc->wkalarm.enabled = val;
 
 	return 0;
@@ -340,11 +340,11 @@ static int mpc5121_rtc_probe(struct platform_device *op)
 
 	if (of_device_is_compatible(op->dev.of_node, "fsl,mpc5121-rtc")) {
 		u32 ka;
-		ka = in_be32(&rtc->regs->keep_alive);
+		ka = ioread32be(&rtc->regs->keep_alive);
 		if (ka & 0x02) {
 			dev_warn(&op->dev,
 				"mpc5121-rtc: Battery or oscillator failure!\n");
-			out_be32(&rtc->regs->keep_alive, ka);
+			iowrite32be(ka, &rtc->regs->keep_alive);
 		}
 		rtc->rtc->ops = &mpc5121_rtc_ops;
 		/*
@@ -376,8 +376,8 @@ static void mpc5121_rtc_remove(struct platform_device *op)
 	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 
 	/* disable interrupt, so there are no nasty surprises */
-	out_8(&regs->alm_enable, 0);
-	out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
+	iowrite8(0, &regs->alm_enable);
+	iowrite8(ioread8(&regs->int_enable) & ~0x1, &regs->int_enable);
 
 	irq_dispose_mapping(rtc->irq);
 	irq_dispose_mapping(rtc->irq_periodic);
-- 
2.54.0


^ permalink raw reply related

* [PATCH] rtc: pcf8563: fix clock provider leak on unbind
From: Yi Ding @ 2026-06-02  3:51 UTC (permalink / raw)
  To: Alexandre Belloni; +Cc: Heiko Schocher, linux-rtc, linux-kernel, Yi Ding

pcf8563_clkout_register_clk() registers the CLKOUT clock provider with
of_clk_add_provider(), but nothing ever unwinds it: there is no
of_clk_del_provider() call and the driver has no remove callback. Each
of_clk_add_provider() allocates a struct of_clk_provider, takes a
reference on the OF node and adds an entry to the global of_clk_providers
list, none of which is released when the device is unbound. Every
bind/unbind (or module reload) therefore leaks a provider structure and
an of_node reference.

The clock itself is already device-managed (devm_clk_register()); only
the provider registration was not. Use devm_of_clk_add_hw_provider() so
the provider is removed automatically on unbind. Tie it to the parent
i2c device, whose OF node carries the #clock-cells and clock-output-names
properties (the RTC class device has no OF node of its own).

Fixes: a39a6405d5f9 ("rtc: pcf8563: add CLKOUT to common clock framework")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Yi Ding <yi.s.ding@gmail.com>
---
 drivers/rtc/rtc-pcf8563.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index b281e9489..7083d9278 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -449,7 +449,9 @@ static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
 	clk = devm_clk_register(&pcf8563->rtc->dev, &pcf8563->clkout_hw);
 
 	if (!IS_ERR(clk))
-		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+		devm_of_clk_add_hw_provider(pcf8563->rtc->dev.parent,
+					    of_clk_hw_simple_get,
+					    &pcf8563->clkout_hw);
 
 	return clk;
 }
-- 
2.47.3


^ permalink raw reply related

* [PATCH v1] rtc: m41t80: clean up watchdog on probe failure
From: Yuho Choi @ 2026-06-01 19:46 UTC (permalink / raw)
  To: Alexandre Belloni; +Cc: linux-rtc, linux-kernel, Yuho Choi

m41t80_probe() registers the watchdog misc device and reboot notifier
before registering the RTC device. If RTC device registration fails,
probe returns without calling m41t80_remove(), leaving the watchdog misc
device and reboot notifier registered.

Both watchdog paths use the global save_client pointer, which can
outlive the failed probe and point at driver state that has been
released by devres.

Unregister the watchdog misc device and reboot notifier before returning
from the RTC registration failure path.

Fixes: 10d0c768cc6d ("rtc: m41t80: fix race conditions")
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
---
 drivers/rtc/rtc-m41t80.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index b26afef37d9c..f4a30320c6ed 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -1009,9 +1009,17 @@ static int m41t80_probe(struct i2c_client *client)
 
 	rc = devm_rtc_register_device(m41t80_data->rtc);
 	if (rc)
-		return rc;
+		goto err_wdt;
 
 	return 0;
+err_wdt:
+#ifdef CONFIG_RTC_DRV_M41T80_WDT
+	if (m41t80_data->features & M41T80_FEATURE_HT) {
+		misc_deregister(&wdt_dev);
+		unregister_reboot_notifier(&wdt_notifier);
+	}
+#endif
+	return rc;
 }
 
 static void m41t80_remove(struct i2c_client *client)
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH v4] dt-bindings: clock: via,vt8500: Convert to DT Schema
From: Krzysztof Kozlowski @ 2026-06-01 11:44 UTC (permalink / raw)
  To: Uday Kiran
  Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, skhan, me, linux-rtc,
	devicetree, linux-kernel
In-Reply-To: <CAAj-GBmNXvTNbnQ8hOzsjnQd0Oi4a17LY8yjb8HTbD4PpTXH3Q@mail.gmail.com>

On 31/05/2026 18:49, Uday Kiran wrote:
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/clock/via,vt8500-clock.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: VIA/Wondermedia VT8500 Clock Controller
>>
>> How PMC is a clock controller? Really?
> 
> No Krzysztof, actually that was a wrong direction in v4.
> 
>>> +
>>> +maintainers:
>>> +  - Michael Turquette <mturquette@baylibre.com>
>>> +  - Stephen Boyd <sboyd@kernel.org>
>>
>>
>> Subsystem maintainers do not care about PMC. This can be platform
>> maintainer.
> 
> I agree with you. I changed maintainers accordingly.
> 
>>> +
>>> +description:
>>> +  Clock controller bindings for VIA/Wondermedia VT8500 and Wondermedia WM8xxx
>>> +  series SoCs.
>>> +
>>> +select:
>>> +  properties:
>>> +    compatible:
>>> +      const: via,vt8500-pmc
>>> +
>>> +  required:
>>> +    - compatible
>>
>> Why do you have select?
>>
>> I don't understand your changes. This was not at v2 and I did not ask to
>> change that.
> 
> The select: block with via,vt8500-pmc and the clocks: type: object were
> mistakenly added to via,vt8500-clock.yaml in v4 — leftover confusion from
> trying to handle the PMC node's clock container in the same schema. In v5 these
> are removed from the clock schema entirely. The PMC binding is now a separate
> patch (via,vt8500-pmc.yaml) which is the right place for the clock container
> node description.
> 
>>> +
>>> +properties:
>>> +  compatible:
>>> +    const: via,vt8500-pmc
>>
>>
>> So via,vt8500-clock.yaml or pmc? Why aren't you removing the pmc file?
>> Why is this located at clocks?
> 
> In the next revision, this patch is scope only to the clock provider bindings
> (via,vt8500-device-clock, via,vt8500-pll-clock, wm,*-pll-clock). It no longer
> models PMC/top-level node properties and does not modify PMC binding files.
> 
>>> +
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +  clocks:
>>> +    type: object
>>> +    additionalProperties: true
>>
>> No, this cannot be "true".
> 
> Agreed, I dropped that structure and kept strict schema validation.

So open v5 and tell me how did you solve "this cannot be 'true'", part?

Best regards,
Krzysztof

^ permalink raw reply


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