mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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
  0 siblings, 0 replies; 8+ 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] 8+ 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
  0 siblings, 0 replies; 8+ 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] 8+ messages in thread

end of thread, other threads:[~2026-11-09  3:38 UTC | newest]

Thread overview: 8+ 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-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

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®