* [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 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, 1 reply; 4+ 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 [flat|nested] 4+ 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
1 sibling, 0 replies; 4+ 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 [flat|nested] 4+ messages in thread