@@ -56,6 +56,42 @@ struct rk808_rtc {
56
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
95
/* Read current time and date in RTC */
60
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
137
tm -> tm_mon = (bcd2bin (rtc_data [4 ] & MONTHS_REG_MSK )) - 1 ;
102
138
tm -> tm_year = (bcd2bin (rtc_data [5 ] & YEARS_REG_MSK )) + 100 ;
103
139
tm -> tm_wday = bcd2bin (rtc_data [6 ] & WEEKS_REG_MSK );
140
+ rockchip_to_gregorian (tm );
104
141
dev_dbg (dev , "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n" ,
105
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
145
return ret ;
109
146
}
@@ -116,16 +153,17 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
116
153
u8 rtc_data [NUM_TIME_REGS ];
117
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
160
rtc_data [0 ] = bin2bcd (tm -> tm_sec );
120
161
rtc_data [1 ] = bin2bcd (tm -> tm_min );
121
162
rtc_data [2 ] = bin2bcd (tm -> tm_hour );
122
163
rtc_data [3 ] = bin2bcd (tm -> tm_mday );
123
164
rtc_data [4 ] = bin2bcd (tm -> tm_mon + 1 );
124
165
rtc_data [5 ] = bin2bcd (tm -> tm_year - 100 );
125
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
168
/* Stop RTC while updating the RTC registers */
131
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
208
alrm -> time .tm_mday = bcd2bin (alrm_data [3 ] & DAYS_REG_MSK );
171
209
alrm -> time .tm_mon = (bcd2bin (alrm_data [4 ] & MONTHS_REG_MSK )) - 1 ;
172
210
alrm -> time .tm_year = (bcd2bin (alrm_data [5 ] & YEARS_REG_MSK )) + 100 ;
211
+ rockchip_to_gregorian (& alrm -> time );
173
212
174
213
ret = regmap_read (rk808 -> regmap , RK808_RTC_INT_REG , & int_reg );
175
214
if (ret ) {
@@ -227,6 +266,7 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
227
266
alrm -> time .tm_mday , alrm -> time .tm_wday , alrm -> time .tm_hour ,
228
267
alrm -> time .tm_min , alrm -> time .tm_sec );
229
268
269
+ gregorian_to_rockchip (& alrm -> time );
230
270
alrm_data [0 ] = bin2bcd (alrm -> time .tm_sec );
231
271
alrm_data [1 ] = bin2bcd (alrm -> time .tm_min );
232
272
alrm_data [2 ] = bin2bcd (alrm -> time .tm_hour );
0 commit comments