diff options
Diffstat (limited to 'firmware/drivers/rtc/rtc_jz4740.c')
-rw-r--r-- | firmware/drivers/rtc/rtc_jz4740.c | 291 |
1 files changed, 39 insertions, 252 deletions
diff --git a/firmware/drivers/rtc/rtc_jz4740.c b/firmware/drivers/rtc/rtc_jz4740.c index a73f300aa8..b82978ed21 100644 --- a/firmware/drivers/rtc/rtc_jz4740.c +++ b/firmware/drivers/rtc/rtc_jz4740.c | |||
@@ -30,281 +30,68 @@ | |||
30 | #include "timefuncs.h" | 30 | #include "timefuncs.h" |
31 | #include "logf.h" | 31 | #include "logf.h" |
32 | 32 | ||
33 | static const unsigned int yearday[5] = {0, 366, 366+365, 366+365*2, 366+365*3}; | 33 | /* Stolen from dietlibc-0.29/libugly/gmtime_r.c (GPLv2) */ |
34 | static const unsigned int sweekday = 6; | 34 | #define SPD (24*60*60) |
35 | static const unsigned int sum_monthday[13] = { | 35 | #define ISLEAP(year) (!(year%4) && ((year%100) || !(year%400))) |
36 | 0, | 36 | static void _localtime(const time_t t, struct tm *r) |
37 | 31, | ||
38 | 31+28, | ||
39 | 31+28+31, | ||
40 | 31+28+31+30, | ||
41 | 31+28+31+30+31, | ||
42 | 31+28+31+30+31+30, | ||
43 | 31+28+31+30+31+30+31, | ||
44 | 31+28+31+30+31+30+31+31, | ||
45 | 31+28+31+30+31+30+31+31+30, | ||
46 | 31+28+31+30+31+30+31+31+30+31, | ||
47 | 31+28+31+30+31+30+31+31+30+31+30, | ||
48 | 365 | ||
49 | }; | ||
50 | |||
51 | static unsigned int jz_mktime(int year, int mon, int day, int hour, int min, | ||
52 | int sec) | ||
53 | { | 37 | { |
54 | unsigned int seccounter; | 38 | time_t i; |
39 | register time_t work = t % SPD; | ||
40 | static int m_to_d[12] = /* This could be shared with mktime() */ | ||
41 | {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; | ||
42 | |||
43 | r->tm_sec = work % 60; | ||
44 | work /= 60; | ||
45 | r->tm_min = work % 60; | ||
46 | r->tm_hour = work / 60; | ||
47 | work = t / SPD; | ||
48 | r->tm_wday = (4 + work) % 7; | ||
49 | |||
50 | for (i=1970; ; ++i) | ||
51 | { | ||
52 | register time_t k = ISLEAP(i) ? 366 : 365; | ||
55 | 53 | ||
56 | if (year < 2000) | 54 | if (work >= k) |
57 | year = 2000; | 55 | work -= k; |
58 | year -= 2000; | ||
59 | seccounter = (year/4)*(365*3+366); | ||
60 | seccounter += yearday[year%4]; | ||
61 | if (year%4) | ||
62 | seccounter += sum_monthday[mon-1]; | ||
63 | else | ||
64 | if (mon >= 3) | ||
65 | seccounter += sum_monthday[mon-1]+1; | ||
66 | else | 56 | else |
67 | seccounter += sum_monthday[mon-1]; | ||
68 | seccounter += day-1; | ||
69 | seccounter *= 24; | ||
70 | seccounter += hour; | ||
71 | seccounter *= 60; | ||
72 | seccounter += min; | ||
73 | seccounter *= 60; | ||
74 | seccounter += sec; | ||
75 | |||
76 | return seccounter; | ||
77 | } | ||
78 | |||
79 | static void jz_gettime(unsigned int rtc, int *year, int *mon, int *day, | ||
80 | int *hour, int *min, int *sec, int *weekday) | ||
81 | { | ||
82 | unsigned int tday, tsec, i, tmp; | ||
83 | |||
84 | tday = rtc/(24*3600); | ||
85 | *weekday = ((tday % 7) + sweekday) % 7; | ||
86 | *year = (tday/(366+365*3)) * 4; | ||
87 | tday = tday%(366+365*3); | ||
88 | for (i=0;i<5;i++) | ||
89 | { | ||
90 | if (tday<yearday[i]) | ||
91 | { | ||
92 | *year += i-1; | ||
93 | tday -= yearday[i-1]; | ||
94 | break; | 57 | break; |
95 | } | ||
96 | } | 58 | } |
97 | for (i=0;i<13;i++) | 59 | |
60 | r->tm_year = i - 1900; | ||
61 | r->tm_yday = work; | ||
62 | |||
63 | r->tm_mday = 1; | ||
64 | if (ISLEAP(i) && (work>58)) | ||
98 | { | 65 | { |
99 | tmp = sum_monthday[i]; | 66 | if (work==59) |
100 | if (((*year%4) == 0) && (i>=2)) | 67 | r->tm_mday=2; /* 29.2. */ |
101 | tmp += 1; | 68 | |
102 | if (tday<tmp) | 69 | work-=1; |
103 | { | ||
104 | *mon = i; | ||
105 | tmp = sum_monthday[i-1]; | ||
106 | if (((*year%4) == 0) && ((i-1)>=2)) | ||
107 | tmp += 1; | ||
108 | *day = tday - tmp + 1; | ||
109 | break; | ||
110 | } | ||
111 | } | 70 | } |
112 | tsec = rtc % (24 * 3600); | 71 | |
113 | *hour = tsec / 3600; | 72 | for (i=11; i && (m_to_d[i] > work); --i); |
114 | *min = (tsec / 60) % 60; | 73 | r->tm_mon = i; |
115 | *sec = tsec - *hour*3600 - *min*60; | 74 | r->tm_mday += work - m_to_d[i]; |
116 | *year += 2000; | ||
117 | } | 75 | } |
118 | 76 | ||
119 | int rtc_read_datetime(struct tm *tm) | 77 | int rtc_read_datetime(struct tm *tm) |
120 | { | 78 | { |
121 | unsigned int sec,mon,mday,wday,year,hour,min; | 79 | _localtime(REG_RTC_RSR, tm); |
122 | |||
123 | /* | ||
124 | * Only the values that we read from the RTC are set. We leave | ||
125 | * tm_wday, tm_yday and tm_isdst untouched. Even though the | ||
126 | * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated | ||
127 | * by the RTC when initially set to a non-zero value. | ||
128 | */ | ||
129 | jz_gettime(REG_RTC_RSR, &year, &mon, &mday, &hour, &min, &sec, &wday); | ||
130 | |||
131 | year -= 2000; | ||
132 | |||
133 | tm->tm_sec = sec; | ||
134 | tm->tm_min = min; | ||
135 | tm->tm_hour = hour; | ||
136 | tm->tm_mday = mday; | ||
137 | tm->tm_wday = wday; | ||
138 | /* Don't use centry, but start from year 1970 */ | ||
139 | tm->tm_mon = mon; | ||
140 | if (year <= 69) | ||
141 | year += 100; | ||
142 | tm->tm_year = year; | ||
143 | 80 | ||
144 | return 1; | 81 | return 1; |
145 | } | 82 | } |
146 | 83 | ||
147 | int rtc_write_datetime(const struct tm *tm) | 84 | int rtc_write_datetime(const struct tm *tm) |
148 | { | 85 | { |
149 | unsigned int year, lval; | 86 | time_t val = mktime((struct tm*)tm); |
150 | |||
151 | year = tm->tm_year; | ||
152 | /* Don't use centry, but start from year 1970 */ | ||
153 | if (year > 69) | ||
154 | year -= 100; | ||
155 | year += 2000; | ||
156 | |||
157 | lval = jz_mktime(year, tm->tm_mon, tm->tm_mday, tm->tm_hour, | ||
158 | tm->tm_min, tm->tm_sec); | ||
159 | 87 | ||
160 | __cpm_start_rtc(); | 88 | __cpm_start_rtc(); |
161 | udelay(100); | 89 | udelay(100); |
162 | REG_RTC_RSR = lval; | 90 | REG_RTC_RSR = val; |
163 | __cpm_stop_rtc(); | 91 | __cpm_stop_rtc(); |
164 | |||
165 | return 0; | ||
166 | } | ||
167 | 92 | ||
168 | #if 0 | 93 | return 0; |
169 | void get_rtc_alm_time(struct rtc_time *alm_tm) | ||
170 | { | ||
171 | unsigned int sec,mon,mday,wday,year,hour,min; | ||
172 | unsigned int lval; | ||
173 | unsigned long flags; | ||
174 | /* | ||
175 | * Only the values that we read from the RTC are set. That | ||
176 | * means only tm_hour, tm_min, and tm_sec. | ||
177 | */ | ||
178 | lval = REG_RTC_RSAR; | ||
179 | jz_gettime(lval, &year, &mon, &mday, &hour, &min, &sec, &wday); | ||
180 | |||
181 | alm_tm->tm_sec = sec; | ||
182 | alm_tm->tm_min = min; | ||
183 | alm_tm->tm_hour = hour; | ||
184 | } | ||
185 | |||
186 | |||
187 | int rtc_ioctl(unsigned int cmd,struct rtc_time *val,unsigned int epo) | ||
188 | { | ||
189 | struct rtc_time wtime; | ||
190 | switch (cmd) { | ||
191 | case RTC_ALM_READ: /* Read the present alarm time */ | ||
192 | /* | ||
193 | * This returns a struct rtc_time. Reading >= 0xc0 | ||
194 | * means "don't care" or "match all". Only the tm_hour, | ||
195 | * tm_min, and tm_sec values are filled in. | ||
196 | */ | ||
197 | get_rtc_alm_time(val); | ||
198 | break; | ||
199 | case RTC_ALM_SET: /* Store a time into the alarm */ | ||
200 | { | ||
201 | unsigned char ahrs, amin, asec; | ||
202 | unsigned int sec,mon,mday,wday,year,hour,min; | ||
203 | unsigned int lval; | ||
204 | unsigned long flags; | ||
205 | struct rtc_time alm_tm; | ||
206 | |||
207 | alm_tm = *val; | ||
208 | ahrs = alm_tm.tm_hour; | ||
209 | amin = alm_tm.tm_min; | ||
210 | asec = alm_tm.tm_sec; | ||
211 | |||
212 | |||
213 | |||
214 | if (ahrs >= 24) | ||
215 | return -1; | ||
216 | |||
217 | if (amin >= 60) | ||
218 | return -1; | ||
219 | |||
220 | if (asec >= 60) | ||
221 | return -1; | ||
222 | |||
223 | flags = spin_lock_irqsave(); | ||
224 | lval = REG_RTC_RSR; | ||
225 | jz_gettime(lval, &year, &mon, &mday, &hour, &min, &sec, &wday); | ||
226 | hour = ahrs; | ||
227 | min = amin; | ||
228 | sec = asec; | ||
229 | lval = jz_mktime(year, mon, mday, hour, min, sec); | ||
230 | REG_RTC_RSAR = lval; | ||
231 | spin_unlock_irqrestore(flags); | ||
232 | break; | ||
233 | } | ||
234 | case RTC_RD_TIME: /* Read the time/date from RTC */ | ||
235 | get_rtc_time(val); | ||
236 | break; | ||
237 | case RTC_SET_TIME: /* Set the RTC */ | ||
238 | { | ||
239 | struct rtc_time rtc_tm; | ||
240 | unsigned int mon, day, hrs, min, sec, leap_yr, date; | ||
241 | unsigned int yrs; | ||
242 | unsigned int lval; | ||
243 | unsigned long flags; | ||
244 | |||
245 | rtc_tm = *val; | ||
246 | yrs = rtc_tm.tm_year;// + 1900; | ||
247 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ | ||
248 | day = rtc_tm.tm_wday; | ||
249 | date = rtc_tm.tm_mday; | ||
250 | hrs = rtc_tm.tm_hour; | ||
251 | min = rtc_tm.tm_min; | ||
252 | sec = rtc_tm.tm_sec; | ||
253 | |||
254 | |||
255 | if (yrs < 1970) | ||
256 | return -EINVAL; | ||
257 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); | ||
258 | |||
259 | if ((mon > 12) || (date == 0)) | ||
260 | return -EINVAL; | ||
261 | |||
262 | if (date > (days_in_mo[mon] + ((mon == 2) && leap_yr))) | ||
263 | return -EINVAL; | ||
264 | |||
265 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) | ||
266 | return -EINVAL; | ||
267 | |||
268 | if ((yrs -= epoch) > 255) /* They are unsigned */ | ||
269 | return -EINVAL; | ||
270 | |||
271 | flags = spin_lock_irqsave(); | ||
272 | /* These limits and adjustments are independant of | ||
273 | * whether the chip is in binary mode or not. | ||
274 | */ | ||
275 | |||
276 | if (yrs > 169) { | ||
277 | spin_unlock_irqrestore(flags); | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | yrs += epoch; | ||
282 | lval = jz_mktime(yrs, mon, date, hrs, min, sec); | ||
283 | REG_RTC_RSR = lval; | ||
284 | /* FIXME: maybe we need to write alarm register here. */ | ||
285 | spin_unlock_irqrestore(flags); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | break; | ||
290 | case RTC_EPOCH_READ: /* Read the epoch. */ | ||
291 | epo = epoch; | ||
292 | return 0; | ||
293 | case RTC_EPOCH_SET: /* Set the epoch. */ | ||
294 | /* | ||
295 | * There were no RTC clocks before 1900. | ||
296 | */ | ||
297 | if (epo < 1900) | ||
298 | return -EINVAL; | ||
299 | |||
300 | epoch = epo; | ||
301 | return 0; | ||
302 | default: | ||
303 | return -EINVAL; | ||
304 | } | ||
305 | return -EINVAL; | ||
306 | } | 94 | } |
307 | #endif | ||
308 | 95 | ||
309 | void rtc_init(void) | 96 | void rtc_init(void) |
310 | { | 97 | { |