* [PATCH v2 0/4] rtc: Add StarFive JH7110 RTC support
@ 2026-11-08 21:28 Owen O'Hehir
2026-11-08 21:28 ` [PATCH v2 1/4] dt-bindings: rtc: Add StarFive JH7110 RTC Owen O'Hehir
` (3 more replies)
0 siblings, 4 replies; 11+ messages in thread
From: Owen O'Hehir @ 2026-11-08 21:28 UTC (permalink / raw)
To: Alexandre Belloni, linux-rtc
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Philipp Zabel, devicetree, linux-kernel,
linux-riscv, Hal Feng, ziv.xu, Conor Dooley,
Uwe Kleine-König
The JH7110 has an RTC in its always-on domain that mainline does not
support. This series adds a binding, a driver, a MAINTAINERS entry and
the SoC DT node.
The driver is based on the StarFive vendor driver (rtc-starfive.c,
commit ebac2b5 in the StarFive 6.12 tree), reworked for mainline:
- hardware calibration and the default time set in probe are dropped
- wakeup uses the generic wake IRQ helpers instead of the irq_desc hack
- set_time waits for the counter to load the new time
- read_time re-reads if the time rolls over between TIME and DATE
- the offset rounds to the nearest step and follows the sysfs sign
convention (positive = slower)
- the 32.768 kHz counter clock is described in the binding and enabled
Thanks to ziv.xu and Hal Feng at StarFive for the original driver.
Tested on a VisionFive 2 v1.3B with next-20261105 and v7.3.1: setting
and reading the time across the 2000-2099 range (out-of-range years
refused), leap day and century rollover, the alarm interrupt with
cancel, the offset, the rate over 60 s, and setting the system clock at
boot. Not tested: suspend wakeup, drift over hours, and keeping time
across a power-off, as the board has no RTC battery connector.
Known behaviour: the RTC loses about the length of a reboot across a
warm reboot; the counter appears to stop during reset. After the
StarFive vendor kernel the first boot found an invalid time. I would
appreciate an opinion on whether this is expected of the hardware or
something the driver should handle.
Changes in v2:
- dt-bindings: list myself as maintainer instead of the RTC subsystem
maintainer (as requested by Conor)
- MAINTAINERS: new patch adding an entry for the driver & binding
- driver: drop the <linux/mod_devicetable.h> include (as requested by Uwe)
v1: https://lore.kernel.org/r/20261106175600.3877614-0-oo.hehir@gmail.com
Owen O'Hehir (3):
dt-bindings: rtc: Add StarFive JH7110 RTC
MAINTAINERS: Add entry for the StarFive JH7110 RTC driver
riscv: dts: starfive: jh7110: Add the RTC node
ziv.xu (1):
rtc: Add StarFive JH7110 RTC driver
.../bindings/rtc/starfive,jh7110-rtc.yaml | 85 +++++
MAINTAINERS | 7 +
arch/riscv/boot/dts/starfive/jh7110.dtsi | 14 +
drivers/rtc/Kconfig | 11 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-jh7110.c | 323 ++++++++++++++++++
6 files changed, 441 insertions(+)
create mode 100644 Documentation/devicetree/bindings/rtc/starfive,jh7110-rtc.yaml
create mode 100644 drivers/rtc/rtc-jh7110.c
base-commit: ddfe51b0a0f5dc9e415cc2c8ad8db17532dd426b
--
2.43.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 1/4] dt-bindings: rtc: Add StarFive JH7110 RTC
2026-11-08 21:28 [PATCH v2 0/4] rtc: Add StarFive JH7110 RTC support Owen O'Hehir
@ 2026-11-08 21:28 ` Owen O'Hehir
2026-11-08 22:56 ` Conor Dooley
2026-11-08 21:28 ` [PATCH v2 2/4] rtc: Add StarFive JH7110 RTC driver Owen O'Hehir
` (2 subsequent siblings)
3 siblings, 1 reply; 11+ messages in thread
From: Owen O'Hehir @ 2026-11-08 21:28 UTC (permalink / raw)
To: Alexandre Belloni, linux-rtc
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Philipp Zabel, devicetree, linux-kernel,
linux-riscv, Hal Feng, ziv.xu, Conor Dooley,
Uwe Kleine-König
Describe the RTC in the always-on domain of the StarFive JH7110 SoC.
Signed-off-by: Owen O'Hehir <oo.hehir@gmail.com>
---
.../bindings/rtc/starfive,jh7110-rtc.yaml | 85 +++++++++++++++++++
1 file changed, 85 insertions(+)
create mode 100644 Documentation/devicetree/bindings/rtc/starfive,jh7110-rtc.yaml
diff --git a/Documentation/devicetree/bindings/rtc/starfive,jh7110-rtc.yaml b/Documentation/devicetree/bindings/rtc/starfive,jh7110-rtc.yaml
new file mode 100644
index 000000000..a88ab91ab
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/starfive,jh7110-rtc.yaml
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/starfive,jh7110-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JH7110 Real Time Clock
+
+maintainers:
+ - Owen O'Hehir <oo.hehir@gmail.com>
+
+description:
+ The RTC in the always-on domain of the StarFive JH7110 SoC. It counts BCD
+ time and date from a 32.768 kHz clock and has an alarm, a frequency offset
+ adjustment and millisecond and one-second pulse outputs.
+
+allOf:
+ - $ref: rtc.yaml#
+
+properties:
+ compatible:
+ const: starfive,jh7110-rtc
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ items:
+ - description: Millisecond pulse
+ - description: One-second pulse
+ - description: Alarm and calibration events
+
+ interrupt-names:
+ items:
+ - const: ms-pulse
+ - const: sec-pulse
+ - const: rtc
+
+ clocks:
+ items:
+ - description: APB bus clock
+ - description: Calibration reference clock
+ - description: 32.768 kHz counter clock
+
+ clock-names:
+ items:
+ - const: apb
+ - const: cal
+ - const: 32k
+
+ resets:
+ items:
+ - description: 32.768 kHz counter domain reset
+ - description: APB bus reset
+ - description: Calibration reset
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-names
+ - clocks
+ - clock-names
+ - resets
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/starfive,jh7110-crg.h>
+ #include <dt-bindings/reset/starfive,jh7110-crg.h>
+
+ rtc@17040000 {
+ compatible = "starfive,jh7110-rtc";
+ reg = <0x17040000 0x10000>;
+ interrupts = <10>, <11>, <12>;
+ interrupt-names = "ms-pulse", "sec-pulse", "rtc";
+ clocks = <&aoncrg JH7110_AONCLK_RTC_APB>,
+ <&aoncrg JH7110_AONCLK_RTC_CAL>,
+ <&aoncrg JH7110_AONCLK_RTC_32K>;
+ clock-names = "apb", "cal", "32k";
+ resets = <&aoncrg JH7110_AONRST_RTC_32K>,
+ <&aoncrg JH7110_AONRST_RTC_APB>,
+ <&aoncrg JH7110_AONRST_RTC_CAL>;
+ };
--
2.43.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 2/4] rtc: Add StarFive JH7110 RTC driver
2026-11-08 21:28 [PATCH v2 0/4] rtc: Add StarFive JH7110 RTC support Owen O'Hehir
2026-11-08 21:28 ` [PATCH v2 1/4] dt-bindings: rtc: Add StarFive JH7110 RTC Owen O'Hehir
@ 2026-11-08 21:28 ` Owen O'Hehir
2026-11-09 3:12 ` E Shattow
2026-11-08 21:28 ` [PATCH v2 3/4] MAINTAINERS: Add entry for the " Owen O'Hehir
2026-11-08 21:28 ` [PATCH v2 4/4] riscv: dts: starfive: jh7110: Add the RTC node Owen O'Hehir
3 siblings, 1 reply; 11+ messages in thread
From: Owen O'Hehir @ 2026-11-08 21:28 UTC (permalink / raw)
To: Alexandre Belloni, linux-rtc
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Philipp Zabel, devicetree, linux-kernel,
linux-riscv, Hal Feng, ziv.xu, Conor Dooley,
Uwe Kleine-König
From: "ziv.xu" <ziv.xu@starfivetech.com>
Add a driver for the RTC in the always-on domain of the StarFive JH7110
SoC. It supports time, alarm with wakeup, and the frequency offset.
Signed-off-by: ziv.xu <ziv.xu@starfivetech.com>
Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
[Owen: rework of the StarFive vendor driver for mainline: drop hardware
calibration & the default time set in probe, use the generic wake IRQ
helpers, wait for the update bit in set_time, re-read a time that rolls
over during the read, round the offset to the nearest step & follow the
sysfs offset sign, enable the 32k counter clock]
Co-developed-by: Owen O'Hehir <oo.hehir@gmail.com>
Signed-off-by: Owen O'Hehir <oo.hehir@gmail.com>
---
drivers/rtc/Kconfig | 11 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-jh7110.c | 323 +++++++++++++++++++++++++++++++++++++++
3 files changed, 335 insertions(+)
create mode 100644 drivers/rtc/rtc-jh7110.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 73ec9230e..332f2e022 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1807,6 +1807,17 @@ config RTC_DRV_MPC5121
This driver can also be built as a module. If so, the module
will be called rtc-mpc5121.
+config RTC_DRV_JH7110
+ tristate "StarFive JH7110 RTC"
+ depends on ARCH_STARFIVE || COMPILE_TEST
+ help
+ If you say yes here you get support for the RTC in the always-on
+ domain of StarFive JH7110 SoCs, with alarm and frequency offset
+ support.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-jh7110.
+
config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC"
depends on MIPS || COMPILE_TEST
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 46f1a0fc2..a5cddb8d8 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_RTC_DRV_IMX_BBM_SCMI) += rtc-imx-sm-bbm.o
obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
obj-$(CONFIG_RTC_DRV_ISL12026) += rtc-isl12026.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
+obj-$(CONFIG_RTC_DRV_JH7110) += rtc-jh7110.o
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
obj-$(CONFIG_RTC_DRV_LOONGSON) += rtc-loongson.o
obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
diff --git a/drivers/rtc/rtc-jh7110.c b/drivers/rtc/rtc-jh7110.c
new file mode 100644
index 000000000..d2d89cdd4
--- /dev/null
+++ b/drivers/rtc/rtc-jh7110.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RTC driver for the StarFive JH7110 SoC
+ *
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/bcd.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/reset.h>
+#include <linux/rtc.h>
+
+#define JH7110_RTC_CFG 0x00
+#define JH7110_RTC_CFG_ENABLE BIT(0)
+#define JH7110_RTC_CFG_CAL_SEL_HW BIT(2)
+#define JH7110_RTC_CFG_HOUR_24H BIT(3)
+#define JH7110_RTC_SW_CAL_VALUE 0x04
+#define JH7110_RTC_IRQ_EN 0x10
+#define JH7110_RTC_IRQ_EVENT 0x14
+#define JH7110_RTC_IRQ_ALARM BIT(4)
+#define JH7110_RTC_IRQ_ALL GENMASK(4, 0)
+#define JH7110_RTC_EVENT_UPDATE BIT(31)
+#define JH7110_RTC_CAL_VALUE 0x24
+#define JH7110_RTC_CFG_TIME 0x28
+#define JH7110_RTC_CFG_DATE 0x2c
+#define JH7110_RTC_ACT_TIME 0x34
+#define JH7110_RTC_ACT_DATE 0x38
+#define JH7110_RTC_TIME 0x3c
+#define JH7110_RTC_DATE 0x40
+
+#define JH7110_RTC_TIME_SEC GENMASK(6, 0)
+#define JH7110_RTC_TIME_MIN GENMASK(13, 7)
+#define JH7110_RTC_TIME_HOUR GENMASK(20, 14)
+#define JH7110_RTC_DATE_DAY GENMASK(5, 0)
+#define JH7110_RTC_DATE_MON GENMASK(10, 6)
+#define JH7110_RTC_DATE_YEAR GENMASK(18, 11)
+
+#define JH7110_RTC_CAL_MASK GENMASK(15, 0)
+#define JH7110_RTC_TICKS_PER_SEC 32768
+
+#define JH7110_RTC_SYNC_TIMEOUT_US 1000
+
+struct jh7110_rtc {
+ struct rtc_device *rtc;
+ void __iomem *base;
+};
+
+static void jh7110_rtc_reg2tm(struct rtc_time *tm, u32 time, u32 date)
+{
+ tm->tm_sec = bcd2bin(FIELD_GET(JH7110_RTC_TIME_SEC, time));
+ tm->tm_min = bcd2bin(FIELD_GET(JH7110_RTC_TIME_MIN, time));
+ tm->tm_hour = bcd2bin(FIELD_GET(JH7110_RTC_TIME_HOUR, time));
+ tm->tm_mday = bcd2bin(FIELD_GET(JH7110_RTC_DATE_DAY, date));
+ tm->tm_mon = bcd2bin(FIELD_GET(JH7110_RTC_DATE_MON, date)) - 1;
+ tm->tm_year = bcd2bin(FIELD_GET(JH7110_RTC_DATE_YEAR, date)) + 100;
+}
+
+static u32 jh7110_rtc_tm2time(struct rtc_time *tm)
+{
+ return FIELD_PREP(JH7110_RTC_TIME_SEC, bin2bcd(tm->tm_sec)) |
+ FIELD_PREP(JH7110_RTC_TIME_MIN, bin2bcd(tm->tm_min)) |
+ FIELD_PREP(JH7110_RTC_TIME_HOUR, bin2bcd(tm->tm_hour));
+}
+
+static u32 jh7110_rtc_tm2date(struct rtc_time *tm)
+{
+ return FIELD_PREP(JH7110_RTC_DATE_DAY, bin2bcd(tm->tm_mday)) |
+ FIELD_PREP(JH7110_RTC_DATE_MON, bin2bcd(tm->tm_mon + 1)) |
+ FIELD_PREP(JH7110_RTC_DATE_YEAR, bin2bcd(tm->tm_year - 100));
+}
+
+static int jh7110_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
+ u32 time, date;
+
+ /*
+ * re-read if the time rolled over between reading TIME & DATE, since
+ * that rollover can also change the date.
+ */
+ do {
+ time = readl(jrtc->base + JH7110_RTC_TIME);
+ date = readl(jrtc->base + JH7110_RTC_DATE);
+ } while (time != readl(jrtc->base + JH7110_RTC_TIME));
+
+ jh7110_rtc_reg2tm(tm, time, date);
+
+ return 0;
+}
+
+static int jh7110_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
+ u32 val;
+
+ writel(jh7110_rtc_tm2time(tm), jrtc->base + JH7110_RTC_CFG_TIME);
+ writel(jh7110_rtc_tm2date(tm), jrtc->base + JH7110_RTC_CFG_DATE);
+
+ /*
+ * The counter loads CFG_TIME & CFG_DATE on this pulse; the bit appears
+ * to read back as 1 until the load is done.
+ */
+ writel(JH7110_RTC_EVENT_UPDATE, jrtc->base + JH7110_RTC_IRQ_EVENT);
+
+ return readl_poll_timeout(jrtc->base + JH7110_RTC_IRQ_EVENT, val,
+ !(val & JH7110_RTC_EVENT_UPDATE), 10,
+ JH7110_RTC_SYNC_TIMEOUT_US);
+}
+
+static int jh7110_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
+ u32 val;
+
+ val = readl(jrtc->base + JH7110_RTC_IRQ_EN);
+ if (enabled)
+ val |= JH7110_RTC_IRQ_ALARM;
+ else
+ val &= ~JH7110_RTC_IRQ_ALARM;
+ writel(val, jrtc->base + JH7110_RTC_IRQ_EN);
+
+ return 0;
+}
+
+static int jh7110_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
+
+ jh7110_rtc_reg2tm(&alrm->time, readl(jrtc->base + JH7110_RTC_ACT_TIME),
+ readl(jrtc->base + JH7110_RTC_ACT_DATE));
+ alrm->enabled = !!(readl(jrtc->base + JH7110_RTC_IRQ_EN) & JH7110_RTC_IRQ_ALARM);
+
+ return 0;
+}
+
+static int jh7110_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
+ u32 val;
+ int ret;
+
+ jh7110_rtc_alarm_irq_enable(dev, 0);
+ writel(jh7110_rtc_tm2time(&alrm->time), jrtc->base + JH7110_RTC_ACT_TIME);
+ writel(jh7110_rtc_tm2date(&alrm->time), jrtc->base + JH7110_RTC_ACT_DATE);
+ writel(JH7110_RTC_IRQ_ALARM, jrtc->base + JH7110_RTC_IRQ_EVENT);
+
+ ret = readl_poll_timeout(jrtc->base + JH7110_RTC_IRQ_EVENT, val,
+ !(val & JH7110_RTC_IRQ_ALARM), 10,
+ JH7110_RTC_SYNC_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ return jh7110_rtc_alarm_irq_enable(dev, alrm->enabled);
+}
+
+/*
+ * 1 sec for the RTC = CAL_VALUE + 1 cycles of the 32.768 kHz clock.
+ * Default of 0x7fff = exactly one second.
+ * Each step of CAL_VALUE changes the rate by 1/32768, about 30.5 ppm.
+ */
+static int jh7110_rtc_read_offset(struct device *dev, long *offset)
+{
+ struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
+ s64 ticks;
+
+ ticks = (readl(jrtc->base + JH7110_RTC_CAL_VALUE) & JH7110_RTC_CAL_MASK) + 1;
+ *offset = DIV_S64_ROUND_CLOSEST((ticks - JH7110_RTC_TICKS_PER_SEC) * NSEC_PER_SEC,
+ JH7110_RTC_TICKS_PER_SEC);
+
+ return 0;
+}
+
+static int jh7110_rtc_set_offset(struct device *dev, long offset)
+{
+ struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
+ s64 ticks;
+ u32 val;
+
+ if (offset < -NSEC_PER_SEC || offset > NSEC_PER_SEC)
+ return -ERANGE;
+
+ ticks = JH7110_RTC_TICKS_PER_SEC +
+ DIV_S64_ROUND_CLOSEST((s64)offset * JH7110_RTC_TICKS_PER_SEC, NSEC_PER_SEC);
+ if (ticks < 1 || ticks > JH7110_RTC_CAL_MASK + 1)
+ return -ERANGE;
+
+ writel(ticks - 1, jrtc->base + JH7110_RTC_SW_CAL_VALUE);
+ val = readl(jrtc->base + JH7110_RTC_CFG);
+ writel(val & ~JH7110_RTC_CFG_CAL_SEL_HW, jrtc->base + JH7110_RTC_CFG);
+
+ return 0;
+}
+
+static irqreturn_t jh7110_rtc_irq(int irq, void *data)
+{
+ struct jh7110_rtc *jrtc = data;
+ u32 events, val;
+
+ events = readl(jrtc->base + JH7110_RTC_IRQ_EVENT) &
+ readl(jrtc->base + JH7110_RTC_IRQ_EN) & JH7110_RTC_IRQ_ALL;
+ if (!events)
+ return IRQ_NONE;
+
+ writel(events, jrtc->base + JH7110_RTC_IRQ_EVENT);
+ if (readl_poll_timeout_atomic(jrtc->base + JH7110_RTC_IRQ_EVENT, val,
+ !(val & events), 0, JH7110_RTC_SYNC_TIMEOUT_US))
+ dev_warn_ratelimited(&jrtc->rtc->dev, "interrupt events 0x%x not cleared\n",
+ events);
+
+ if (events & JH7110_RTC_IRQ_ALARM)
+ rtc_update_irq(jrtc->rtc, 1, RTC_AF | RTC_IRQF);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops jh7110_rtc_ops = {
+ .read_time = jh7110_rtc_read_time,
+ .set_time = jh7110_rtc_set_time,
+ .read_alarm = jh7110_rtc_read_alarm,
+ .set_alarm = jh7110_rtc_set_alarm,
+ .alarm_irq_enable = jh7110_rtc_alarm_irq_enable,
+ .read_offset = jh7110_rtc_read_offset,
+ .set_offset = jh7110_rtc_set_offset,
+};
+
+static int jh7110_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct reset_control *rst;
+ struct jh7110_rtc *jrtc;
+ struct clk *clk;
+ int irq, ret;
+ u32 val;
+
+ jrtc = devm_kzalloc(dev, sizeof(*jrtc), GFP_KERNEL);
+ if (!jrtc)
+ return -ENOMEM;
+
+ jrtc->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(jrtc->base))
+ return PTR_ERR(jrtc->base);
+
+ clk = devm_clk_get_enabled(dev, "apb");
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to enable apb clock\n");
+
+ clk = devm_clk_get_enabled(dev, "cal");
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to enable cal clock\n");
+
+ clk = devm_clk_get_enabled(dev, "32k");
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to enable 32k clock\n");
+
+ /* Never asserted again, as that would stop the clock & lose the time */
+ rst = devm_reset_control_array_get_exclusive(dev);
+ if (IS_ERR(rst))
+ return dev_err_probe(dev, PTR_ERR(rst), "failed to get resets\n");
+
+ ret = reset_control_deassert(rst);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to deassert resets\n");
+
+ irq = platform_get_irq_byname(pdev, "rtc");
+ if (irq < 0)
+ return irq;
+
+ jrtc->rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(jrtc->rtc))
+ return PTR_ERR(jrtc->rtc);
+
+ platform_set_drvdata(pdev, jrtc);
+
+ jrtc->rtc->ops = &jh7110_rtc_ops;
+ jrtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ jrtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
+
+ val = readl(jrtc->base + JH7110_RTC_CFG);
+ writel(val | JH7110_RTC_CFG_HOUR_24H | JH7110_RTC_CFG_ENABLE,
+ jrtc->base + JH7110_RTC_CFG);
+
+ ret = devm_request_irq(dev, irq, jh7110_rtc_irq, 0, dev_name(dev), jrtc);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request irq\n");
+
+ ret = devm_device_init_wakeup(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to init wakeup\n");
+
+ ret = devm_pm_set_wake_irq(dev, irq);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set wake irq\n");
+
+ return devm_rtc_register_device(jrtc->rtc);
+}
+
+static const struct of_device_id jh7110_rtc_of_match[] = {
+ { .compatible = "starfive,jh7110-rtc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, jh7110_rtc_of_match);
+
+static struct platform_driver jh7110_rtc_driver = {
+ .driver = {
+ .name = "jh7110-rtc",
+ .of_match_table = jh7110_rtc_of_match,
+ },
+ .probe = jh7110_rtc_probe,
+};
+module_platform_driver(jh7110_rtc_driver);
+
+MODULE_AUTHOR("Samin Guo <samin.guo@starfivetech.com>");
+MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>");
+MODULE_DESCRIPTION("StarFive JH7110 RTC driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 3/4] MAINTAINERS: Add entry for the StarFive JH7110 RTC driver
2026-11-08 21:28 [PATCH v2 0/4] rtc: Add StarFive JH7110 RTC support Owen O'Hehir
2026-11-08 21:28 ` [PATCH v2 1/4] dt-bindings: rtc: Add StarFive JH7110 RTC Owen O'Hehir
2026-11-08 21:28 ` [PATCH v2 2/4] rtc: Add StarFive JH7110 RTC driver Owen O'Hehir
@ 2026-11-08 21:28 ` Owen O'Hehir
2026-11-08 21:28 ` [PATCH v2 4/4] riscv: dts: starfive: jh7110: Add the RTC node Owen O'Hehir
3 siblings, 0 replies; 11+ messages in thread
From: Owen O'Hehir @ 2026-11-08 21:28 UTC (permalink / raw)
To: Alexandre Belloni, linux-rtc
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Philipp Zabel, devicetree, linux-kernel,
linux-riscv, Hal Feng, ziv.xu, Conor Dooley,
Uwe Kleine-König
Add myself as maintainer of the StarFive JH7110 RTC driver and its
binding.
Signed-off-by: Owen O'Hehir <oo.hehir@gmail.com>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index aa647f5d3..2ee86a46c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26877,6 +26877,13 @@ S: Supported
F: Documentation/devicetree/bindings/sound/starfive,jh7110-pwmdac.yaml
F: sound/soc/starfive/jh7110_pwmdac.c
+STARFIVE JH7110 RTC DRIVER
+M: Owen O'Hehir <oo.hehir@gmail.com>
+L: linux-rtc@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/rtc/starfive,jh7110-rtc.yaml
+F: drivers/rtc/rtc-jh7110.c
+
STARFIVE JH7110 SYSCON
M: William Qiu <william.qiu@starfivetech.com>
M: Xingyu Wu <xingyu.wu@starfivetech.com>
--
2.43.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 4/4] riscv: dts: starfive: jh7110: Add the RTC node
2026-11-08 21:28 [PATCH v2 0/4] rtc: Add StarFive JH7110 RTC support Owen O'Hehir
` (2 preceding siblings ...)
2026-11-08 21:28 ` [PATCH v2 3/4] MAINTAINERS: Add entry for the " Owen O'Hehir
@ 2026-11-08 21:28 ` Owen O'Hehir
2026-11-09 3:37 ` E Shattow
3 siblings, 1 reply; 11+ messages in thread
From: Owen O'Hehir @ 2026-11-08 21:28 UTC (permalink / raw)
To: Alexandre Belloni, linux-rtc
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Philipp Zabel, devicetree, linux-kernel,
linux-riscv, Hal Feng, ziv.xu, Conor Dooley,
Uwe Kleine-König
Tested on a VisionFive 2 v1.3B.
Signed-off-by: Owen O'Hehir <oo.hehir@gmail.com>
---
arch/riscv/boot/dts/starfive/jh7110.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
index 82ea63f71..14f92b942 100644
--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
@@ -1206,6 +1206,20 @@ pwrc: power-controller@17030000 {
#power-domain-cells = <1>;
};
+ rtc: rtc@17040000 {
+ compatible = "starfive,jh7110-rtc";
+ reg = <0x0 0x17040000 0x0 0x10000>;
+ interrupts = <10>, <11>, <12>;
+ interrupt-names = "ms-pulse", "sec-pulse", "rtc";
+ clocks = <&aoncrg JH7110_AONCLK_RTC_APB>,
+ <&aoncrg JH7110_AONCLK_RTC_CAL>,
+ <&aoncrg JH7110_AONCLK_RTC_32K>;
+ clock-names = "apb", "cal", "32k";
+ resets = <&aoncrg JH7110_AONRST_RTC_32K>,
+ <&aoncrg JH7110_AONRST_RTC_APB>,
+ <&aoncrg JH7110_AONRST_RTC_CAL>;
+ };
+
csi2rx: csi@19800000 {
compatible = "starfive,jh7110-csi2rx", "cdns,csi2rx";
reg = <0x0 0x19800000 0x0 0x10000>;
--
2.43.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 1/4] dt-bindings: rtc: Add StarFive JH7110 RTC
2026-11-08 21:28 ` [PATCH v2 1/4] dt-bindings: rtc: Add StarFive JH7110 RTC Owen O'Hehir
@ 2026-11-08 22:56 ` Conor Dooley
0 siblings, 0 replies; 11+ messages in thread
From: Conor Dooley @ 2026-11-08 22:56 UTC (permalink / raw)
To: Owen O'Hehir
Cc: Alexandre Belloni, linux-rtc, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Emil Renner Berthing, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Philipp Zabel,
devicetree, linux-kernel, linux-riscv, Hal Feng, ziv.xu,
Uwe Kleine-König
[-- 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 [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/4] rtc: Add StarFive JH7110 RTC driver
2026-11-08 21:28 ` [PATCH v2 2/4] rtc: Add StarFive JH7110 RTC driver Owen O'Hehir
@ 2026-11-09 3:12 ` E Shattow
2026-11-09 15:44 ` Owen O'Hehir
2026-11-09 16:29 ` Alexandre Belloni
0 siblings, 2 replies; 11+ messages in thread
From: E Shattow @ 2026-11-09 3:12 UTC (permalink / raw)
To: Owen O'Hehir, Alexandre Belloni, linux-rtc
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Philipp Zabel, devicetree, linux-kernel,
linux-riscv, Hal Feng, ziv.xu, Conor Dooley,
Uwe Kleine-König
Hi Owen,
On 11/8/26 13:28, Owen O'Hehir wrote:
> From: "ziv.xu" <ziv.xu@starfivetech.com>
>
> Add a driver for the RTC in the always-on domain of the StarFive JH7110
> SoC. It supports time, alarm with wakeup, and the frequency offset.
>
> Signed-off-by: ziv.xu <ziv.xu@starfivetech.com>
> Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
> [Owen: rework of the StarFive vendor driver for mainline: drop hardware
> calibration & the default time set in probe, use the generic wake IRQ
> helpers, wait for the update bit in set_time, re-read a time that rolls
> over during the read, round the offset to the nearest step & follow the
> sysfs offset sign, enable the 32k counter clock]
> Co-developed-by: Owen O'Hehir <oo.hehir@gmail.com>
> Signed-off-by: Owen O'Hehir <oo.hehir@gmail.com>
> ---
> drivers/rtc/Kconfig | 11 ++
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-jh7110.c | 323 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 335 insertions(+)
> create mode 100644 drivers/rtc/rtc-jh7110.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 73ec9230e..332f2e022 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1807,6 +1807,17 @@ config RTC_DRV_MPC5121
> This driver can also be built as a module. If so, the module
> will be called rtc-mpc5121.
>
> +config RTC_DRV_JH7110
> + tristate "StarFive JH7110 RTC"
> + depends on ARCH_STARFIVE || COMPILE_TEST
> + help
> + If you say yes here you get support for the RTC in the always-on
> + domain of StarFive JH7110 SoCs, with alarm and frequency offset
> + support.
> +
> + This driver can also be built as a module. If so, the module
> + will be called rtc-jh7110.
> +
> config RTC_DRV_JZ4740
> tristate "Ingenic JZ4740 SoC"
> depends on MIPS || COMPILE_TEST
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 46f1a0fc2..a5cddb8d8 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -82,6 +82,7 @@ obj-$(CONFIG_RTC_DRV_IMX_BBM_SCMI) += rtc-imx-sm-bbm.o
> obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
> obj-$(CONFIG_RTC_DRV_ISL12026) += rtc-isl12026.o
> obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
> +obj-$(CONFIG_RTC_DRV_JH7110) += rtc-jh7110.o
> obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
> obj-$(CONFIG_RTC_DRV_LOONGSON) += rtc-loongson.o
> obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
> diff --git a/drivers/rtc/rtc-jh7110.c b/drivers/rtc/rtc-jh7110.c
> new file mode 100644
> index 000000000..d2d89cdd4
> --- /dev/null
> +++ b/drivers/rtc/rtc-jh7110.c
> @@ -0,0 +1,323 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * RTC driver for the StarFive JH7110 SoC
> + *
> + * Copyright (C) 2021 StarFive Technology Co., Ltd.
> + */
Is this copyrighted work from previous year 2021 being imported without
modification?
If there is modification then I would assume it needs appended your
authorship and the current year 2026.
> +
> +#include <linux/bcd.h>
> +#include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/math64.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeirq.h>
> +#include <linux/reset.h>
> +#include <linux/rtc.h>
> +
> +#define JH7110_RTC_CFG 0x00
> +#define JH7110_RTC_CFG_ENABLE BIT(0)
> +#define JH7110_RTC_CFG_CAL_SEL_HW BIT(2)
> +#define JH7110_RTC_CFG_HOUR_24H BIT(3)
> +#define JH7110_RTC_SW_CAL_VALUE 0x04
> +#define JH7110_RTC_IRQ_EN 0x10
> +#define JH7110_RTC_IRQ_EVENT 0x14
> +#define JH7110_RTC_IRQ_ALARM BIT(4)
> +#define JH7110_RTC_IRQ_ALL GENMASK(4, 0)
> +#define JH7110_RTC_EVENT_UPDATE BIT(31)
> +#define JH7110_RTC_CAL_VALUE 0x24
> +#define JH7110_RTC_CFG_TIME 0x28
> +#define JH7110_RTC_CFG_DATE 0x2c
> +#define JH7110_RTC_ACT_TIME 0x34
> +#define JH7110_RTC_ACT_DATE 0x38
> +#define JH7110_RTC_TIME 0x3c
> +#define JH7110_RTC_DATE 0x40
> +
Align 8-char tab stops per Linux coding style, and then tidy up the
extra junk clearspace on some of the defines
> +#define JH7110_RTC_TIME_SEC GENMASK(6, 0)
> +#define JH7110_RTC_TIME_MIN GENMASK(13, 7)
> +#define JH7110_RTC_TIME_HOUR GENMASK(20, 14)
> +#define JH7110_RTC_DATE_DAY GENMASK(5, 0)
> +#define JH7110_RTC_DATE_MON GENMASK(10, 6)
> +#define JH7110_RTC_DATE_YEAR GENMASK(18, 11)
> +
> +#define JH7110_RTC_CAL_MASK GENMASK(15, 0)
> +#define JH7110_RTC_TICKS_PER_SEC 32768
> +
> +#define JH7110_RTC_SYNC_TIMEOUT_US 1000
> +
> +struct jh7110_rtc {
> + struct rtc_device *rtc;
> + void __iomem *base;
> +};
> +
> +static void jh7110_rtc_reg2tm(struct rtc_time *tm, u32 time, u32 date)
> +{
> + tm->tm_sec = bcd2bin(FIELD_GET(JH7110_RTC_TIME_SEC, time));
> + tm->tm_min = bcd2bin(FIELD_GET(JH7110_RTC_TIME_MIN, time));
> + tm->tm_hour = bcd2bin(FIELD_GET(JH7110_RTC_TIME_HOUR, time));
> + tm->tm_mday = bcd2bin(FIELD_GET(JH7110_RTC_DATE_DAY, date));
> + tm->tm_mon = bcd2bin(FIELD_GET(JH7110_RTC_DATE_MON, date)) - 1;
> + tm->tm_year = bcd2bin(FIELD_GET(JH7110_RTC_DATE_YEAR, date)) + 100;
> +}
> +
> +static u32 jh7110_rtc_tm2time(struct rtc_time *tm)
> +{
> + return FIELD_PREP(JH7110_RTC_TIME_SEC, bin2bcd(tm->tm_sec)) |
> + FIELD_PREP(JH7110_RTC_TIME_MIN, bin2bcd(tm->tm_min)) |
> + FIELD_PREP(JH7110_RTC_TIME_HOUR, bin2bcd(tm->tm_hour));
> +}
> +
> +static u32 jh7110_rtc_tm2date(struct rtc_time *tm)
> +{
> + return FIELD_PREP(JH7110_RTC_DATE_DAY, bin2bcd(tm->tm_mday)) |
> + FIELD_PREP(JH7110_RTC_DATE_MON, bin2bcd(tm->tm_mon + 1)) |
> + FIELD_PREP(JH7110_RTC_DATE_YEAR, bin2bcd(tm->tm_year - 100));
> +}
> +
> +static int jh7110_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
> + u32 time, date;
> +
> + /*
> + * re-read if the time rolled over between reading TIME & DATE, since
> + * that rollover can also change the date.
> + */
> + do {
> + time = readl(jrtc->base + JH7110_RTC_TIME);
> + date = readl(jrtc->base + JH7110_RTC_DATE);
> + } while (time != readl(jrtc->base + JH7110_RTC_TIME));
> +
> + jh7110_rtc_reg2tm(tm, time, date);
> +
> + return 0;
> +}
> +
> +static int jh7110_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
> + u32 val;
> +
> + writel(jh7110_rtc_tm2time(tm), jrtc->base + JH7110_RTC_CFG_TIME);
> + writel(jh7110_rtc_tm2date(tm), jrtc->base + JH7110_RTC_CFG_DATE);
> +
> + /*
> + * The counter loads CFG_TIME & CFG_DATE on this pulse; the bit appears
> + * to read back as 1 until the load is done.
> + */
> + writel(JH7110_RTC_EVENT_UPDATE, jrtc->base + JH7110_RTC_IRQ_EVENT);
> +
> + return readl_poll_timeout(jrtc->base + JH7110_RTC_IRQ_EVENT, val,
> + !(val & JH7110_RTC_EVENT_UPDATE), 10,
> + JH7110_RTC_SYNC_TIMEOUT_US);
> +}
> +
> +static int jh7110_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> + struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
> + u32 val;
> +
> + val = readl(jrtc->base + JH7110_RTC_IRQ_EN);
> + if (enabled)
> + val |= JH7110_RTC_IRQ_ALARM;
> + else
> + val &= ~JH7110_RTC_IRQ_ALARM;
> + writel(val, jrtc->base + JH7110_RTC_IRQ_EN);
> +
> + return 0;
> +}
> +
> +static int jh7110_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
> +
> + jh7110_rtc_reg2tm(&alrm->time, readl(jrtc->base + JH7110_RTC_ACT_TIME),
> + readl(jrtc->base + JH7110_RTC_ACT_DATE));
> + alrm->enabled = !!(readl(jrtc->base + JH7110_RTC_IRQ_EN) & JH7110_RTC_IRQ_ALARM);
> +
> + return 0;
> +}
> +
> +static int jh7110_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
> + u32 val;
> + int ret;
> +
> + jh7110_rtc_alarm_irq_enable(dev, 0);
> + writel(jh7110_rtc_tm2time(&alrm->time), jrtc->base + JH7110_RTC_ACT_TIME);
> + writel(jh7110_rtc_tm2date(&alrm->time), jrtc->base + JH7110_RTC_ACT_DATE);
> + writel(JH7110_RTC_IRQ_ALARM, jrtc->base + JH7110_RTC_IRQ_EVENT);
> +
> + ret = readl_poll_timeout(jrtc->base + JH7110_RTC_IRQ_EVENT, val,
> + !(val & JH7110_RTC_IRQ_ALARM), 10,
> + JH7110_RTC_SYNC_TIMEOUT_US);
> + if (ret)
> + return ret;
> +
> + return jh7110_rtc_alarm_irq_enable(dev, alrm->enabled);
> +}
> +
> +/*
> + * 1 sec for the RTC = CAL_VALUE + 1 cycles of the 32.768 kHz clock.
> + * Default of 0x7fff = exactly one second.
> + * Each step of CAL_VALUE changes the rate by 1/32768, about 30.5 ppm.
> + */
> +static int jh7110_rtc_read_offset(struct device *dev, long *offset)
> +{
> + struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
> + s64 ticks;
> +
> + ticks = (readl(jrtc->base + JH7110_RTC_CAL_VALUE) & JH7110_RTC_CAL_MASK) + 1;
> + *offset = DIV_S64_ROUND_CLOSEST((ticks - JH7110_RTC_TICKS_PER_SEC) * NSEC_PER_SEC,
> + JH7110_RTC_TICKS_PER_SEC);
> +
> + return 0;
> +}
> +
> +static int jh7110_rtc_set_offset(struct device *dev, long offset)
> +{
> + struct jh7110_rtc *jrtc = dev_get_drvdata(dev);
> + s64 ticks;
> + u32 val;
> +
> + if (offset < -NSEC_PER_SEC || offset > NSEC_PER_SEC)
> + return -ERANGE;
> +
> + ticks = JH7110_RTC_TICKS_PER_SEC +
> + DIV_S64_ROUND_CLOSEST((s64)offset * JH7110_RTC_TICKS_PER_SEC, NSEC_PER_SEC);
> + if (ticks < 1 || ticks > JH7110_RTC_CAL_MASK + 1)
> + return -ERANGE;
> +
> + writel(ticks - 1, jrtc->base + JH7110_RTC_SW_CAL_VALUE);
> + val = readl(jrtc->base + JH7110_RTC_CFG);
> + writel(val & ~JH7110_RTC_CFG_CAL_SEL_HW, jrtc->base + JH7110_RTC_CFG);
> +
> + return 0;
> +}
> +
> +static irqreturn_t jh7110_rtc_irq(int irq, void *data)
> +{
> + struct jh7110_rtc *jrtc = data;
> + u32 events, val;
> +
> + events = readl(jrtc->base + JH7110_RTC_IRQ_EVENT) &
> + readl(jrtc->base + JH7110_RTC_IRQ_EN) & JH7110_RTC_IRQ_ALL;
> + if (!events)
> + return IRQ_NONE;
> +
> + writel(events, jrtc->base + JH7110_RTC_IRQ_EVENT);
> + if (readl_poll_timeout_atomic(jrtc->base + JH7110_RTC_IRQ_EVENT, val,
> + !(val & events), 0, JH7110_RTC_SYNC_TIMEOUT_US))
> + dev_warn_ratelimited(&jrtc->rtc->dev, "interrupt events 0x%x not cleared\n",
> + events);
> +
> + if (events & JH7110_RTC_IRQ_ALARM)
> + rtc_update_irq(jrtc->rtc, 1, RTC_AF | RTC_IRQF);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static const struct rtc_class_ops jh7110_rtc_ops = {
> + .read_time = jh7110_rtc_read_time,
> + .set_time = jh7110_rtc_set_time,
> + .read_alarm = jh7110_rtc_read_alarm,
> + .set_alarm = jh7110_rtc_set_alarm,
> + .alarm_irq_enable = jh7110_rtc_alarm_irq_enable,
> + .read_offset = jh7110_rtc_read_offset,
> + .set_offset = jh7110_rtc_set_offset,
> +};
> +
> +static int jh7110_rtc_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct reset_control *rst;
> + struct jh7110_rtc *jrtc;
> + struct clk *clk;
> + int irq, ret;
> + u32 val;
> +
> + jrtc = devm_kzalloc(dev, sizeof(*jrtc), GFP_KERNEL);
> + if (!jrtc)
> + return -ENOMEM;
> +
> + jrtc->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(jrtc->base))
> + return PTR_ERR(jrtc->base);
> +
> + clk = devm_clk_get_enabled(dev, "apb");
> + if (IS_ERR(clk))
> + return dev_err_probe(dev, PTR_ERR(clk), "failed to enable apb clock\n");
> +
> + clk = devm_clk_get_enabled(dev, "cal");
> + if (IS_ERR(clk))
> + return dev_err_probe(dev, PTR_ERR(clk), "failed to enable cal clock\n");
> +
> + clk = devm_clk_get_enabled(dev, "32k");
> + if (IS_ERR(clk))
> + return dev_err_probe(dev, PTR_ERR(clk), "failed to enable 32k clock\n");
> +
> + /* Never asserted again, as that would stop the clock & lose the time */
> + rst = devm_reset_control_array_get_exclusive(dev);
> + if (IS_ERR(rst))
> + return dev_err_probe(dev, PTR_ERR(rst), "failed to get resets\n");
> +
> + ret = reset_control_deassert(rst);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to deassert resets\n");
> +
> + irq = platform_get_irq_byname(pdev, "rtc");
> + if (irq < 0)
> + return irq;
> +
> + jrtc->rtc = devm_rtc_allocate_device(dev);
> + if (IS_ERR(jrtc->rtc))
> + return PTR_ERR(jrtc->rtc);
> +
> + platform_set_drvdata(pdev, jrtc);
> +
> + jrtc->rtc->ops = &jh7110_rtc_ops;
> + jrtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
> + jrtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
> +
> + val = readl(jrtc->base + JH7110_RTC_CFG);
> + writel(val | JH7110_RTC_CFG_HOUR_24H | JH7110_RTC_CFG_ENABLE,
> + jrtc->base + JH7110_RTC_CFG);
> +
> + ret = devm_request_irq(dev, irq, jh7110_rtc_irq, 0, dev_name(dev), jrtc);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to request irq\n");
> +
> + ret = devm_device_init_wakeup(dev);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to init wakeup\n");
> +
> + ret = devm_pm_set_wake_irq(dev, irq);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to set wake irq\n");
> +
> + return devm_rtc_register_device(jrtc->rtc);
> +}
> +
> +static const struct of_device_id jh7110_rtc_of_match[] = {
> + { .compatible = "starfive,jh7110-rtc" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, jh7110_rtc_of_match);
> +
> +static struct platform_driver jh7110_rtc_driver = {
> + .driver = {
> + .name = "jh7110-rtc",
> + .of_match_table = jh7110_rtc_of_match,
> + },
> + .probe = jh7110_rtc_probe,
> +};
> +module_platform_driver(jh7110_rtc_driver);
I note that JH7100 does not mention RTC in its datasheet. Does JH7110
RTC have any commonality with JHB100 and if so then would rtc-starfive
be a more suitable name for the code filename and module?
> +
> +MODULE_AUTHOR("Samin Guo <samin.guo@starfivetech.com>");
> +MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>");
Review use of authorship macros as appropriate. This may be okay as-is.
> +MODULE_DESCRIPTION("StarFive JH7110 RTC driver");
> +MODULE_LICENSE("GPL");
-E
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 4/4] riscv: dts: starfive: jh7110: Add the RTC node
2026-11-08 21:28 ` [PATCH v2 4/4] riscv: dts: starfive: jh7110: Add the RTC node Owen O'Hehir
@ 2026-11-09 3:37 ` E Shattow
2026-11-09 15:44 ` Owen O'Hehir
0 siblings, 1 reply; 11+ messages in thread
From: E Shattow @ 2026-11-09 3:37 UTC (permalink / raw)
To: Owen O'Hehir, Alexandre Belloni, linux-rtc
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Philipp Zabel, devicetree, linux-kernel,
linux-riscv, Hal Feng, ziv.xu, Conor Dooley,
Uwe Kleine-König
Hi Owen,
On 11/8/26 13:28, Owen O'Hehir wrote:
> Tested on a VisionFive 2 v1.3B.
>
> Signed-off-by: Owen O'Hehir <oo.hehir@gmail.com>
> ---
> arch/riscv/boot/dts/starfive/jh7110.dtsi | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> index 82ea63f71..14f92b942 100644
> --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
> +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> @@ -1206,6 +1206,20 @@ pwrc: power-controller@17030000 {
> #power-domain-cells = <1>;
> };
>
> + rtc: rtc@17040000 {
> + compatible = "starfive,jh7110-rtc";
> + reg = <0x0 0x17040000 0x0 0x10000>;
> + interrupts = <10>, <11>, <12>;
> + interrupt-names = "ms-pulse", "sec-pulse", "rtc";
> + clocks = <&aoncrg JH7110_AONCLK_RTC_APB>,
> + <&aoncrg JH7110_AONCLK_RTC_CAL>,
> + <&aoncrg JH7110_AONCLK_RTC_32K>;
> + clock-names = "apb", "cal", "32k";
> + resets = <&aoncrg JH7110_AONRST_RTC_32K>,
> + <&aoncrg JH7110_AONRST_RTC_APB>,
> + <&aoncrg JH7110_AONRST_RTC_CAL>;
> + };
> +
> csi2rx: csi@19800000 {
> compatible = "starfive,jh7110-csi2rx", "cdns,csi2rx";
> reg = <0x0 0x19800000 0x0 0x10000>;
Is status property applicable to SoC rtc? If not, then is 'rtc' label
appropriate when there's no status applicable?
Note that Mars CM / CM-Lite System-on-Modules may be used commonly with
board carriers which implement a battery-backed RTC on the I2C bus, and
so another 'rtc' label may be applicable, something to consider. The
initial Mars CM / CM-Lite dts ignores this because there is an
inconvenient I2C bus device address conflict of the SoM EEPROM and some
carrier boards' RTC, and the SoC RTC driver was not then present;
problems for a future self.
-E
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 4/4] riscv: dts: starfive: jh7110: Add the RTC node
2026-11-09 3:37 ` E Shattow
@ 2026-11-09 15:44 ` Owen O'Hehir
0 siblings, 0 replies; 11+ messages in thread
From: Owen O'Hehir @ 2026-11-09 15:44 UTC (permalink / raw)
To: E Shattow
Cc: Alexandre Belloni, linux-rtc, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Emil Renner Berthing, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Philipp Zabel,
devicetree, linux-kernel, linux-riscv, Hal Feng, ziv.xu,
Conor Dooley, Uwe Kleine-König
Hi E,
> Is status property applicable to SoC rtc? If not, then is 'rtc' label
> appropriate when there's no status applicable?
The RTC is in the SoC always-on domain and its clocks come from aoncrg;
the 32 kHz oscillator is set in jh7110-common.dtsi, which every JH7110
board includes, so no board needs to enable it. It is left enabled in
the dtsi like the other always-on nodes (aoncrg, aongpio, pwrc). Other
SoC RTCs do the same, e.g. Allwinner (including the D1), Sophgo CV180x
and i.MX snvs_rtc; the ones disabled by default, such as STM32, depend
on board parts that not every board has.
An alias is only needed when a board has more than one RTC, and none of
the JH7110 boards in the tree do. A board can still disable the node or
alias it through the label.
> Note that Mars CM / CM-Lite System-on-Modules may be used commonly with
> board carriers which implement a battery-backed RTC on the I2C bus, and
> so another 'rtc' label may be applicable, something to consider.
Good point. v3 renames the label to soc_rtc, leaving rtc free for a
carrier board's RTC.
Owen
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/4] rtc: Add StarFive JH7110 RTC driver
2026-11-09 3:12 ` E Shattow
@ 2026-11-09 15:44 ` Owen O'Hehir
2026-11-09 16:29 ` Alexandre Belloni
1 sibling, 0 replies; 11+ messages in thread
From: Owen O'Hehir @ 2026-11-09 15:44 UTC (permalink / raw)
To: E Shattow
Cc: Alexandre Belloni, linux-rtc, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Emil Renner Berthing, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Philipp Zabel,
devicetree, linux-kernel, linux-riscv, Hal Feng, ziv.xu,
Conor Dooley, Uwe Kleine-König
Hi E,
Thanks for the review.
> Is this copyrighted work from previous year 2021 being imported without
> modification?
>
> If there is modification then I would assume it needs appended your
> authorship and the current year 2026.
It is modified, so v3 adds my copyright line below StarFive's.
> Align 8-char tab stops per Linux coding style, and then tidy up the
> extra junk clearspace on some of the defines
The values line up in the file; in the patch the leading '+' pushes a
few of them (TIME, DATE, CFG_HOUR_24H, SW_CAL_VALUE, EVENT_UPDATE) one
tab out. The extra space before some names marks them as bit fields of
the register above; as it reads as noise, v3 drops it.
> I note that JH7100 does not mention RTC in its datasheet. Does JH7110
> RTC have any commonality with JHB100 and if so then would rtc-starfive
> be a more suitable name for the code filename and module?
The JHB100 clock and reset bindings do name an RTC clock and reset,
under its Peripheral-2 clock and reset generator alongside CAN and
GMAC, whose inputs include no 32 kHz clock; the JH7110 RTC is in the
always-on domain. I searched for JHB100 documentation but found nothing
on its RTC beyond those names, so I cannot say whether the block is the
same. I would keep the jh7110 name, after the first SoC supported; if
the JHB100 turns out to use the same block, it can reuse the driver with
its own compatible. That is what the pending JHB100 TRNG series does
with jh7110-trng.c. I would appreciate advice from Hal or anyone who
knows whether the JHB100 RTC is the same IP.
> Review use of authorship macros as appropriate. This may be okay as-is.
The driver is derived from the StarFive one, so I kept its authors and
will leave these as they are.
Owen
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/4] rtc: Add StarFive JH7110 RTC driver
2026-11-09 3:12 ` E Shattow
2026-11-09 15:44 ` Owen O'Hehir
@ 2026-11-09 16:29 ` Alexandre Belloni
1 sibling, 0 replies; 11+ messages in thread
From: Alexandre Belloni @ 2026-11-09 16:29 UTC (permalink / raw)
To: E Shattow
Cc: Owen O'Hehir, linux-rtc, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Emil Renner Berthing, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Philipp Zabel,
devicetree, linux-kernel, linux-riscv, Hal Feng, ziv.xu,
Conor Dooley, Uwe Kleine-König
On 08/11/2026 19:12:58-0800, E Shattow wrote:
> > +static const struct of_device_id jh7110_rtc_of_match[] = {
> > + { .compatible = "starfive,jh7110-rtc" },
> > + { }
> > +};
> > +MODULE_DEVICE_TABLE(of, jh7110_rtc_of_match);
> > +
> > +static struct platform_driver jh7110_rtc_driver = {
> > + .driver = {
> > + .name = "jh7110-rtc",
> > + .of_match_table = jh7110_rtc_of_match,
> > + },
> > + .probe = jh7110_rtc_probe,
> > +};
> > +module_platform_driver(jh7110_rtc_driver);
>
> I note that JH7100 does not mention RTC in its datasheet. Does JH7110
> RTC have any commonality with JHB100 and if so then would rtc-starfive
> be a more suitable name for the code filename and module?
>
The filename has to be soc specific, else we will end up with
rtc-starfive.c, rtc-starfive2.c, etc... when the vendor choose to change
the IP.
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-11-09 16:29 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-08 21:28 [PATCH v2 0/4] rtc: Add StarFive JH7110 RTC support Owen O'Hehir
2026-11-08 21:28 ` [PATCH v2 1/4] dt-bindings: rtc: Add StarFive JH7110 RTC Owen O'Hehir
2026-11-08 22:56 ` Conor Dooley
2026-11-08 21:28 ` [PATCH v2 2/4] rtc: Add StarFive JH7110 RTC driver Owen O'Hehir
2026-11-09 3:12 ` E Shattow
2026-11-09 15:44 ` Owen O'Hehir
2026-11-09 16:29 ` Alexandre Belloni
2026-11-08 21:28 ` [PATCH v2 3/4] MAINTAINERS: Add entry for the " Owen O'Hehir
2026-11-08 21:28 ` [PATCH v2 4/4] riscv: dts: starfive: jh7110: Add the RTC node Owen O'Hehir
2026-11-09 3:37 ` E Shattow
2026-11-09 15:44 ` Owen O'Hehir
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®