* [PATCH 0/2] rtc: mt6397: expose the RTC's spare bytes as nvmem
@ 2026-09-18 4:57 Ryan Brue
2026-09-18 4:57 ` [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's nvmem layout Ryan Brue
2026-09-18 4:57 ` [PATCH 2/2] rtc: mt6397: expose the spare bytes of the alarm registers as nvmem Ryan Brue
0 siblings, 2 replies; 5+ messages in thread
From: Ryan Brue @ 2026-09-18 4:57 UTC (permalink / raw)
To: Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Eddie Huang, Alexandre Belloni
Cc: linux-pm, mfd, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-rtc, Ryan Brue
Four of the MT6397 RTC's alarm registers use only their low bits. Each alarm
field lives in the low byte of its own register and the driver masks its
writes accordingly, so the high byte of four of them is storage the clock and
the alarm never touch. MediaTek's documentation names them RTC_NEW_SPARE0 to
RTC_NEW_SPARE3 and assigns the first to a fuel gauge, which is how its PMIC
battery drivers carry a state of charge across a reboot.
These patches describe that layout in the binding and expose all four bytes
from the RTC driver as a battery-backed nvmem provider. Doing it here rather
than in the consumer is the point: a write then lands under the same lock the
alarm paths take, so it can neither be lost inside mtk_rtc_set_alarm()'s
read-modify-write nor fire the write trigger in the middle of one.
There is no in-tree consumer yet. The one this is for is an MT6397 fuel gauge
that is not ready to post; its other dependency, the MT6397 PMIC AUXADC, is
on the list now [1]. Offering the provider ahead of the consumer follows what
the subsystem already does -- 32 drivers under drivers/rtc register nvmem --
and it is the part that has to exist before a battery driver can stop reaching
into this block behind the RTC's back.
Tested on an MT6397, in an Amazon Fire HD 10 (2017). MediaTek's spare map for
the mt6323 matches, and the alarm field masks are common to every compatible
this driver binds.
[1] https://lore.kernel.org/all/20260917-rbrue-suez-upstreaming-mt6397-auxadc-v2-0-db35882a6080@gmail.com/
Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
Ryan Brue (2):
dt-bindings: mfd: mediatek: mt6397: describe the RTC's nvmem layout
rtc: mt6397: expose the spare bytes of the alarm registers as nvmem
.../devicetree/bindings/mfd/mediatek,mt6397.yaml | 9 +++
drivers/rtc/rtc-mt6397.c | 91 +++++++++++++++++++++-
include/linux/mfd/mt6397/rtc.h | 7 ++
3 files changed, 106 insertions(+), 1 deletion(-)
---
base-commit: fd73f4a6659897191fa0d40695fe370925dd3780
change-id: 20260917-rbrue-suez-upstreaming-mt6397-rtc-nvmem-ee2a326ad7f2
Best regards,
--
Ryan Brue <ryanbrue.dev@gmail.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's nvmem layout
2026-09-18 4:57 [PATCH 0/2] rtc: mt6397: expose the RTC's spare bytes as nvmem Ryan Brue
@ 2026-09-18 4:57 ` Ryan Brue
2026-09-21 10:37 ` AngeloGioacchino Del Regno
2026-09-18 4:57 ` [PATCH 2/2] rtc: mt6397: expose the spare bytes of the alarm registers as nvmem Ryan Brue
1 sibling, 1 reply; 5+ messages in thread
From: Ryan Brue @ 2026-09-18 4:57 UTC (permalink / raw)
To: Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Eddie Huang, Alexandre Belloni
Cc: linux-pm, mfd, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-rtc, Ryan Brue
Four of the MT6397 RTC's alarm registers use only their low bits; the
high byte of each is storage the clock and the alarm don't touch.
MediaTek's documentation names them RTC_NEW_SPARE0 to RTC_NEW_SPARE3 and
assigns the first to a fuel gauge, which is what a battery driver reads
at boot so that the reported capacity does not jump across a reboot.
They sit in the RTC's always-on domain, so the driver can offer them as
a battery-backed nvmem provider. Allow a board to lay cells out over
them.
Assisted-by: LLM
Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
index 3cbc0dc12c31..5c89c589b53c 100644
--- a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
@@ -81,6 +81,15 @@ properties:
start-year: true
+ nvmem-layout:
+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml
+ description:
+ The RTC carries four bytes of storage that neither the clock nor the
+ alarm uses, in the high half of four of the alarm registers, and
+ offers them as a battery-backed nvmem provider. MediaTek's
+ documentation names them RTC_NEW_SPARE0 to RTC_NEW_SPARE3 and gives
+ the first to a fuel gauge.
+
required:
- compatible
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/2] rtc: mt6397: expose the spare bytes of the alarm registers as nvmem
2026-09-18 4:57 [PATCH 0/2] rtc: mt6397: expose the RTC's spare bytes as nvmem Ryan Brue
2026-09-18 4:57 ` [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's nvmem layout Ryan Brue
@ 2026-09-18 4:57 ` Ryan Brue
2026-09-21 10:37 ` AngeloGioacchino Del Regno
1 sibling, 1 reply; 5+ messages in thread
From: Ryan Brue @ 2026-09-18 4:57 UTC (permalink / raw)
To: Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Eddie Huang, Alexandre Belloni
Cc: linux-pm, mfd, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-rtc, Ryan Brue
Each alarm field lives in the low bits of its register and the driver
masks its writes accordingly, so the high byte of four of them is storage
the RTC never touches. MediaTek names these RTC_NEW_SPARE0 to
RTC_NEW_SPARE3 and gives the first to a fuel gauge, which is how its PMIC
battery drivers carry a state of charge over a reboot.
Offer all four as a battery-backed nvmem provider, so that a consumer does
not have to reach into this block behind the driver's back. Doing it here
is what makes it safe: a write lands under the same lock the alarm paths
take, so it can neither be lost inside mtk_rtc_set_alarm()'s
read-modify-write nor fire the write trigger in the middle of one.
The nvmem core does not range check a cell against the provider size, so
the callbacks check the offset themselves.
Tested on an MT6397; MediaTek's spare map for mt6323 matches, and the
alarm field masks are common to every compatible this driver binds.
Assisted-by: LLM
Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
drivers/rtc/rtc-mt6397.c | 91 +++++++++++++++++++++++++++++++++++++++++-
include/linux/mfd/mt6397/rtc.h | 7 ++++
2 files changed, 97 insertions(+), 1 deletion(-)
diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
index 3d857681f760..d6e156516aa6 100644
--- a/drivers/rtc/rtc-mt6397.c
+++ b/drivers/rtc/rtc-mt6397.c
@@ -4,6 +4,8 @@
* Author: Tianping.Fang <tianping.fang@mediatek.com>
*/
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/mfd/mt6397/core.h>
@@ -243,10 +245,91 @@ static const struct rtc_class_ops mtk_rtc_ops = {
.set_alarm = mtk_rtc_set_alarm,
};
+/*
+ * The spare byte of each of these registers, in the order a board addresses
+ * them as RTC_NEW_SPARE0 to RTC_NEW_SPARE3.
+ */
+static const u32 mtk_rtc_spare_reg[] = {
+ RTC_AL_HOU, RTC_AL_DOM, RTC_AL_DOW, RTC_AL_MTH,
+};
+
+static int mtk_rtc_nvram_read(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ struct mt6397_rtc *rtc = priv;
+ u8 *buf = val;
+ u32 data;
+ int ret = 0;
+
+ if (offset >= ARRAY_SIZE(mtk_rtc_spare_reg) ||
+ bytes > ARRAY_SIZE(mtk_rtc_spare_reg) - offset)
+ return -EINVAL;
+
+ mutex_lock(&rtc->lock);
+
+ while (bytes--) {
+ ret = regmap_read(rtc->regmap,
+ rtc->addr_base + mtk_rtc_spare_reg[offset++],
+ &data);
+ if (ret)
+ break;
+
+ *buf++ = FIELD_GET(RTC_SPARE_MASK, data);
+ }
+
+ mutex_unlock(&rtc->lock);
+
+ return ret;
+}
+
+static int mtk_rtc_nvram_write(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ struct mt6397_rtc *rtc = priv;
+ u8 *buf = val;
+ int ret = 0;
+
+ if (offset >= ARRAY_SIZE(mtk_rtc_spare_reg) ||
+ bytes > ARRAY_SIZE(mtk_rtc_spare_reg) - offset)
+ return -EINVAL;
+
+ mutex_lock(&rtc->lock);
+
+ while (bytes--) {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->addr_base + mtk_rtc_spare_reg[offset++],
+ RTC_SPARE_MASK,
+ FIELD_PREP(RTC_SPARE_MASK, *buf++));
+ if (ret)
+ goto out;
+ }
+
+ /*
+ * None of it reaches the always-on domain until the write trigger,
+ * which commits every pending alarm register at once -- so this runs
+ * under the same lock the alarm paths take, rather than landing in
+ * the middle of one of them.
+ */
+ ret = mtk_rtc_write_trigger(rtc);
+out:
+ mutex_unlock(&rtc->lock);
+
+ return ret;
+}
+
static int mtk_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent);
+ struct nvmem_config nvmem_cfg = {
+ .name = "mt6397_rtc_spare",
+ .word_size = 1,
+ .stride = 1,
+ .size = ARRAY_SIZE(mtk_rtc_spare_reg),
+ .type = NVMEM_TYPE_BATTERY_BACKED,
+ .reg_read = mtk_rtc_nvram_read,
+ .reg_write = mtk_rtc_nvram_write,
+ };
struct mt6397_rtc *rtc;
int ret;
@@ -293,7 +376,13 @@ static int mtk_rtc_probe(struct platform_device *pdev)
rtc->rtc_dev->start_secs = mktime64(1968, 1, 2, 0, 0, 0);
rtc->rtc_dev->set_start_time = true;
- return devm_rtc_register_device(rtc->rtc_dev);
+ ret = devm_rtc_register_device(rtc->rtc_dev);
+ if (ret)
+ return ret;
+
+ nvmem_cfg.priv = rtc;
+
+ return devm_rtc_nvmem_register(rtc->rtc_dev, &nvmem_cfg);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/mfd/mt6397/rtc.h b/include/linux/mfd/mt6397/rtc.h
index 27883af44f87..f4da579ec638 100644
--- a/include/linux/mfd/mt6397/rtc.h
+++ b/include/linux/mfd/mt6397/rtc.h
@@ -49,6 +49,13 @@
#define RTC_AL_SEC 0x0018
+/* The high byte of four of the alarms is spare, always-on storage */
+#define RTC_AL_HOU 0x001c
+#define RTC_AL_DOM 0x001e
+#define RTC_AL_DOW 0x0020
+#define RTC_AL_MTH 0x0022
+#define RTC_SPARE_MASK GENMASK(15, 8)
+
#define RTC_AL_SEC_MASK 0x003f
#define RTC_AL_MIN_MASK 0x003f
#define RTC_AL_HOU_MASK 0x001f
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] rtc: mt6397: expose the spare bytes of the alarm registers as nvmem
2026-09-18 4:57 ` [PATCH 2/2] rtc: mt6397: expose the spare bytes of the alarm registers as nvmem Ryan Brue
@ 2026-09-21 10:37 ` AngeloGioacchino Del Regno
0 siblings, 0 replies; 5+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-09-21 10:37 UTC (permalink / raw)
To: Ryan Brue, Sen Chu, Sean Wang, Macpaul Lin, Lee Jones,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
Eddie Huang, Alexandre Belloni
Cc: linux-pm, mfd, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-rtc
On 9/18/26 06:57, Ryan Brue wrote:
> Each alarm field lives in the low bits of its register and the driver
> masks its writes accordingly, so the high byte of four of them is storage
> the RTC never touches. MediaTek names these RTC_NEW_SPARE0 to
> RTC_NEW_SPARE3 and gives the first to a fuel gauge, which is how its PMIC
> battery drivers carry a state of charge over a reboot.
>
> Offer all four as a battery-backed nvmem provider, so that a consumer does
> not have to reach into this block behind the driver's back. Doing it here
> is what makes it safe: a write lands under the same lock the alarm paths
> take, so it can neither be lost inside mtk_rtc_set_alarm()'s
> read-modify-write nor fire the write trigger in the middle of one.
>
> The nvmem core does not range check a cell against the provider size, so
> the callbacks check the offset themselves.
>
> Tested on an MT6397; MediaTek's spare map for mt6323 matches, and the
> alarm field masks are common to every compatible this driver binds.
>
> Assisted-by: LLM
> Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's nvmem layout
2026-09-18 4:57 ` [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's nvmem layout Ryan Brue
@ 2026-09-21 10:37 ` AngeloGioacchino Del Regno
0 siblings, 0 replies; 5+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-09-21 10:37 UTC (permalink / raw)
To: Ryan Brue, Sen Chu, Sean Wang, Macpaul Lin, Lee Jones,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
Eddie Huang, Alexandre Belloni
Cc: linux-pm, mfd, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-rtc
On 9/18/26 06:57, Ryan Brue wrote:
> Four of the MT6397 RTC's alarm registers use only their low bits; the
> high byte of each is storage the clock and the alarm don't touch.
> MediaTek's documentation names them RTC_NEW_SPARE0 to RTC_NEW_SPARE3 and
> assigns the first to a fuel gauge, which is what a battery driver reads
> at boot so that the reported capacity does not jump across a reboot.
>
> They sit in the RTC's always-on domain, so the driver can offer them as
> a battery-backed nvmem provider. Allow a board to lay cells out over
> them.
>
> Assisted-by: LLM
> Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
Makes a lot of sense to me.
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
> index 3cbc0dc12c31..5c89c589b53c 100644
> --- a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
> +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
> @@ -81,6 +81,15 @@ properties:
>
> start-year: true
>
> + nvmem-layout:
> + $ref: /schemas/nvmem/layouts/nvmem-layout.yaml
> + description:
> + The RTC carries four bytes of storage that neither the clock nor the
> + alarm uses, in the high half of four of the alarm registers, and
> + offers them as a battery-backed nvmem provider. MediaTek's
> + documentation names them RTC_NEW_SPARE0 to RTC_NEW_SPARE3 and gives
> + the first to a fuel gauge.
> +
> required:
> - compatible
>
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-21 10:37 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18 4:57 [PATCH 0/2] rtc: mt6397: expose the RTC's spare bytes as nvmem Ryan Brue
2026-09-18 4:57 ` [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's nvmem layout Ryan Brue
2026-09-21 10:37 ` AngeloGioacchino Del Regno
2026-09-18 4:57 ` [PATCH 2/2] rtc: mt6397: expose the spare bytes of the alarm registers as nvmem Ryan Brue
2026-09-21 10:37 ` AngeloGioacchino Del Regno
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®