Linux RTC
 help / color / mirror / Atom feed
* [PATCH 0/2] rtc: mt6397: provide the RTC's 32 kHz output as a clock
@ 2026-11-02  5:33 Ryan Brue
  2026-11-02  5:33 ` [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's 32 kHz output Ryan Brue
  2026-11-02  5:33 ` [PATCH 2/2] rtc: mt6397: provide the 32 kHz output as a clock Ryan Brue
  0 siblings, 2 replies; 7+ messages in thread
From: Ryan Brue @ 2026-11-02  5:33 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

The MT6397 RTC drives a 32 kHz clock out of the PMIC, which boards use as
the sleep clock of a Wi-Fi/Bluetooth combo chip. RTC_CON.F32KOB gates it,
and mainline never touches that bit, so the chip only works if the
bootloader happened to turn the output on.

On the Amazon Fire HD 10 (2017), which can boot through U-Boot instead of
the vendor's LK, nothing sets it in the former - the bit is set at every
boot, and the MT6630 combo chip's Wi-Fi and Bluetooth never come up.
Letting the RTC provide the output as a clock lets the chip's
mmc-pwrseq-simple enable it. With the clock wired up both came up on that
board in two boots out of two, and in none of three without it.

The driver registers the clock only when the RTC node has #clock-cells,
so no existing board changes. The MT6323 shares the MT6397's driver data
and gets it too; every MediaTek PMIC RTC whose registers I could read has
F32KOB at bit 5 of RTC_CON, but for the MT6323 that is inferred from the
shared driver data rather than read from a datasheet.

Both patches apply on top of the RTC nvmem layout pair, new in
v7.4-rc1. That pair went through both rtc and mfd, so I'd suggest these
two go through rtc only, with Lee's ack on patch 1, if that works for
everyone.

The board's devicetree that uses the clock is not upstream yet and follows
separately.

This series was developed with the help of an LLM.

Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
Ryan Brue (2):
      dt-bindings: mfd: mediatek: mt6397: describe the RTC's 32 kHz output
      rtc: mt6397: provide the 32 kHz output as a clock

 .../devicetree/bindings/mfd/mediatek,mt6397.yaml   |  6 ++
 drivers/rtc/rtc-mt6397.c                           | 85 ++++++++++++++++++++++
 include/linux/mfd/mt6397/rtc.h                     |  6 ++
 3 files changed, 97 insertions(+)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261024-rbrue-suez-upstreaming-mt6397-rtc-32k-0a1c16f63383

Best regards,
-- 
Ryan Brue <ryanbrue.dev@gmail.com>


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

* [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's 32 kHz output
  2026-11-02  5:33 [PATCH 0/2] rtc: mt6397: provide the RTC's 32 kHz output as a clock Ryan Brue
@ 2026-11-02  5:33 ` Ryan Brue
  2026-11-02  5:37   ` sashiko-bot
  2026-11-02  7:47   ` Krzysztof Kozlowski
  2026-11-02  5:33 ` [PATCH 2/2] rtc: mt6397: provide the 32 kHz output as a clock Ryan Brue
  1 sibling, 2 replies; 7+ messages in thread
From: Ryan Brue @ 2026-11-02  5:33 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

The MT6397 RTC drives its 32 kHz clock out of the PMIC, where boards
use it as the sleep clock of a Wi-Fi/Bluetooth combo chip. The output
is off unless something turns it on.

Let the RTC node provide it as a clock.

Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
 Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
index 055625362951..3bfe1ad60d2d 100644
--- a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
@@ -84,6 +84,11 @@ properties:
 
       start-year: true
 
+      "#clock-cells":
+        description:
+          The 32 kHz clock the RTC drives out to other chips.
+        const: 0
+
       nvmem-layout:
         $ref: /schemas/nvmem/layouts/nvmem-layout.yaml
         description:
@@ -694,5 +699,6 @@ examples:
 
         rtc {
             compatible = "mediatek,mt6397-rtc";
+            #clock-cells = <0>;
         };
     };

-- 
2.55.0


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

* [PATCH 2/2] rtc: mt6397: provide the 32 kHz output as a clock
  2026-11-02  5:33 [PATCH 0/2] rtc: mt6397: provide the RTC's 32 kHz output as a clock Ryan Brue
  2026-11-02  5:33 ` [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's 32 kHz output Ryan Brue
@ 2026-11-02  5:33 ` Ryan Brue
  2026-11-02  5:44   ` sashiko-bot
  1 sibling, 1 reply; 7+ messages in thread
From: Ryan Brue @ 2026-11-02  5:33 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

The RTC's 32 kHz output is gated by RTC_CON.F32KOB, which the vendor
kernel clears before it powers the Wi-Fi/Bluetooth combo chip. Mainline
never touches it, so on a board whose bootloader leaves it set, such a
chip has no sleep clock and does not come up.

Register the output as a clock when the RTC node has #clock-cells, so
the chip's power sequence can enable it.

Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
 drivers/rtc/rtc-mt6397.c       | 85 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/mt6397/rtc.h |  6 +++
 2 files changed, 91 insertions(+)

diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
index d6e156516aa6..5130fecffa7b 100644
--- a/drivers/rtc/rtc-mt6397.c
+++ b/drivers/rtc/rtc-mt6397.c
@@ -6,6 +6,7 @@
 
 #include <linux/array_size.h>
 #include <linux/bitfield.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/mt6397/core.h>
@@ -317,6 +318,84 @@ static int mtk_rtc_nvram_write(void *priv, unsigned int offset, void *val,
 	return ret;
 }
 
+#ifdef CONFIG_COMMON_CLK
+static int mtk_rtc_clkout_set(struct clk_hw *hw, bool on)
+{
+	struct mt6397_rtc *rtc = container_of(hw, struct mt6397_rtc, clkout);
+	int ret;
+
+	mutex_lock(&rtc->lock);
+	ret = regmap_update_bits(rtc->regmap, rtc->addr_base + rtc->data->con,
+				 RTC_CON_F32KOB, on ? 0 : RTC_CON_F32KOB);
+	if (!ret)
+		ret = mtk_rtc_write_trigger(rtc);
+	mutex_unlock(&rtc->lock);
+
+	return ret;
+}
+
+static int mtk_rtc_clkout_prepare(struct clk_hw *hw)
+{
+	return mtk_rtc_clkout_set(hw, true);
+}
+
+static void mtk_rtc_clkout_unprepare(struct clk_hw *hw)
+{
+	mtk_rtc_clkout_set(hw, false);
+}
+
+static int mtk_rtc_clkout_is_prepared(struct clk_hw *hw)
+{
+	struct mt6397_rtc *rtc = container_of(hw, struct mt6397_rtc, clkout);
+	u32 con;
+
+	if (regmap_read(rtc->regmap, rtc->addr_base + rtc->data->con, &con))
+		return 0;
+
+	return !(con & RTC_CON_F32KOB);
+}
+
+static unsigned long mtk_rtc_clkout_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	return 32768;
+}
+
+static const struct clk_ops mtk_rtc_clkout_ops = {
+	.prepare = mtk_rtc_clkout_prepare,
+	.unprepare = mtk_rtc_clkout_unprepare,
+	.is_prepared = mtk_rtc_clkout_is_prepared,
+	.recalc_rate = mtk_rtc_clkout_recalc_rate,
+};
+
+/* The 32 kHz output the PMIC drives to other chips, such as a combo chip */
+static int mtk_rtc_register_clkout(struct device *dev, struct mt6397_rtc *rtc)
+{
+	struct clk_init_data init = {
+		.name = "mt6397-rtc-32k",
+		.ops = &mtk_rtc_clkout_ops,
+	};
+	int ret;
+
+	if (!rtc->data->con || !of_property_present(dev->of_node, "#clock-cells"))
+		return 0;
+
+	rtc->clkout.init = &init;
+
+	ret = devm_clk_hw_register(dev, &rtc->clkout);
+	if (ret)
+		return ret;
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+					   &rtc->clkout);
+}
+#else
+static int mtk_rtc_register_clkout(struct device *dev, struct mt6397_rtc *rtc)
+{
+	return 0;
+}
+#endif
+
 static int mtk_rtc_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -380,6 +459,11 @@ static int mtk_rtc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	ret = mtk_rtc_register_clkout(&pdev->dev, rtc);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "failed to register the 32k clock\n");
+
 	nvmem_cfg.priv = rtc;
 
 	return devm_rtc_nvmem_register(rtc->rtc_dev, &nvmem_cfg);
@@ -416,6 +500,7 @@ static const struct mtk_rtc_data mt6358_rtc_data = {
 
 static const struct mtk_rtc_data mt6397_rtc_data = {
 	.wrtgr = RTC_WRTGR_MT6397,
+	.con = RTC_CON_MT6397,
 };
 
 static const struct of_device_id mt6397_rtc_of_match[] = {
diff --git a/include/linux/mfd/mt6397/rtc.h b/include/linux/mfd/mt6397/rtc.h
index f4da579ec638..a8130d726c59 100644
--- a/include/linux/mfd/mt6397/rtc.h
+++ b/include/linux/mfd/mt6397/rtc.h
@@ -9,6 +9,7 @@
 #ifndef _LINUX_MFD_MT6397_RTC_H_
 #define _LINUX_MFD_MT6397_RTC_H_
 
+#include <linux/clk-provider.h>
 #include <linux/jiffies.h>
 #include <linux/mutex.h>
 #include <linux/regmap.h>
@@ -22,6 +23,9 @@
 #define RTC_WRTGR_MT6397       0x003c
 #define RTC_WRTGR_MT6323       RTC_WRTGR_MT6397
 
+#define RTC_CON_MT6397         0x003e
+#define RTC_CON_F32KOB         BIT(5)
+
 #define RTC_IRQ_STA            0x0002
 #define RTC_IRQ_STA_AL         BIT(0)
 #define RTC_IRQ_STA_LP         BIT(3)
@@ -72,6 +76,7 @@
 
 struct mtk_rtc_data {
 	u32                     wrtgr;
+	u32                     con;
 };
 
 struct mt6397_rtc {
@@ -83,6 +88,7 @@ struct mt6397_rtc {
 	int                     irq;
 	u32                     addr_base;
 	const struct mtk_rtc_data *data;
+	struct clk_hw           clkout;
 };
 
 #endif /* _LINUX_MFD_MT6397_RTC_H_ */

-- 
2.55.0


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

* Re: [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's 32 kHz output
  2026-11-02  5:33 ` [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's 32 kHz output Ryan Brue
@ 2026-11-02  5:37   ` sashiko-bot
  2026-11-02  7:47   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-11-02  5:37 UTC (permalink / raw)
  To: Ryan Brue; +Cc: mfd, linux-rtc, Alexandre Belloni, lee

> The MT6397 RTC drives its 32 kHz clock out of the PMIC, where boards
> use it as the sleep clock of a Wi-Fi/Bluetooth combo chip. The output
> is off unless something turns it on.
> 
> Let the RTC node provide it as a clock.
> 
> Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261101-rbrue-suez-upstreaming-mt6397-rtc-32k-v1-0-9758f38d7053@gmail.com?part=1


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

* Re: [PATCH 2/2] rtc: mt6397: provide the 32 kHz output as a clock
  2026-11-02  5:33 ` [PATCH 2/2] rtc: mt6397: provide the 32 kHz output as a clock Ryan Brue
@ 2026-11-02  5:44   ` sashiko-bot
  2026-11-02 14:36     ` Ryan Brue
  0 siblings, 1 reply; 7+ messages in thread
From: sashiko-bot @ 2026-11-02  5:44 UTC (permalink / raw)
  To: Ryan Brue
  Cc: mfd, devicetree, linux-rtc, robh, conor+dt, Alexandre Belloni,
	lee

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] rtc: mt6397: NULL dereference of rtc->data in mtk_rtc_register_clkout()
--

commit 7a674b1fa23c59043354cce078b81b55651fd9c2
Author: Ryan Brue <ryanbrue.dev@gmail.com>

rtc: mt6397: provide the 32 kHz output as a clock

This commit registers the MT6397 RTC's 32 kHz output gated by RTC_CON.F32KOB
as a clock provider when the RTC node specifies #clock-cells, allowing client
devices such as Wi-Fi/Bluetooth combo chips to enable their sleep clock.

> diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
> index d6e156516aa6c..5130fecffa7b4 100644
> --- a/drivers/rtc/rtc-mt6397.c
> +++ b/drivers/rtc/rtc-mt6397.c
[ ... ]
> @@ -317,6 +318,84 @@ static int mtk_rtc_nvram_write(void *priv, unsigned int offset, void *val,
[ ... ]
> +/* The 32 kHz output the PMIC drives to other chips, such as a combo chip */
> +static int mtk_rtc_register_clkout(struct device *dev, struct mt6397_rtc *rtc)
> +{
> +	struct clk_init_data init = {
> +		.name = "mt6397-rtc-32k",
> +		.ops = &mtk_rtc_clkout_ops,
> +	};
> +	int ret;
> +
> +	if (!rtc->data->con || !of_property_present(dev->of_node, "#clock-cells"))
> +		return 0;

[Severity: High]
Can this dereference a NULL rtc->data pointer during mtk_rtc_probe()?

In drivers/mfd/mt6397-core.c, mt6397_devs[] unconditionally registers the
mt6397-rtc MFD cell:

    {
        .name = "mt6397-rtc",
        .num_resources = ARRAY_SIZE(mt6397_rtc_resources),
        .resources = mt6397_rtc_resources,
        .of_compatible = "mediatek,mt6397-rtc",
    }

On MT6397 boards whose Device Tree omits the optional mediatek,mt6397-rtc
child node under the PMIC node (such as mt8173-evb.dts and mt8135-evbp1.dts),
mfd_add_device() registers the mt6397-rtc platform device with
pdev->dev.of_node set to NULL. Because mtk_rtc_driver has .driver.name set to
"mt6397-rtc" and no id_table, platform_match() binds the device via the
driver-name fallback and invokes mtk_rtc_probe():

drivers/rtc/rtc-mt6397.c:mtk_rtc_probe() {
    ...
    rtc->data = of_device_get_match_data(&pdev->dev);
    ...
    ret = mtk_rtc_register_clkout(&pdev->dev, rtc);
}

When pdev->dev.of_node is NULL, of_device_get_match_data() returns NULL.
Previously, mtk_rtc_probe() never dereferenced rtc->data during probe,
whereas mtk_rtc_register_clkout() now evaluates !rtc->data->con before
checking dev->of_node or whether rtc->data is NULL.

Should mtk_rtc_register_clkout() check !rtc->data (or check
of_property_present() first), or should mtk_rtc_probe() handle a NULL
rtc->data?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261101-rbrue-suez-upstreaming-mt6397-rtc-32k-v1-0-9758f38d7053@gmail.com?part=2

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

* Re: [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's 32 kHz output
  2026-11-02  5:33 ` [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's 32 kHz output Ryan Brue
  2026-11-02  5:37   ` sashiko-bot
@ 2026-11-02  7:47   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 7+ messages in thread
From: Krzysztof Kozlowski @ 2026-11-02  7:47 UTC (permalink / raw)
  To: Ryan Brue, 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

On 02/11/2026 06:33, Ryan Brue wrote:
> The MT6397 RTC drives its 32 kHz clock out of the PMIC, where boards
> use it as the sleep clock of a Wi-Fi/Bluetooth combo chip. The output
> is off unless something turns it on.
> 
> Let the RTC node provide it as a clock.
> 
> Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
> ---
>  Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml | 6 ++++++
>  1 file changed, 6 insertions(+)

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

Best regards,
Krzysztof

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

* Re: [PATCH 2/2] rtc: mt6397: provide the 32 kHz output as a clock
  2026-11-02  5:44   ` sashiko-bot
@ 2026-11-02 14:36     ` Ryan Brue
  0 siblings, 0 replies; 7+ messages in thread
From: Ryan Brue @ 2026-11-02 14:36 UTC (permalink / raw)
  To: sashiko-reviews
  Cc: mfd, devicetree, linux-rtc, robh, conor+dt, Alexandre Belloni,
	lee

On 11/1/26 11:44 PM, sashiko-bot@kernel.org wrote:
> When pdev->dev.of_node is NULL, of_device_get_match_data() returns NULL.
> Previously, mtk_rtc_probe() never dereferenced rtc->data during probe,
> whereas mtk_rtc_register_clkout() now evaluates !rtc->data->con before
> checking dev->of_node or whether rtc->data is NULL.
>
> Should mtk_rtc_register_clkout() check !rtc->data (or check
> of_property_present() first), or should mtk_rtc_probe() handle a NULL
> rtc->data?
>

Yes, good find, my bad. I'll send out a v2 fixing this.

--
Ryan Brue

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

end of thread, other threads:[~2026-11-02 14:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02  5:33 [PATCH 0/2] rtc: mt6397: provide the RTC's 32 kHz output as a clock Ryan Brue
2026-11-02  5:33 ` [PATCH 1/2] dt-bindings: mfd: mediatek: mt6397: describe the RTC's 32 kHz output Ryan Brue
2026-11-02  5:37   ` sashiko-bot
2026-11-02  7:47   ` Krzysztof Kozlowski
2026-11-02  5:33 ` [PATCH 2/2] rtc: mt6397: provide the 32 kHz output as a clock Ryan Brue
2026-11-02  5:44   ` sashiko-bot
2026-11-02 14:36     ` Ryan Brue

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