Skip to content

Commit 9f7e432

Browse files
committed
Merge tag 'rtc-4.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC fixes from Alexandre Belloni: "Late fixes for the RTC subsystem for 4.4: A fix for a nasty hardware bug in rk808 and an initialization reordering in da9063 to fix a possible crash" * tag 'rtc-4.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: rtc: da9063: fix access ordering error during RTC interrupt at system power on rtc: rk808: Compensate for Rockchip calendar deviation on November 31st
2 parents 69c37a9 + 77535ac commit 9f7e432

File tree

2 files changed

+53
-14
lines changed

2 files changed

+53
-14
lines changed

drivers/rtc/rtc-da9063.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -483,24 +483,23 @@ static int da9063_rtc_probe(struct platform_device *pdev)
483483

484484
platform_set_drvdata(pdev, rtc);
485485

486+
rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
487+
&da9063_rtc_ops, THIS_MODULE);
488+
if (IS_ERR(rtc->rtc_dev))
489+
return PTR_ERR(rtc->rtc_dev);
490+
491+
da9063_data_to_tm(data, &rtc->alarm_time, rtc);
492+
rtc->rtc_sync = false;
493+
486494
irq_alarm = platform_get_irq_byname(pdev, "ALARM");
487495
ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
488496
da9063_alarm_event,
489497
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
490498
"ALARM", rtc);
491-
if (ret) {
499+
if (ret)
492500
dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
493501
irq_alarm, ret);
494-
return ret;
495-
}
496-
497-
rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
498-
&da9063_rtc_ops, THIS_MODULE);
499-
if (IS_ERR(rtc->rtc_dev))
500-
return PTR_ERR(rtc->rtc_dev);
501502

502-
da9063_data_to_tm(data, &rtc->alarm_time, rtc);
503-
rtc->rtc_sync = false;
504503
return ret;
505504
}
506505

drivers/rtc/rtc-rk808.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,42 @@ struct rk808_rtc {
5656
int irq;
5757
};
5858

59+
/*
60+
* The Rockchip calendar used by the RK808 counts November with 31 days. We use
61+
* these translation functions to convert its dates to/from the Gregorian
62+
* calendar used by the rest of the world. We arbitrarily define Jan 1st, 2016
63+
* as the day when both calendars were in sync, and treat all other dates
64+
* relative to that.
65+
* NOTE: Other system software (e.g. firmware) that reads the same hardware must
66+
* implement this exact same conversion algorithm, with the same anchor date.
67+
*/
68+
static time64_t nov2dec_transitions(struct rtc_time *tm)
69+
{
70+
return (tm->tm_year + 1900) - 2016 + (tm->tm_mon + 1 > 11 ? 1 : 0);
71+
}
72+
73+
static void rockchip_to_gregorian(struct rtc_time *tm)
74+
{
75+
/* If it's Nov 31st, rtc_tm_to_time64() will count that like Dec 1st */
76+
time64_t time = rtc_tm_to_time64(tm);
77+
rtc_time64_to_tm(time + nov2dec_transitions(tm) * 86400, tm);
78+
}
79+
80+
static void gregorian_to_rockchip(struct rtc_time *tm)
81+
{
82+
time64_t extra_days = nov2dec_transitions(tm);
83+
time64_t time = rtc_tm_to_time64(tm);
84+
rtc_time64_to_tm(time - extra_days * 86400, tm);
85+
86+
/* Compensate if we went back over Nov 31st (will work up to 2381) */
87+
if (nov2dec_transitions(tm) < extra_days) {
88+
if (tm->tm_mon + 1 == 11)
89+
tm->tm_mday++; /* This may result in 31! */
90+
else
91+
rtc_time64_to_tm(time - (extra_days - 1) * 86400, tm);
92+
}
93+
}
94+
5995
/* Read current time and date in RTC */
6096
static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
6197
{
@@ -101,9 +137,10 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
101137
tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1;
102138
tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100;
103139
tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK);
140+
rockchip_to_gregorian(tm);
104141
dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
105142
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
106-
tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
143+
tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
107144

108145
return ret;
109146
}
@@ -116,16 +153,17 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
116153
u8 rtc_data[NUM_TIME_REGS];
117154
int ret;
118155

156+
dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
157+
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
158+
tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
159+
gregorian_to_rockchip(tm);
119160
rtc_data[0] = bin2bcd(tm->tm_sec);
120161
rtc_data[1] = bin2bcd(tm->tm_min);
121162
rtc_data[2] = bin2bcd(tm->tm_hour);
122163
rtc_data[3] = bin2bcd(tm->tm_mday);
123164
rtc_data[4] = bin2bcd(tm->tm_mon + 1);
124165
rtc_data[5] = bin2bcd(tm->tm_year - 100);
125166
rtc_data[6] = bin2bcd(tm->tm_wday);
126-
dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
127-
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
128-
tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
129167

130168
/* Stop RTC while updating the RTC registers */
131169
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
@@ -170,6 +208,7 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
170208
alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK);
171209
alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1;
172210
alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100;
211+
rockchip_to_gregorian(&alrm->time);
173212

174213
ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg);
175214
if (ret) {
@@ -227,6 +266,7 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
227266
alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour,
228267
alrm->time.tm_min, alrm->time.tm_sec);
229268

269+
gregorian_to_rockchip(&alrm->time);
230270
alrm_data[0] = bin2bcd(alrm->time.tm_sec);
231271
alrm_data[1] = bin2bcd(alrm->time.tm_min);
232272
alrm_data[2] = bin2bcd(alrm->time.tm_hour);

0 commit comments

Comments
 (0)