linux-renesas-soc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/5] RZ/N1 RTC support
@ 2022-05-13 11:03 Miquel Raynal
  2022-05-13 11:03 ` [PATCH v6 1/5] dt-bindings: rtc: rzn1: Describe the RZN1 RTC Miquel Raynal
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Miquel Raynal @ 2022-05-13 11:03 UTC (permalink / raw)
  To: Alessandro Zummo, Alexandre Belloni, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm
  Cc: Miquel Raynal, linux-rtc, linux-renesas-soc, devicetree,
	Gareth Williams, Milan Stevanovic, Jimmy Lalande,
	Pascal Eberhard, Thomas Petazzoni, Herve Codina, Clement Leger

Hello,

This small series adds support for the RZ/N1 RTC.

Despite its limitations, I found useful to at least have alarm and
offset support.

Cheers,
Miquèl

Changes in v6:
* Fix a sparse warning by dropping a variable not really used and
  replaced by a comment.

Changes in v5:
* Dropped a (now) useless header that could produce a build error.

Changes in v4:
* Collected more tags (on the DT bindings).
* Fixed the name of the SoC in the header: RZ/N1 instead of RZN1.
* Dropped the error message when the alarm IRQ is not available (already
  handled by the core)
* Used pm_runtime_put() instead of pm_runtime_put_sync().
* Used pm_runtime_resume_and_get() instead of pm_runtime_get().
* Used devm_pm_runtime_enable() instead of pm_runtime_enable().

Changes in v3:
* Collected tags.
* s/soc:/clk:/ in the clock commit title.
* Dropped the RTC hclk fix which has already been applied.
* Added the power-domain properties both in the bindings and in the DT.
* Used runtime PM to enable the clock instead of using the clk API
  directly. 

Changes in v2:
* Fixed the error path in the clk driver, where I missed to release a
  spin_lock.
* Collected tags.
* Moved the rtc subnode in the dt to keep the nodes ordered by unit
  address.
* Dropped the useless "oneOf" statement in the bindings (compatible
  property).
* Dropped the start-year property in the bindings (already defined).
* Avoided rollover calculations that could be more easily handled (and
  reviewed) with a time64_t conversion.
* Returned ERANGE instead of EOPNOTSUPP when the alarm date is not
  valid.
* Cleared RTC_FEATURE_UPDATE_INTERRUPT to avoid warning from the tools.
* Dropped the sysctl patch adding the reset helper, instead fulfilled
  the description of the RTC clock so that when requesting this clock to
  be enabled, the idle bit is released.
* Avoided rollover calculations that could be more easily handled
  (and reviewed) with a time64_t conversion.
* Fixed the max_range value, after a rtc-range test and looking at other
  implementations.

Michel Pollet (1):
  rtc: rzn1: Add new RTC driver

Miquel Raynal (4):
  dt-bindings: rtc: rzn1: Describe the RZN1 RTC
  rtc: rzn1: Add alarm support
  rtc: rzn1: Add oscillator offset support
  MAINTAINERS: Add myself as maintainer of the RZN1 RTC driver

 .../bindings/rtc/renesas,rzn1-rtc.yaml        |  70 +++
 MAINTAINERS                                   |   8 +
 drivers/rtc/Kconfig                           |   7 +
 drivers/rtc/Makefile                          |   1 +
 drivers/rtc/rtc-rzn1.c                        | 422 ++++++++++++++++++
 5 files changed, 508 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml
 create mode 100644 drivers/rtc/rtc-rzn1.c

-- 
2.27.0


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

* [PATCH v6 1/5] dt-bindings: rtc: rzn1: Describe the RZN1 RTC
  2022-05-13 11:03 [PATCH v6 0/5] RZ/N1 RTC support Miquel Raynal
@ 2022-05-13 11:03 ` Miquel Raynal
  2022-05-13 11:03 ` [PATCH v6 2/5] rtc: rzn1: Add new RTC driver Miquel Raynal
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Miquel Raynal @ 2022-05-13 11:03 UTC (permalink / raw)
  To: Alessandro Zummo, Alexandre Belloni, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm
  Cc: Miquel Raynal, linux-rtc, linux-renesas-soc, devicetree,
	Gareth Williams, Milan Stevanovic, Jimmy Lalande,
	Pascal Eberhard, Thomas Petazzoni, Herve Codina, Clement Leger,
	Krzysztof Kozlowski

Add new binding file for this RTC.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 .../bindings/rtc/renesas,rzn1-rtc.yaml        | 70 +++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml

diff --git a/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml b/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml
new file mode 100644
index 000000000000..2d4741f51663
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/renesas,rzn1-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/N1 SoCs Real-Time Clock DT bindings
+
+maintainers:
+  - Miquel Raynal <miquel.raynal@bootlin.com>
+
+allOf:
+  - $ref: rtc.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,r9a06g032-rtc
+      - const: renesas,rzn1-rtc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 3
+    maxItems: 3
+
+  interrupt-names:
+    items:
+      - const: alarm
+      - const: timer
+      - const: pps
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: hclk
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+  - power-domains
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/r9a06g032-sysctrl.h>
+    rtc@40006000 {
+       compatible = "renesas,r9a06g032-rtc", "renesas,rzn1-rtc";
+       reg = <0x40006000 0x1000>;
+       interrupts = <GIC_SPI 66 IRQ_TYPE_EDGE_RISING>,
+                    <GIC_SPI 67 IRQ_TYPE_EDGE_RISING>,
+                    <GIC_SPI 68 IRQ_TYPE_EDGE_RISING>;
+       interrupt-names = "alarm", "timer", "pps";
+       clocks = <&sysctrl R9A06G032_HCLK_RTC>;
+       clock-names = "hclk";
+       power-domains = <&sysctrl>;
+       start-year = <2000>;
+     };
-- 
2.27.0


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

* [PATCH v6 2/5] rtc: rzn1: Add new RTC driver
  2022-05-13 11:03 [PATCH v6 0/5] RZ/N1 RTC support Miquel Raynal
  2022-05-13 11:03 ` [PATCH v6 1/5] dt-bindings: rtc: rzn1: Describe the RZN1 RTC Miquel Raynal
@ 2022-05-13 11:03 ` Miquel Raynal
  2022-05-14  4:29   ` Nobuhiro Iwamatsu
  2022-05-13 11:03 ` [PATCH v6 3/5] rtc: rzn1: Add alarm support Miquel Raynal
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Miquel Raynal @ 2022-05-13 11:03 UTC (permalink / raw)
  To: Alessandro Zummo, Alexandre Belloni, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm
  Cc: Miquel Raynal, linux-rtc, linux-renesas-soc, devicetree,
	Gareth Williams, Milan Stevanovic, Jimmy Lalande,
	Pascal Eberhard, Thomas Petazzoni, Herve Codina, Clement Leger,
	Michel Pollet

From: Michel Pollet <michel.pollet@bp.renesas.com>

Add a basic RTC driver for the RZ/N1.

Signed-off-by: Michel Pollet <michel.pollet@bp.renesas.com>
Co-developed-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/rtc/Kconfig    |   7 ++
 drivers/rtc/Makefile   |   1 +
 drivers/rtc/rtc-rzn1.c | 245 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 253 insertions(+)
 create mode 100644 drivers/rtc/rtc-rzn1.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 41c65b4d2baf..a00f901b5c1d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1548,6 +1548,13 @@ config RTC_DRV_RS5C313
 	help
 	  If you say yes here you get support for the Ricoh RS5C313 RTC chips.
 
+config RTC_DRV_RZN1
+	tristate "Renesas RZ/N1 RTC"
+	depends on ARCH_RZN1 || COMPILE_TEST
+	depends on OF && HAS_IOMEM
+	help
+	  If you say yes here you get support for the Renesas RZ/N1 RTC.
+
 config RTC_DRV_GENERIC
 	tristate "Generic RTC support"
 	# Please consider writing a new RTC driver instead of using the generic
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 2d827d8261d5..fb04467b652d 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -151,6 +151,7 @@ obj-$(CONFIG_RTC_DRV_RX6110)	+= rtc-rx6110.o
 obj-$(CONFIG_RTC_DRV_RX8010)	+= rtc-rx8010.o
 obj-$(CONFIG_RTC_DRV_RX8025)	+= rtc-rx8025.o
 obj-$(CONFIG_RTC_DRV_RX8581)	+= rtc-rx8581.o
+obj-$(CONFIG_RTC_DRV_RZN1)	+= rtc-rzn1.o
 obj-$(CONFIG_RTC_DRV_S35390A)	+= rtc-s35390a.o
 obj-$(CONFIG_RTC_DRV_S3C)	+= rtc-s3c.o
 obj-$(CONFIG_RTC_DRV_S5M)	+= rtc-s5m.o
diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c
new file mode 100644
index 000000000000..685cba87cd90
--- /dev/null
+++ b/drivers/rtc/rtc-rzn1.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Renesas RZ/N1 Real Time Clock interface for Linux
+ *
+ * Copyright:
+ * - 2014 Renesas Electronics Europe Limited
+ * - 2022 Schneider Electric
+ *
+ * Authors:
+ * - Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com>
+ * - Miquel Raynal <miquel.raynal@bootlin.com>
+ */
+
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/rtc.h>
+
+#define RZN1_RTC_CTL0 0x00
+#define   RZN1_RTC_CTL0_SLSB_SUBU 0
+#define   RZN1_RTC_CTL0_SLSB_SCMP BIT(4)
+#define   RZN1_RTC_CTL0_AMPM BIT(5)
+#define   RZN1_RTC_CTL0_CE BIT(7)
+
+#define RZN1_RTC_CTL1 0x04
+#define   RZN1_RTC_CTL1_ALME BIT(4)
+
+#define RZN1_RTC_CTL2 0x08
+#define   RZN1_RTC_CTL2_WAIT BIT(0)
+#define   RZN1_RTC_CTL2_WST BIT(1)
+#define   RZN1_RTC_CTL2_WUST BIT(5)
+#define   RZN1_RTC_CTL2_STOPPED (RZN1_RTC_CTL2_WAIT | RZN1_RTC_CTL2_WST)
+
+#define RZN1_RTC_SEC 0x14
+#define RZN1_RTC_MIN 0x18
+#define RZN1_RTC_HOUR 0x1c
+#define RZN1_RTC_WEEK 0x20
+#define RZN1_RTC_DAY 0x24
+#define RZN1_RTC_MONTH 0x28
+#define RZN1_RTC_YEAR 0x2c
+
+#define RZN1_RTC_SUBU 0x38
+#define   RZN1_RTC_SUBU_DEV BIT(7)
+#define   RZN1_RTC_SUBU_DECR BIT(6)
+
+#define RZN1_RTC_ALM 0x40
+#define RZN1_RTC_ALH 0x44
+#define RZN1_RTC_ALW 0x48
+
+#define RZN1_RTC_SECC 0x4c
+#define RZN1_RTC_MINC 0x50
+#define RZN1_RTC_HOURC 0x54
+#define RZN1_RTC_WEEKC 0x58
+#define RZN1_RTC_DAYC 0x5c
+#define RZN1_RTC_MONTHC 0x60
+#define RZN1_RTC_YEARC 0x64
+
+struct rzn1_rtc {
+	struct rtc_device *rtcdev;
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm)
+{
+	tm->tm_sec = readl(rtc->base + RZN1_RTC_SECC);
+	tm->tm_min = readl(rtc->base + RZN1_RTC_MINC);
+	tm->tm_hour = readl(rtc->base + RZN1_RTC_HOURC);
+	tm->tm_wday = readl(rtc->base + RZN1_RTC_WEEKC);
+	tm->tm_mday = readl(rtc->base + RZN1_RTC_DAYC);
+	tm->tm_mon = readl(rtc->base + RZN1_RTC_MONTHC);
+	tm->tm_year = readl(rtc->base + RZN1_RTC_YEARC);
+}
+
+static unsigned int rzn1_rtc_tm_to_wday(struct rtc_time *tm)
+{
+	time64_t time;
+	unsigned int days;
+	u32 secs;
+
+	time = rtc_tm_to_time64(tm);
+	days = div_s64_rem(time, 86400, &secs);
+
+	/* day of the week, 1970-01-01 was a Thursday */
+	return (days + 4) % 7;
+}
+
+static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rzn1_rtc *rtc = dev_get_drvdata(dev);
+	u32 val, secs;
+
+	/*
+	 * The RTC was not started or is stopped and thus does not carry the
+	 * proper time/date.
+	 */
+	val = readl(rtc->base + RZN1_RTC_CTL2);
+	if (val & RZN1_RTC_CTL2_STOPPED)
+		return -EINVAL;
+
+	rzn1_rtc_get_time_snapshot(rtc, tm);
+	secs = readl(rtc->base + RZN1_RTC_SECC);
+	if (tm->tm_sec != secs)
+		rzn1_rtc_get_time_snapshot(rtc, tm);
+
+	tm->tm_sec = bcd2bin(tm->tm_sec);
+	tm->tm_min = bcd2bin(tm->tm_min);
+	tm->tm_hour = bcd2bin(tm->tm_hour);
+	tm->tm_wday = bcd2bin(tm->tm_wday);
+	tm->tm_mday = bcd2bin(tm->tm_mday);
+	tm->tm_mon = bcd2bin(tm->tm_mon);
+	tm->tm_year = bcd2bin(tm->tm_year);
+
+	return 0;
+}
+
+static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rzn1_rtc *rtc = dev_get_drvdata(dev);
+	u32 val;
+	int ret;
+
+	tm->tm_sec = bin2bcd(tm->tm_sec);
+	tm->tm_min = bin2bcd(tm->tm_min);
+	tm->tm_hour = bin2bcd(tm->tm_hour);
+	tm->tm_wday = bin2bcd(rzn1_rtc_tm_to_wday(tm));
+	tm->tm_mday = bin2bcd(tm->tm_mday);
+	tm->tm_mon = bin2bcd(tm->tm_mon);
+	tm->tm_year = bin2bcd(tm->tm_year);
+
+	val = readl(rtc->base + RZN1_RTC_CTL2);
+	if (!(val & RZN1_RTC_CTL2_STOPPED)) {
+		/* Hold the counter if it was counting up */
+		writel(RZN1_RTC_CTL2_WAIT, rtc->base + RZN1_RTC_CTL2);
+
+		/* Wait for the counter to stop: two 32k clock cycles */
+		usleep_range(61, 100);
+		ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL2, val,
+					 val & RZN1_RTC_CTL2_WST, 0, 100);
+		if (ret)
+			return ret;
+	}
+
+	writel(tm->tm_sec, rtc->base + RZN1_RTC_SEC);
+	writel(tm->tm_min, rtc->base + RZN1_RTC_MIN);
+	writel(tm->tm_hour, rtc->base + RZN1_RTC_HOUR);
+	writel(tm->tm_wday, rtc->base + RZN1_RTC_WEEK);
+	writel(tm->tm_mday, rtc->base + RZN1_RTC_DAY);
+	writel(tm->tm_mon, rtc->base + RZN1_RTC_MONTH);
+	writel(tm->tm_year, rtc->base + RZN1_RTC_YEAR);
+	writel(0, rtc->base + RZN1_RTC_CTL2);
+
+	return 0;
+}
+
+static const struct rtc_class_ops rzn1_rtc_ops = {
+	.read_time = rzn1_rtc_read_time,
+	.set_time = rzn1_rtc_set_time,
+};
+
+static int rzn1_rtc_probe(struct platform_device *pdev)
+{
+	struct rzn1_rtc *rtc;
+	int ret;
+
+	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, rtc);
+
+	rtc->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(rtc->base))
+		return dev_err_probe(&pdev->dev, PTR_ERR(rtc->base), "Missing reg\n");
+
+	rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
+	if (IS_ERR(rtc->rtcdev))
+		return PTR_ERR(rtc);
+
+	rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
+	rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
+	rtc->rtcdev->ops = &rzn1_rtc_ops;
+	clear_bit(RTC_FEATURE_ALARM, rtc->rtcdev->features);
+	clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
+
+	devm_pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_resume_and_get(&pdev->dev);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Ensure the clock counter is enabled.
+	 * Set 24-hour mode and possible oscillator offset compensation in SUBU mode.
+	 */
+	writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | RZN1_RTC_CTL0_SLSB_SUBU,
+	       rtc->base + RZN1_RTC_CTL0);
+
+	/* Disable all interrupts */
+	writel(0, rtc->base + RZN1_RTC_CTL1);
+
+	ret = devm_rtc_register_device(rtc->rtcdev);
+	if (ret)
+		goto dis_runtime_pm;
+
+	return 0;
+
+dis_runtime_pm:
+	pm_runtime_put(&pdev->dev);
+
+	return ret;
+}
+
+static int rzn1_rtc_remove(struct platform_device *pdev)
+{
+	pm_runtime_put(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id rzn1_rtc_of_match[] = {
+	{ .compatible	= "renesas,rzn1-rtc" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rzn1_rtc_of_match);
+
+static struct platform_driver rzn1_rtc_driver = {
+	.probe = rzn1_rtc_probe,
+	.remove = rzn1_rtc_remove,
+	.driver = {
+		.name	= "rzn1-rtc",
+		.owner	= THIS_MODULE,
+		.of_match_table = rzn1_rtc_of_match,
+	},
+};
+module_platform_driver(rzn1_rtc_driver);
+
+MODULE_AUTHOR("Michel Pollet <Michel.Pollet@bp.renesas.com");
+MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com");
+MODULE_DESCRIPTION("RZ/N1 RTC driver");
+MODULE_LICENSE("GPL");
-- 
2.27.0


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

* [PATCH v6 3/5] rtc: rzn1: Add alarm support
  2022-05-13 11:03 [PATCH v6 0/5] RZ/N1 RTC support Miquel Raynal
  2022-05-13 11:03 ` [PATCH v6 1/5] dt-bindings: rtc: rzn1: Describe the RZN1 RTC Miquel Raynal
  2022-05-13 11:03 ` [PATCH v6 2/5] rtc: rzn1: Add new RTC driver Miquel Raynal
@ 2022-05-13 11:03 ` Miquel Raynal
  2022-05-13 11:03 ` [PATCH v6 4/5] rtc: rzn1: Add oscillator offset support Miquel Raynal
  2022-05-13 11:03 ` [PATCH v6 5/5] MAINTAINERS: Add myself as maintainer of the RZN1 RTC driver Miquel Raynal
  4 siblings, 0 replies; 7+ messages in thread
From: Miquel Raynal @ 2022-05-13 11:03 UTC (permalink / raw)
  To: Alessandro Zummo, Alexandre Belloni, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm
  Cc: Miquel Raynal, linux-rtc, linux-renesas-soc, devicetree,
	Gareth Williams, Milan Stevanovic, Jimmy Lalande,
	Pascal Eberhard, Thomas Petazzoni, Herve Codina, Clement Leger

The RZN1 RTC can trigger an interrupt when reaching a particular date up
to 7 days ahead. Bring support for this alarm.

One drawback though, the granularity is about a minute.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/rtc/rtc-rzn1.c | 106 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 105 insertions(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c
index 685cba87cd90..7ee190daa651 100644
--- a/drivers/rtc/rtc-rzn1.c
+++ b/drivers/rtc/rtc-rzn1.c
@@ -158,14 +158,107 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	return 0;
 }
 
+static irqreturn_t rzn1_rtc_alarm_irq(int irq, void *dev_id)
+{
+	struct rzn1_rtc *rtc = dev_id;
+
+	rtc_update_irq(rtc->rtcdev, 1, RTC_AF | RTC_IRQF);
+
+	return IRQ_HANDLED;
+}
+
+static int rzn1_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+	struct rzn1_rtc *rtc = dev_get_drvdata(dev);
+	u32 ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
+
+	if (enable)
+		ctl1 |= RZN1_RTC_CTL1_ALME;
+	else
+		ctl1 &= ~RZN1_RTC_CTL1_ALME;
+
+	writel(ctl1, rtc->base + RZN1_RTC_CTL1);
+
+	return 0;
+}
+
+static int rzn1_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rzn1_rtc *rtc = dev_get_drvdata(dev);
+	struct rtc_time *tm = &alrm->time;
+	unsigned int min, hour, wday, delta_days;
+	time64_t alarm;
+	u32 ctl1;
+	int ret;
+
+	ret = rzn1_rtc_read_time(dev, tm);
+	if (ret)
+		return ret;
+
+	min = readl(rtc->base + RZN1_RTC_ALM);
+	hour = readl(rtc->base + RZN1_RTC_ALH);
+	wday = readl(rtc->base + RZN1_RTC_ALW);
+
+	tm->tm_sec = 0;
+	tm->tm_min = bcd2bin(min);
+	tm->tm_hour = bcd2bin(hour);
+	delta_days = ((fls(wday) - 1) - tm->tm_wday + 7) % 7;
+	tm->tm_wday = fls(wday) - 1;
+
+	if (delta_days) {
+		alarm = rtc_tm_to_time64(tm) + (delta_days * 86400);
+		rtc_time64_to_tm(alarm, tm);
+	}
+
+	ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
+	alrm->enabled = !!(ctl1 & RZN1_RTC_CTL1_ALME);
+
+	return 0;
+}
+
+static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rzn1_rtc *rtc = dev_get_drvdata(dev);
+	struct rtc_time *tm = &alrm->time, tm_now;
+	unsigned long alarm, farest;
+	unsigned int days_ahead, wday;
+	int ret;
+
+	ret = rzn1_rtc_read_time(dev, &tm_now);
+	if (ret)
+		return ret;
+
+	/* We cannot set alarms more than one week ahead */
+	farest = rtc_tm_to_time64(&tm_now) + (7 * 86400);
+	alarm = rtc_tm_to_time64(tm);
+	if (time_after(alarm, farest))
+		return -ERANGE;
+
+	/* Convert alarm day into week day */
+	days_ahead = tm->tm_mday - tm_now.tm_mday;
+	wday = (tm_now.tm_wday + days_ahead) % 7;
+
+	writel(bin2bcd(tm->tm_min), rtc->base + RZN1_RTC_ALM);
+	writel(bin2bcd(tm->tm_hour), rtc->base + RZN1_RTC_ALH);
+	writel(BIT(wday), rtc->base + RZN1_RTC_ALW);
+
+	rzn1_rtc_alarm_irq_enable(dev, alrm->enabled);
+
+	return 0;
+}
+
 static const struct rtc_class_ops rzn1_rtc_ops = {
 	.read_time = rzn1_rtc_read_time,
 	.set_time = rzn1_rtc_set_time,
+	.read_alarm = rzn1_rtc_read_alarm,
+	.set_alarm = rzn1_rtc_set_alarm,
+	.alarm_irq_enable = rzn1_rtc_alarm_irq_enable,
 };
 
 static int rzn1_rtc_probe(struct platform_device *pdev)
 {
 	struct rzn1_rtc *rtc;
+	int alarm_irq;
 	int ret;
 
 	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
@@ -178,6 +271,10 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
 	if (IS_ERR(rtc->base))
 		return dev_err_probe(&pdev->dev, PTR_ERR(rtc->base), "Missing reg\n");
 
+	alarm_irq = platform_get_irq(pdev, 0);
+	if (alarm_irq < 0)
+		return alarm_irq;
+
 	rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
 	if (IS_ERR(rtc->rtcdev))
 		return PTR_ERR(rtc);
@@ -185,7 +282,7 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
 	rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
 	rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
 	rtc->rtcdev->ops = &rzn1_rtc_ops;
-	clear_bit(RTC_FEATURE_ALARM, rtc->rtcdev->features);
+	set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
 	clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
 
 	devm_pm_runtime_enable(&pdev->dev);
@@ -203,6 +300,13 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
 	/* Disable all interrupts */
 	writel(0, rtc->base + RZN1_RTC_CTL1);
 
+	ret = devm_request_irq(&pdev->dev, alarm_irq, rzn1_rtc_alarm_irq, 0,
+			       dev_name(&pdev->dev), rtc);
+	if (ret) {
+		dev_err(&pdev->dev, "RTC timer interrupt not available\n");
+		goto dis_runtime_pm;
+	}
+
 	ret = devm_rtc_register_device(rtc->rtcdev);
 	if (ret)
 		goto dis_runtime_pm;
-- 
2.27.0


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

* [PATCH v6 4/5] rtc: rzn1: Add oscillator offset support
  2022-05-13 11:03 [PATCH v6 0/5] RZ/N1 RTC support Miquel Raynal
                   ` (2 preceding siblings ...)
  2022-05-13 11:03 ` [PATCH v6 3/5] rtc: rzn1: Add alarm support Miquel Raynal
@ 2022-05-13 11:03 ` Miquel Raynal
  2022-05-13 11:03 ` [PATCH v6 5/5] MAINTAINERS: Add myself as maintainer of the RZN1 RTC driver Miquel Raynal
  4 siblings, 0 replies; 7+ messages in thread
From: Miquel Raynal @ 2022-05-13 11:03 UTC (permalink / raw)
  To: Alessandro Zummo, Alexandre Belloni, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm
  Cc: Miquel Raynal, linux-rtc, linux-renesas-soc, devicetree,
	Gareth Williams, Milan Stevanovic, Jimmy Lalande,
	Pascal Eberhard, Thomas Petazzoni, Herve Codina, Clement Leger

The RZN1 RTC can compensate the imprecision of the oscillator up to
approximately 190ppm.

Seconds can last slightly shorter or longer depending on the
configuration.

Below ~65ppm of correction, we can change the time spent in a second
every minute, which is the most accurate compensation that the RTC can
offer. Above, the compensation will be active every 20s.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/rtc/rtc-rzn1.c | 73 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c
index 7ee190daa651..f340793d9fc7 100644
--- a/drivers/rtc/rtc-rzn1.c
+++ b/drivers/rtc/rtc-rzn1.c
@@ -247,12 +247,85 @@ static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 	return 0;
 }
 
+static int rzn1_rtc_read_offset(struct device *dev, long *offset)
+{
+	struct rzn1_rtc *rtc = dev_get_drvdata(dev);
+	unsigned int ppb_per_step;
+	bool subtract;
+	u32 val;
+
+	val = readl(rtc->base + RZN1_RTC_SUBU);
+	ppb_per_step = val & RZN1_RTC_SUBU_DEV ? 1017 : 3051;
+	subtract = val & RZN1_RTC_SUBU_DECR;
+	val &= 0x3F;
+
+	if (!val)
+		*offset = 0;
+	else if (subtract)
+		*offset = -(((~val) & 0x3F) + 1) * ppb_per_step;
+	else
+		*offset = (val - 1) * ppb_per_step;
+
+	return 0;
+}
+
+static int rzn1_rtc_set_offset(struct device *dev, long offset)
+{
+	struct rzn1_rtc *rtc = dev_get_drvdata(dev);
+	unsigned int steps;
+	int stepsh, stepsl;
+	u32 val;
+	int ret;
+
+	/*
+	 * Check which resolution mode (every 20 or 60s) can be used.
+	 * Between 2 and 124 clock pulses can be added or substracted.
+	 *
+	 * In 20s mode, the minimum resolution is 2 / (32768 * 20) which is
+	 * close to 3051 ppb. In 60s mode, the resolution is closer to 1017.
+	 */
+	stepsh = DIV_ROUND_CLOSEST(offset, 1017);
+	stepsl = DIV_ROUND_CLOSEST(offset, 3051);
+
+	if (stepsh >= -0x3E && stepsh <= 0x3E) {
+		/* 1017 ppb per step */
+		steps = stepsh;
+		val |= RZN1_RTC_SUBU_DEV;
+	} else if (stepsl >= -0x3E && stepsl <= 0x3E) {
+		/* 3051 ppb per step */
+		steps = stepsl;
+	} else {
+		return -ERANGE;
+	}
+
+	if (!steps)
+		return 0;
+
+	if (steps > 0) {
+		val |= steps + 1;
+	} else {
+		val |= RZN1_RTC_SUBU_DECR;
+		val |= (~(-steps - 1)) & 0x3F;
+	}
+
+	ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL2, val,
+				 !(val & RZN1_RTC_CTL2_WUST), 100, 2000000);
+	if (ret)
+		return ret;
+
+	writel(val, rtc->base + RZN1_RTC_SUBU);
+
+	return 0;
+}
+
 static const struct rtc_class_ops rzn1_rtc_ops = {
 	.read_time = rzn1_rtc_read_time,
 	.set_time = rzn1_rtc_set_time,
 	.read_alarm = rzn1_rtc_read_alarm,
 	.set_alarm = rzn1_rtc_set_alarm,
 	.alarm_irq_enable = rzn1_rtc_alarm_irq_enable,
+	.read_offset = rzn1_rtc_read_offset,
+	.set_offset = rzn1_rtc_set_offset,
 };
 
 static int rzn1_rtc_probe(struct platform_device *pdev)
-- 
2.27.0


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

* [PATCH v6 5/5] MAINTAINERS: Add myself as maintainer of the RZN1 RTC driver
  2022-05-13 11:03 [PATCH v6 0/5] RZ/N1 RTC support Miquel Raynal
                   ` (3 preceding siblings ...)
  2022-05-13 11:03 ` [PATCH v6 4/5] rtc: rzn1: Add oscillator offset support Miquel Raynal
@ 2022-05-13 11:03 ` Miquel Raynal
  4 siblings, 0 replies; 7+ messages in thread
From: Miquel Raynal @ 2022-05-13 11:03 UTC (permalink / raw)
  To: Alessandro Zummo, Alexandre Belloni, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm
  Cc: Miquel Raynal, linux-rtc, linux-renesas-soc, devicetree,
	Gareth Williams, Milan Stevanovic, Jimmy Lalande,
	Pascal Eberhard, Thomas Petazzoni, Herve Codina, Clement Leger

After contributing it, I'll volunteer to maintain it.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9cf74e4eacce..cc4a3cca022e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16847,6 +16847,14 @@ S:	Supported
 F:	Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
 F:	drivers/iio/adc/rzg2l_adc.c
 
+RENESAS RZ/N1 RTC CONTROLLER DRIVER
+M:	Miquel Raynal <miquel.raynal@bootlin.com>
+L:	linux-rtc@vger.kernel.org
+L:	linux-renesas-soc@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml
+F:	drivers/rtc/rtc-rzn1.c
+
 RENESAS R-CAR GEN3 & RZ/N1 NAND CONTROLLER DRIVER
 M:	Miquel Raynal <miquel.raynal@bootlin.com>
 L:	linux-mtd@lists.infradead.org
-- 
2.27.0


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

* Re: [PATCH v6 2/5] rtc: rzn1: Add new RTC driver
  2022-05-13 11:03 ` [PATCH v6 2/5] rtc: rzn1: Add new RTC driver Miquel Raynal
@ 2022-05-14  4:29   ` Nobuhiro Iwamatsu
  0 siblings, 0 replies; 7+ messages in thread
From: Nobuhiro Iwamatsu @ 2022-05-14  4:29 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Alessandro Zummo, Alexandre Belloni, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, linux-rtc,
	linux-renesas-soc, devicetree, Gareth Williams, Milan Stevanovic,
	Jimmy Lalande, Pascal Eberhard, Thomas Petazzoni, Herve Codina,
	Clement Leger, Michel Pollet

Hi,

2022年5月13日(金) 20:03 Miquel Raynal <miquel.raynal@bootlin.com>:
>
> From: Michel Pollet <michel.pollet@bp.renesas.com>
>
> Add a basic RTC driver for the RZ/N1.
>
> Signed-off-by: Michel Pollet <michel.pollet@bp.renesas.com>
> Co-developed-by: Miquel Raynal <miquel.raynal@bootlin.com>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/rtc/Kconfig    |   7 ++
>  drivers/rtc/Makefile   |   1 +
>  drivers/rtc/rtc-rzn1.c | 245 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 253 insertions(+)
>  create mode 100644 drivers/rtc/rtc-rzn1.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 41c65b4d2baf..a00f901b5c1d 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1548,6 +1548,13 @@ config RTC_DRV_RS5C313
>         help
>           If you say yes here you get support for the Ricoh RS5C313 RTC chips.
>
> +config RTC_DRV_RZN1
> +       tristate "Renesas RZ/N1 RTC"
> +       depends on ARCH_RZN1 || COMPILE_TEST
> +       depends on OF && HAS_IOMEM
> +       help
> +         If you say yes here you get support for the Renesas RZ/N1 RTC.
> +
>  config RTC_DRV_GENERIC
>         tristate "Generic RTC support"
>         # Please consider writing a new RTC driver instead of using the generic
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 2d827d8261d5..fb04467b652d 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -151,6 +151,7 @@ obj-$(CONFIG_RTC_DRV_RX6110)        += rtc-rx6110.o
>  obj-$(CONFIG_RTC_DRV_RX8010)   += rtc-rx8010.o
>  obj-$(CONFIG_RTC_DRV_RX8025)   += rtc-rx8025.o
>  obj-$(CONFIG_RTC_DRV_RX8581)   += rtc-rx8581.o
> +obj-$(CONFIG_RTC_DRV_RZN1)     += rtc-rzn1.o
>  obj-$(CONFIG_RTC_DRV_S35390A)  += rtc-s35390a.o
>  obj-$(CONFIG_RTC_DRV_S3C)      += rtc-s3c.o
>  obj-$(CONFIG_RTC_DRV_S5M)      += rtc-s5m.o
> diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c
> new file mode 100644
> index 000000000000..685cba87cd90
> --- /dev/null
> +++ b/drivers/rtc/rtc-rzn1.c
> @@ -0,0 +1,245 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Renesas RZ/N1 Real Time Clock interface for Linux
> + *
> + * Copyright:
> + * - 2014 Renesas Electronics Europe Limited
> + * - 2022 Schneider Electric
> + *
> + * Authors:
> + * - Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com>
> + * - Miquel Raynal <miquel.raynal@bootlin.com>
> + */
> +
> +#include <linux/bcd.h>
> +#include <linux/clk.h>
> +#include <linux/init.h>
> +#include <linux/iopoll.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/rtc.h>
> +
> +#define RZN1_RTC_CTL0 0x00
> +#define   RZN1_RTC_CTL0_SLSB_SUBU 0
> +#define   RZN1_RTC_CTL0_SLSB_SCMP BIT(4)
> +#define   RZN1_RTC_CTL0_AMPM BIT(5)
> +#define   RZN1_RTC_CTL0_CE BIT(7)
> +
> +#define RZN1_RTC_CTL1 0x04
> +#define   RZN1_RTC_CTL1_ALME BIT(4)
> +
> +#define RZN1_RTC_CTL2 0x08
> +#define   RZN1_RTC_CTL2_WAIT BIT(0)
> +#define   RZN1_RTC_CTL2_WST BIT(1)
> +#define   RZN1_RTC_CTL2_WUST BIT(5)
> +#define   RZN1_RTC_CTL2_STOPPED (RZN1_RTC_CTL2_WAIT | RZN1_RTC_CTL2_WST)
> +
> +#define RZN1_RTC_SEC 0x14
> +#define RZN1_RTC_MIN 0x18
> +#define RZN1_RTC_HOUR 0x1c
> +#define RZN1_RTC_WEEK 0x20
> +#define RZN1_RTC_DAY 0x24
> +#define RZN1_RTC_MONTH 0x28
> +#define RZN1_RTC_YEAR 0x2c
> +
> +#define RZN1_RTC_SUBU 0x38
> +#define   RZN1_RTC_SUBU_DEV BIT(7)
> +#define   RZN1_RTC_SUBU_DECR BIT(6)
> +
> +#define RZN1_RTC_ALM 0x40
> +#define RZN1_RTC_ALH 0x44
> +#define RZN1_RTC_ALW 0x48
> +
> +#define RZN1_RTC_SECC 0x4c
> +#define RZN1_RTC_MINC 0x50
> +#define RZN1_RTC_HOURC 0x54
> +#define RZN1_RTC_WEEKC 0x58
> +#define RZN1_RTC_DAYC 0x5c
> +#define RZN1_RTC_MONTHC 0x60
> +#define RZN1_RTC_YEARC 0x64
> +
> +struct rzn1_rtc {
> +       struct rtc_device *rtcdev;
> +       void __iomem *base;
> +       struct clk *clk;

clk variables do not seem to be used in this patch series.
If it is not used in the future, I think it can be deleted with
'#Include <linux/clk.h>".

> +};
> +
> +static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm)
> +{
> +       tm->tm_sec = readl(rtc->base + RZN1_RTC_SECC);
> +       tm->tm_min = readl(rtc->base + RZN1_RTC_MINC);
> +       tm->tm_hour = readl(rtc->base + RZN1_RTC_HOURC);
> +       tm->tm_wday = readl(rtc->base + RZN1_RTC_WEEKC);
> +       tm->tm_mday = readl(rtc->base + RZN1_RTC_DAYC);
> +       tm->tm_mon = readl(rtc->base + RZN1_RTC_MONTHC);
> +       tm->tm_year = readl(rtc->base + RZN1_RTC_YEARC);
> +}
> +
> +static unsigned int rzn1_rtc_tm_to_wday(struct rtc_time *tm)
> +{
> +       time64_t time;
> +       unsigned int days;
> +       u32 secs;
> +
> +       time = rtc_tm_to_time64(tm);
> +       days = div_s64_rem(time, 86400, &secs);
> +
> +       /* day of the week, 1970-01-01 was a Thursday */
> +       return (days + 4) % 7;
> +}
> +
> +static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +       struct rzn1_rtc *rtc = dev_get_drvdata(dev);
> +       u32 val, secs;
> +
> +       /*
> +        * The RTC was not started or is stopped and thus does not carry the
> +        * proper time/date.
> +        */
> +       val = readl(rtc->base + RZN1_RTC_CTL2);
> +       if (val & RZN1_RTC_CTL2_STOPPED)
> +               return -EINVAL;
> +
> +       rzn1_rtc_get_time_snapshot(rtc, tm);
> +       secs = readl(rtc->base + RZN1_RTC_SECC);
> +       if (tm->tm_sec != secs)
> +               rzn1_rtc_get_time_snapshot(rtc, tm);
> +
> +       tm->tm_sec = bcd2bin(tm->tm_sec);
> +       tm->tm_min = bcd2bin(tm->tm_min);
> +       tm->tm_hour = bcd2bin(tm->tm_hour);
> +       tm->tm_wday = bcd2bin(tm->tm_wday);
> +       tm->tm_mday = bcd2bin(tm->tm_mday);
> +       tm->tm_mon = bcd2bin(tm->tm_mon);
> +       tm->tm_year = bcd2bin(tm->tm_year);
> +
> +       return 0;
> +}
> +
> +static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +       struct rzn1_rtc *rtc = dev_get_drvdata(dev);
> +       u32 val;
> +       int ret;
> +
> +       tm->tm_sec = bin2bcd(tm->tm_sec);
> +       tm->tm_min = bin2bcd(tm->tm_min);
> +       tm->tm_hour = bin2bcd(tm->tm_hour);
> +       tm->tm_wday = bin2bcd(rzn1_rtc_tm_to_wday(tm));
> +       tm->tm_mday = bin2bcd(tm->tm_mday);
> +       tm->tm_mon = bin2bcd(tm->tm_mon);
> +       tm->tm_year = bin2bcd(tm->tm_year);
> +
> +       val = readl(rtc->base + RZN1_RTC_CTL2);
> +       if (!(val & RZN1_RTC_CTL2_STOPPED)) {
> +               /* Hold the counter if it was counting up */
> +               writel(RZN1_RTC_CTL2_WAIT, rtc->base + RZN1_RTC_CTL2);
> +
> +               /* Wait for the counter to stop: two 32k clock cycles */
> +               usleep_range(61, 100);
> +               ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL2, val,
> +                                        val & RZN1_RTC_CTL2_WST, 0, 100);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       writel(tm->tm_sec, rtc->base + RZN1_RTC_SEC);
> +       writel(tm->tm_min, rtc->base + RZN1_RTC_MIN);
> +       writel(tm->tm_hour, rtc->base + RZN1_RTC_HOUR);
> +       writel(tm->tm_wday, rtc->base + RZN1_RTC_WEEK);
> +       writel(tm->tm_mday, rtc->base + RZN1_RTC_DAY);
> +       writel(tm->tm_mon, rtc->base + RZN1_RTC_MONTH);
> +       writel(tm->tm_year, rtc->base + RZN1_RTC_YEAR);
> +       writel(0, rtc->base + RZN1_RTC_CTL2);
> +
> +       return 0;
> +}
> +
> +static const struct rtc_class_ops rzn1_rtc_ops = {
> +       .read_time = rzn1_rtc_read_time,
> +       .set_time = rzn1_rtc_set_time,
> +};
> +
> +static int rzn1_rtc_probe(struct platform_device *pdev)
> +{
> +       struct rzn1_rtc *rtc;
> +       int ret;
> +
> +       rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
> +       if (!rtc)
> +               return -ENOMEM;
> +
> +       platform_set_drvdata(pdev, rtc);
> +
> +       rtc->base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(rtc->base))
> +               return dev_err_probe(&pdev->dev, PTR_ERR(rtc->base), "Missing reg\n");
> +
> +       rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
> +       if (IS_ERR(rtc->rtcdev))
> +               return PTR_ERR(rtc);
> +
> +       rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
> +       rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
> +       rtc->rtcdev->ops = &rzn1_rtc_ops;
> +       clear_bit(RTC_FEATURE_ALARM, rtc->rtcdev->features);
> +       clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
> +
> +       devm_pm_runtime_enable(&pdev->dev);
> +       ret = pm_runtime_resume_and_get(&pdev->dev);
> +       if (ret < 0)
> +               return ret;
> +
> +       /*
> +        * Ensure the clock counter is enabled.
> +        * Set 24-hour mode and possible oscillator offset compensation in SUBU mode.
> +        */
> +       writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | RZN1_RTC_CTL0_SLSB_SUBU,
> +              rtc->base + RZN1_RTC_CTL0);
> +
> +       /* Disable all interrupts */
> +       writel(0, rtc->base + RZN1_RTC_CTL1);
> +
> +       ret = devm_rtc_register_device(rtc->rtcdev);
> +       if (ret)
> +               goto dis_runtime_pm;
> +
> +       return 0;
> +
> +dis_runtime_pm:
> +       pm_runtime_put(&pdev->dev);
> +
> +       return ret;
> +}
> +
> +static int rzn1_rtc_remove(struct platform_device *pdev)
> +{
> +       pm_runtime_put(&pdev->dev);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id rzn1_rtc_of_match[] = {
> +       { .compatible   = "renesas,rzn1-rtc" },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(of, rzn1_rtc_of_match);
> +
> +static struct platform_driver rzn1_rtc_driver = {
> +       .probe = rzn1_rtc_probe,
> +       .remove = rzn1_rtc_remove,
> +       .driver = {
> +               .name   = "rzn1-rtc",
> +               .owner  = THIS_MODULE,
> +               .of_match_table = rzn1_rtc_of_match,
> +       },
> +};
> +module_platform_driver(rzn1_rtc_driver);
> +
> +MODULE_AUTHOR("Michel Pollet <Michel.Pollet@bp.renesas.com");
> +MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com");
> +MODULE_DESCRIPTION("RZ/N1 RTC driver");
> +MODULE_LICENSE("GPL");
> --
> 2.27.0
>

Best regards,
  Nobuhiro


--
Nobuhiro Iwamatsu
   iwamatsu at {nigauri.org / debian.org / kernel.org}
   GPG ID: 40AD1FA6

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

end of thread, other threads:[~2022-05-14  4:29 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-13 11:03 [PATCH v6 0/5] RZ/N1 RTC support Miquel Raynal
2022-05-13 11:03 ` [PATCH v6 1/5] dt-bindings: rtc: rzn1: Describe the RZN1 RTC Miquel Raynal
2022-05-13 11:03 ` [PATCH v6 2/5] rtc: rzn1: Add new RTC driver Miquel Raynal
2022-05-14  4:29   ` Nobuhiro Iwamatsu
2022-05-13 11:03 ` [PATCH v6 3/5] rtc: rzn1: Add alarm support Miquel Raynal
2022-05-13 11:03 ` [PATCH v6 4/5] rtc: rzn1: Add oscillator offset support Miquel Raynal
2022-05-13 11:03 ` [PATCH v6 5/5] MAINTAINERS: Add myself as maintainer of the RZN1 RTC driver Miquel Raynal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).