111 lines
3.6 KiB
Diff
111 lines
3.6 KiB
Diff
|
From 5c9c11e2da43d8865cc71e59accf6cad8f04404a Mon Sep 17 00:00:00 2001
|
||
|
From: Andre Przywara <andre.przywara@arm.com>
|
||
|
Date: Fri, 4 Jun 2021 12:12:27 +0100
|
||
|
Subject: [PATCH 014/101] drv:rtc:sun6i: Add support for broken-down alarm
|
||
|
registers
|
||
|
|
||
|
Newer versions of the Allwinner RTC, for instance as found in the H616
|
||
|
SoC, not only store the current day as a linear number, but also change
|
||
|
the way the alarm is handled: There are now two registers, that
|
||
|
explicitly store the wakeup time, in the same format as the current
|
||
|
time.
|
||
|
|
||
|
Add support for that variant by writing the requested wakeup time
|
||
|
directly into the registers, instead of programming the seconds left, as
|
||
|
the old SoCs required.
|
||
|
|
||
|
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||
|
Reviewed by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||
|
---
|
||
|
drivers/rtc/rtc-sun6i.c | 57 +++++++++++++++++++++++++++++------------
|
||
|
1 file changed, 40 insertions(+), 17 deletions(-)
|
||
|
|
||
|
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
|
||
|
index d47389b5f..8e443952c 100644
|
||
|
--- a/drivers/rtc/rtc-sun6i.c
|
||
|
+++ b/drivers/rtc/rtc-sun6i.c
|
||
|
@@ -48,7 +48,8 @@
|
||
|
|
||
|
/* Alarm 0 (counter) */
|
||
|
#define SUN6I_ALRM_COUNTER 0x0020
|
||
|
-#define SUN6I_ALRM_CUR_VAL 0x0024
|
||
|
+/* This holds the remaining alarm seconds on older SoCs (current value) */
|
||
|
+#define SUN6I_ALRM_COUNTER_HMS 0x0024
|
||
|
#define SUN6I_ALRM_EN 0x0028
|
||
|
#define SUN6I_ALRM_EN_CNT_EN BIT(0)
|
||
|
#define SUN6I_ALRM_IRQ_EN 0x002c
|
||
|
@@ -527,32 +528,54 @@ static int sun6i_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||
|
struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
|
||
|
struct rtc_time *alrm_tm = &wkalrm->time;
|
||
|
struct rtc_time tm_now;
|
||
|
- time64_t time_now, time_set;
|
||
|
+ time64_t time_set;
|
||
|
+ u32 counter_val, counter_val_hms;
|
||
|
int ret;
|
||
|
|
||
|
- ret = sun6i_rtc_gettime(dev, &tm_now);
|
||
|
- if (ret < 0) {
|
||
|
- dev_err(dev, "Error in getting time\n");
|
||
|
- return -EINVAL;
|
||
|
- }
|
||
|
-
|
||
|
time_set = rtc_tm_to_time64(alrm_tm);
|
||
|
- time_now = rtc_tm_to_time64(&tm_now);
|
||
|
- if (time_set <= time_now) {
|
||
|
- dev_err(dev, "Date to set in the past\n");
|
||
|
- return -EINVAL;
|
||
|
- }
|
||
|
|
||
|
- if ((time_set - time_now) > U32_MAX) {
|
||
|
- dev_err(dev, "Date too far in the future\n");
|
||
|
- return -EINVAL;
|
||
|
+ if (chip->flags & RTC_LINEAR_DAY) {
|
||
|
+ /*
|
||
|
+ * The alarm registers hold the actual alarm time, encoded
|
||
|
+ * in the same way (linear day + HMS) as the current time.
|
||
|
+ */
|
||
|
+ counter_val_hms = SUN6I_TIME_SET_SEC_VALUE(alrm_tm->tm_sec) |
|
||
|
+ SUN6I_TIME_SET_MIN_VALUE(alrm_tm->tm_min) |
|
||
|
+ SUN6I_TIME_SET_HOUR_VALUE(alrm_tm->tm_hour);
|
||
|
+ /* The division will cut off the H:M:S part of alrm_tm. */
|
||
|
+ counter_val = div_u64(rtc_tm_to_time64(alrm_tm), SECS_PER_DAY);
|
||
|
+ } else {
|
||
|
+ /* The alarm register holds the number of seconds left. */
|
||
|
+ time64_t time_now;
|
||
|
+
|
||
|
+ ret = sun6i_rtc_gettime(dev, &tm_now);
|
||
|
+ if (ret < 0) {
|
||
|
+ dev_err(dev, "Error in getting time\n");
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ time_now = rtc_tm_to_time64(&tm_now);
|
||
|
+ if (time_set <= time_now) {
|
||
|
+ dev_err(dev, "Date to set in the past\n");
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+ if ((time_set - time_now) > U32_MAX) {
|
||
|
+ dev_err(dev, "Date too far in the future\n");
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ counter_val = time_set - time_now;
|
||
|
}
|
||
|
|
||
|
sun6i_rtc_setaie(0, chip);
|
||
|
writel(0, chip->base + SUN6I_ALRM_COUNTER);
|
||
|
+ if (chip->flags & RTC_LINEAR_DAY)
|
||
|
+ writel(0, chip->base + SUN6I_ALRM_COUNTER_HMS);
|
||
|
usleep_range(100, 300);
|
||
|
|
||
|
- writel(time_set - time_now, chip->base + SUN6I_ALRM_COUNTER);
|
||
|
+ writel(counter_val, chip->base + SUN6I_ALRM_COUNTER);
|
||
|
+ if (chip->flags & RTC_LINEAR_DAY)
|
||
|
+ writel(counter_val_hms, chip->base + SUN6I_ALRM_COUNTER_HMS);
|
||
|
chip->alarm = time_set;
|
||
|
|
||
|
sun6i_rtc_setaie(wkalrm->enabled, chip);
|
||
|
--
|
||
|
2.31.1
|
||
|
|