diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-12-20 13:01:11 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-12-20 13:01:11 -0500 |
commit | 9f7e43278605a0daf4edf7025c52c25e9ace6875 (patch) | |
tree | 91e57b00168a0a55c1cee90ccc42f0f009973461 /drivers/rtc | |
parent | 69c37a92ddbf79d9672230f21a04580d7ac2f4c3 (diff) | |
parent | 77535acedc26627f16a1a39c1471f942689fe11e (diff) |
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
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-da9063.c | 19 | ||||
-rw-r--r-- | drivers/rtc/rtc-rk808.c | 48 |
2 files changed, 53 insertions, 14 deletions
diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 284b587da65c..d6c853bbfa9f 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c | |||
@@ -483,24 +483,23 @@ static int da9063_rtc_probe(struct platform_device *pdev) | |||
483 | 483 | ||
484 | platform_set_drvdata(pdev, rtc); | 484 | platform_set_drvdata(pdev, rtc); |
485 | 485 | ||
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 | |||
486 | irq_alarm = platform_get_irq_byname(pdev, "ALARM"); | 494 | irq_alarm = platform_get_irq_byname(pdev, "ALARM"); |
487 | ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL, | 495 | ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL, |
488 | da9063_alarm_event, | 496 | da9063_alarm_event, |
489 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 497 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
490 | "ALARM", rtc); | 498 | "ALARM", rtc); |
491 | if (ret) { | 499 | if (ret) |
492 | dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", | 500 | dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", |
493 | irq_alarm, ret); | 501 | 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); | ||
501 | 502 | ||
502 | da9063_data_to_tm(data, &rtc->alarm_time, rtc); | ||
503 | rtc->rtc_sync = false; | ||
504 | return ret; | 503 | return ret; |
505 | } | 504 | } |
506 | 505 | ||
diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c index 91ca0bc1b484..35c9aada07c8 100644 --- a/drivers/rtc/rtc-rk808.c +++ b/drivers/rtc/rtc-rk808.c | |||
@@ -56,6 +56,42 @@ struct rk808_rtc { | |||
56 | int irq; | 56 | int irq; |
57 | }; | 57 | }; |
58 | 58 | ||
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 | |||
59 | /* Read current time and date in RTC */ | 95 | /* Read current time and date in RTC */ |
60 | static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) | 96 | static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) |
61 | { | 97 | { |
@@ -101,9 +137,10 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) | |||
101 | tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1; | 137 | tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1; |
102 | tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100; | 138 | tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100; |
103 | tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK); | 139 | tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK); |
140 | rockchip_to_gregorian(tm); | ||
104 | dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", | 141 | dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", |
105 | 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, | 142 | 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); |
107 | 144 | ||
108 | return ret; | 145 | return ret; |
109 | } | 146 | } |
@@ -116,6 +153,10 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
116 | u8 rtc_data[NUM_TIME_REGS]; | 153 | u8 rtc_data[NUM_TIME_REGS]; |
117 | int ret; | 154 | int ret; |
118 | 155 | ||
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); | ||
119 | rtc_data[0] = bin2bcd(tm->tm_sec); | 160 | rtc_data[0] = bin2bcd(tm->tm_sec); |
120 | rtc_data[1] = bin2bcd(tm->tm_min); | 161 | rtc_data[1] = bin2bcd(tm->tm_min); |
121 | rtc_data[2] = bin2bcd(tm->tm_hour); | 162 | rtc_data[2] = bin2bcd(tm->tm_hour); |
@@ -123,9 +164,6 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
123 | rtc_data[4] = bin2bcd(tm->tm_mon + 1); | 164 | rtc_data[4] = bin2bcd(tm->tm_mon + 1); |
124 | rtc_data[5] = bin2bcd(tm->tm_year - 100); | 165 | rtc_data[5] = bin2bcd(tm->tm_year - 100); |
125 | rtc_data[6] = bin2bcd(tm->tm_wday); | 166 | 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); | ||
129 | 167 | ||
130 | /* Stop RTC while updating the RTC registers */ | 168 | /* Stop RTC while updating the RTC registers */ |
131 | ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG, | 169 | 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) | |||
170 | alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK); | 208 | alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK); |
171 | alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1; | 209 | alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1; |
172 | alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100; | 210 | alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100; |
211 | rockchip_to_gregorian(&alrm->time); | ||
173 | 212 | ||
174 | ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg); | 213 | ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg); |
175 | if (ret) { | 214 | if (ret) { |
@@ -227,6 +266,7 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
227 | alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, | 266 | alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, |
228 | alrm->time.tm_min, alrm->time.tm_sec); | 267 | alrm->time.tm_min, alrm->time.tm_sec); |
229 | 268 | ||
269 | gregorian_to_rockchip(&alrm->time); | ||
230 | alrm_data[0] = bin2bcd(alrm->time.tm_sec); | 270 | alrm_data[0] = bin2bcd(alrm->time.tm_sec); |
231 | alrm_data[1] = bin2bcd(alrm->time.tm_min); | 271 | alrm_data[1] = bin2bcd(alrm->time.tm_min); |
232 | alrm_data[2] = bin2bcd(alrm->time.tm_hour); | 272 | alrm_data[2] = bin2bcd(alrm->time.tm_hour); |