Thread (8 messages) read the whole thread 8 messages, 3 authors, 2016-07-07

[rtc-linux] Re: [PATCH] rtc: sunxi: use external oscillator

From: Maxime Ripard <hidden>
Date: 2016-07-06 20:20:01

On Wed, Jul 06, 2016 at 10:43:00AM +0200, Stephan Roslen wrote:
We noticed some serious drift problems in Allwinner A20 RTCs. I
found out, that the oscillator source needs to be set to an external
32.768 KHz oscillator instead of the internal 32.000 KHz oscillator.
You should wrap the commit description.
quoted hunk ↗ jump to hunk
Signed-off-by: Stephan Roslen <redacted>
---
 drivers/rtc/rtc-sunxi.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c
index abada60..001256e 100644
--- a/drivers/rtc/rtc-sunxi.c
+++ b/drivers/rtc/rtc-sunxi.c
@@ -34,9 +34,19 @@
 #include <linux/types.h>
 
 #define SUNXI_LOSC_CTRL				0x0000
+
+/* magic number required to set bit 0 */
+#define SUNXI_LOSC_CTRL_KEY			0x16AA0000
+
+#define SUNXI_LOSC_CTRL_AUTO_SWT_EN		BIT(14)
+
 #define SUNXI_LOSC_CTRL_RTC_HMS_ACC		BIT(8)
 #define SUNXI_LOSC_CTRL_RTC_YMD_ACC		BIT(7)
 
+#define SUNXI_LOSC_CTRL_EXT_GSM1		BIT(3)
+#define SUNXI_LOSC_CTRL_EXT_GSM0		BIT(2)
+#define SUNXI_LOSC_CTRL_SRC_SEL			BIT(0)
+
 #define SUNXI_RTC_YMD				0x0004
 
 #define SUNXI_RTC_HMS				0x0008
@@ -438,6 +448,8 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
 	struct resource *res;
 	int ret;
 
+	uint32_t loscctrl;
+
 	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
@@ -468,6 +480,19 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	loscctrl = readl(chip->base + SUNXI_LOSC_CTRL);
+	loscctrl &= ~(SUNXI_LOSC_CTRL_AUTO_SWT_EN);
+	loscctrl |= (SUNXI_LOSC_CTRL_SRC_SEL | SUNXI_LOSC_CTRL_KEY);
+	loscctrl |= SUNXI_LOSC_CTRL_EXT_GSM1;
+	writel(loscctrl, chip->base + SUNXI_LOSC_CTRL);
+	udelay(100);
Why is that udelay needed?
+
+	loscctrl = readl(chip->base + SUNXI_LOSC_CTRL);
+	if (!(loscctrl & SUNXI_LOSC_CTRL_SRC_SEL)) {
+		dev_err(&pdev->dev, "Error: Set LOSC to external failed.\n");
+		dev_err(&pdev->dev, "Warning: RTC time will be wrong!\n");
+	}
+
This isn't needed

The issue is actually worse than that.

That register controls the losc source for the whole clock tree, so it
will affect every clock in the system.

In order to have that correctly propagated, you should register a new
mux here in the clock framework, and have all the other clocks using
that mux as a parent.

That's going to be tricky, because the clocks usually probe way
earlier than the RTC driver. So I'm guessing you could do a clock
driver that maps the registers, register its clock, and then when the
RTC probes just takes over what has been setup already by the clock
driver. This also means removing the ability for the RTC to be
compiled as a module.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

-- 
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
--- 
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help