summaryrefslogtreecommitdiff
path: root/drivers/rtc/class.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-04-04 20:38:01 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2020-04-04 20:38:01 +0300
commitbdabb68931b9360bf18b498062f1ac90bec46633 (patch)
tree67fef8fc22d5bb8fbd4bef4281afb76310dd34d3 /drivers/rtc/class.c
parent828907ef25e0133f50c346ef5a3c79a707a9b100 (diff)
parent1821b79d6a7d6973d1630e71380da8bb5e95f3a5 (diff)
downloadlinux-bdabb68931b9360bf18b498062f1ac90bec46633.tar.xz
Merge tag 'rtc-5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni: "More cleanup this cycle, with the final goal of removing the rtc_time_to_tm and rtc_tm_to_time wrappers. All the drivers that have been modified for this now are ready for the end of times (whether it happens in 2033, 2038, 2106, 2127 or even 4052). There is also a single new driver and the usual fixes and features. Summary: Subsystem: - The rtc_time_to_tm and rtc_tm_to_time wrappers have finally been removed and only the 64bit version remain. - hctosys now works with drivers compiled as modules New driver: - MediaTek MT2712 SoC based RTC Drivers: - set range for 88pm860x, au1xxx, cpcap, da9052, davinci, ds1305, ds1374, mcp5121, pl030, pl031, pm8xxx, puv3, sa1100, sirfsoc, starfire, sun6i - ds1307: DS1388 oscillator failure detection and watchdog support - jz4740: JZ4760 support - pcf85063: clock out pin support - sun6i: external 32k oscillator is now optional, the range is now handled by the core, providing a solution for 2034" * tag 'rtc-5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (87 commits) rtc: ds1307: check for failed memory allocation on wdt rtc: class: remove redundant assignment to variable err rtc: remove rtc_time_to_tm and rtc_tm_to_time rtc: sun6i: let the core handle rtc range rtc: sun6i: switch to rtc_time64_to_tm/rtc_tm_to_time64 rtc: ds1307: add support for watchdog timer on ds1388 rtc: da9052: switch to rtc_time64_to_tm/rtc_tm_to_time64 rtc: da9052: set range rtc: da9052: convert to devm_rtc_allocate_device rtc: imx-sc: Align imx sc msg structs to 4 rtc: fsl-ftm-alarm: report alarm to core rtc: pcf85063: Add pcf85063 clkout control to common clock framework rtc: make definitions in include/uapi/linux/rtc.h actually useful for user space rtc: class: avoid unnecessary lookup in hctosys dt-bindings: rtc: Convert and update jz4740-rtc doc to YAML rtc: jz4740: Rename vendor-specific DT properties rtc: jz4740: Add support for JZ4760 SoC rtc: class: support hctosys from modular RTC drivers rtc: pm8xxx: clear alarm register when alarm is not enabled rtc: omap: drop unused dt-bindings header ...
Diffstat (limited to 'drivers/rtc/class.c')
-rw-r--r--drivers/rtc/class.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 9458e6d6686a..7c88d190c51f 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -34,6 +34,50 @@ static void rtc_device_release(struct device *dev)
#ifdef CONFIG_RTC_HCTOSYS_DEVICE
/* Result of the last RTC to system clock attempt. */
int rtc_hctosys_ret = -ENODEV;
+
+/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
+ * whether it stores the most close value or the value with partial
+ * seconds truncated. However, it is important that we use it to store
+ * the truncated value. This is because otherwise it is necessary,
+ * in an rtc sync function, to read both xtime.tv_sec and
+ * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
+ * of >32bits is not possible. So storing the most close value would
+ * slow down the sync API. So here we have the truncated value and
+ * the best guess is to add 0.5s.
+ */
+
+static void rtc_hctosys(struct rtc_device *rtc)
+{
+ int err;
+ struct rtc_time tm;
+ struct timespec64 tv64 = {
+ .tv_nsec = NSEC_PER_SEC >> 1,
+ };
+
+ err = rtc_read_time(rtc, &tm);
+ if (err) {
+ dev_err(rtc->dev.parent,
+ "hctosys: unable to read the hardware clock\n");
+ goto err_read;
+ }
+
+ tv64.tv_sec = rtc_tm_to_time64(&tm);
+
+#if BITS_PER_LONG == 32
+ if (tv64.tv_sec > INT_MAX) {
+ err = -ERANGE;
+ goto err_read;
+ }
+#endif
+
+ err = do_settimeofday64(&tv64);
+
+ dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
+ &tm, (long long)tv64.tv_sec);
+
+err_read:
+ rtc_hctosys_ret = err;
+}
#endif
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
@@ -375,6 +419,11 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
dev_info(rtc->dev.parent, "registered as %s\n",
dev_name(&rtc->dev));
+#ifdef CONFIG_RTC_HCTOSYS_DEVICE
+ if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE))
+ rtc_hctosys(rtc);
+#endif
+
return 0;
}
EXPORT_SYMBOL_GPL(__rtc_register_device);