Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m68k/atari/time.c
10817 views
1
/*
2
* linux/arch/m68k/atari/time.c
3
*
4
* Atari time and real time clock stuff
5
*
6
* Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
7
*
8
* This file is subject to the terms and conditions of the GNU General Public
9
* License. See the file COPYING in the main directory of this archive
10
* for more details.
11
*/
12
13
#include <linux/types.h>
14
#include <linux/mc146818rtc.h>
15
#include <linux/interrupt.h>
16
#include <linux/init.h>
17
#include <linux/rtc.h>
18
#include <linux/bcd.h>
19
#include <linux/delay.h>
20
21
#include <asm/atariints.h>
22
23
DEFINE_SPINLOCK(rtc_lock);
24
EXPORT_SYMBOL_GPL(rtc_lock);
25
26
void __init
27
atari_sched_init(irq_handler_t timer_routine)
28
{
29
/* set Timer C data Register */
30
st_mfp.tim_dt_c = INT_TICKS;
31
/* start timer C, div = 1:100 */
32
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
33
/* install interrupt service routine for MFP Timer C */
34
if (request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
35
"timer", timer_routine))
36
pr_err("Couldn't register timer interrupt\n");
37
}
38
39
/* ++andreas: gettimeoffset fixed to check for pending interrupt */
40
41
#define TICK_SIZE 10000
42
43
/* This is always executed with interrupts disabled. */
44
unsigned long atari_gettimeoffset (void)
45
{
46
unsigned long ticks, offset = 0;
47
48
/* read MFP timer C current value */
49
ticks = st_mfp.tim_dt_c;
50
/* The probability of underflow is less than 2% */
51
if (ticks > INT_TICKS - INT_TICKS / 50)
52
/* Check for pending timer interrupt */
53
if (st_mfp.int_pn_b & (1 << 5))
54
offset = TICK_SIZE;
55
56
ticks = INT_TICKS - ticks;
57
ticks = ticks * 10000L / INT_TICKS;
58
59
return ticks + offset;
60
}
61
62
63
static void mste_read(struct MSTE_RTC *val)
64
{
65
#define COPY(v) val->v=(mste_rtc.v & 0xf)
66
do {
67
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
68
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
69
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
70
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
71
COPY(year_tens) ;
72
/* prevent from reading the clock while it changed */
73
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
74
#undef COPY
75
}
76
77
static void mste_write(struct MSTE_RTC *val)
78
{
79
#define COPY(v) mste_rtc.v=val->v
80
do {
81
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
82
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
83
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
84
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
85
COPY(year_tens) ;
86
/* prevent from writing the clock while it changed */
87
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
88
#undef COPY
89
}
90
91
#define RTC_READ(reg) \
92
({ unsigned char __val; \
93
(void) atari_writeb(reg,&tt_rtc.regsel); \
94
__val = tt_rtc.data; \
95
__val; \
96
})
97
98
#define RTC_WRITE(reg,val) \
99
do { \
100
atari_writeb(reg,&tt_rtc.regsel); \
101
tt_rtc.data = (val); \
102
} while(0)
103
104
105
#define HWCLK_POLL_INTERVAL 5
106
107
int atari_mste_hwclk( int op, struct rtc_time *t )
108
{
109
int hour, year;
110
int hr24=0;
111
struct MSTE_RTC val;
112
113
mste_rtc.mode=(mste_rtc.mode | 1);
114
hr24=mste_rtc.mon_tens & 1;
115
mste_rtc.mode=(mste_rtc.mode & ~1);
116
117
if (op) {
118
/* write: prepare values */
119
120
val.sec_ones = t->tm_sec % 10;
121
val.sec_tens = t->tm_sec / 10;
122
val.min_ones = t->tm_min % 10;
123
val.min_tens = t->tm_min / 10;
124
hour = t->tm_hour;
125
if (!hr24) {
126
if (hour > 11)
127
hour += 20 - 12;
128
if (hour == 0 || hour == 20)
129
hour += 12;
130
}
131
val.hr_ones = hour % 10;
132
val.hr_tens = hour / 10;
133
val.day_ones = t->tm_mday % 10;
134
val.day_tens = t->tm_mday / 10;
135
val.mon_ones = (t->tm_mon+1) % 10;
136
val.mon_tens = (t->tm_mon+1) / 10;
137
year = t->tm_year - 80;
138
val.year_ones = year % 10;
139
val.year_tens = year / 10;
140
val.weekday = t->tm_wday;
141
mste_write(&val);
142
mste_rtc.mode=(mste_rtc.mode | 1);
143
val.year_ones = (year % 4); /* leap year register */
144
mste_rtc.mode=(mste_rtc.mode & ~1);
145
}
146
else {
147
mste_read(&val);
148
t->tm_sec = val.sec_ones + val.sec_tens * 10;
149
t->tm_min = val.min_ones + val.min_tens * 10;
150
hour = val.hr_ones + val.hr_tens * 10;
151
if (!hr24) {
152
if (hour == 12 || hour == 12 + 20)
153
hour -= 12;
154
if (hour >= 20)
155
hour += 12 - 20;
156
}
157
t->tm_hour = hour;
158
t->tm_mday = val.day_ones + val.day_tens * 10;
159
t->tm_mon = val.mon_ones + val.mon_tens * 10 - 1;
160
t->tm_year = val.year_ones + val.year_tens * 10 + 80;
161
t->tm_wday = val.weekday;
162
}
163
return 0;
164
}
165
166
int atari_tt_hwclk( int op, struct rtc_time *t )
167
{
168
int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
169
unsigned long flags;
170
unsigned char ctrl;
171
int pm = 0;
172
173
ctrl = RTC_READ(RTC_CONTROL); /* control registers are
174
* independent from the UIP */
175
176
if (op) {
177
/* write: prepare values */
178
179
sec = t->tm_sec;
180
min = t->tm_min;
181
hour = t->tm_hour;
182
day = t->tm_mday;
183
mon = t->tm_mon + 1;
184
year = t->tm_year - atari_rtc_year_offset;
185
wday = t->tm_wday + (t->tm_wday >= 0);
186
187
if (!(ctrl & RTC_24H)) {
188
if (hour > 11) {
189
pm = 0x80;
190
if (hour != 12)
191
hour -= 12;
192
}
193
else if (hour == 0)
194
hour = 12;
195
}
196
197
if (!(ctrl & RTC_DM_BINARY)) {
198
sec = bin2bcd(sec);
199
min = bin2bcd(min);
200
hour = bin2bcd(hour);
201
day = bin2bcd(day);
202
mon = bin2bcd(mon);
203
year = bin2bcd(year);
204
if (wday >= 0)
205
wday = bin2bcd(wday);
206
}
207
}
208
209
/* Reading/writing the clock registers is a bit critical due to
210
* the regular update cycle of the RTC. While an update is in
211
* progress, registers 0..9 shouldn't be touched.
212
* The problem is solved like that: If an update is currently in
213
* progress (the UIP bit is set), the process sleeps for a while
214
* (50ms). This really should be enough, since the update cycle
215
* normally needs 2 ms.
216
* If the UIP bit reads as 0, we have at least 244 usecs until the
217
* update starts. This should be enough... But to be sure,
218
* additionally the RTC_SET bit is set to prevent an update cycle.
219
*/
220
221
while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
222
if (in_atomic() || irqs_disabled())
223
mdelay(1);
224
else
225
schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
226
}
227
228
local_irq_save(flags);
229
RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
230
if (!op) {
231
sec = RTC_READ( RTC_SECONDS );
232
min = RTC_READ( RTC_MINUTES );
233
hour = RTC_READ( RTC_HOURS );
234
day = RTC_READ( RTC_DAY_OF_MONTH );
235
mon = RTC_READ( RTC_MONTH );
236
year = RTC_READ( RTC_YEAR );
237
wday = RTC_READ( RTC_DAY_OF_WEEK );
238
}
239
else {
240
RTC_WRITE( RTC_SECONDS, sec );
241
RTC_WRITE( RTC_MINUTES, min );
242
RTC_WRITE( RTC_HOURS, hour + pm);
243
RTC_WRITE( RTC_DAY_OF_MONTH, day );
244
RTC_WRITE( RTC_MONTH, mon );
245
RTC_WRITE( RTC_YEAR, year );
246
if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
247
}
248
RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
249
local_irq_restore(flags);
250
251
if (!op) {
252
/* read: adjust values */
253
254
if (hour & 0x80) {
255
hour &= ~0x80;
256
pm = 1;
257
}
258
259
if (!(ctrl & RTC_DM_BINARY)) {
260
sec = bcd2bin(sec);
261
min = bcd2bin(min);
262
hour = bcd2bin(hour);
263
day = bcd2bin(day);
264
mon = bcd2bin(mon);
265
year = bcd2bin(year);
266
wday = bcd2bin(wday);
267
}
268
269
if (!(ctrl & RTC_24H)) {
270
if (!pm && hour == 12)
271
hour = 0;
272
else if (pm && hour != 12)
273
hour += 12;
274
}
275
276
t->tm_sec = sec;
277
t->tm_min = min;
278
t->tm_hour = hour;
279
t->tm_mday = day;
280
t->tm_mon = mon - 1;
281
t->tm_year = year + atari_rtc_year_offset;
282
t->tm_wday = wday - 1;
283
}
284
285
return( 0 );
286
}
287
288
289
int atari_mste_set_clock_mmss (unsigned long nowtime)
290
{
291
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
292
struct MSTE_RTC val;
293
unsigned char rtc_minutes;
294
295
mste_read(&val);
296
rtc_minutes= val.min_ones + val.min_tens * 10;
297
if ((rtc_minutes < real_minutes
298
? real_minutes - rtc_minutes
299
: rtc_minutes - real_minutes) < 30)
300
{
301
val.sec_ones = real_seconds % 10;
302
val.sec_tens = real_seconds / 10;
303
val.min_ones = real_minutes % 10;
304
val.min_tens = real_minutes / 10;
305
mste_write(&val);
306
}
307
else
308
return -1;
309
return 0;
310
}
311
312
int atari_tt_set_clock_mmss (unsigned long nowtime)
313
{
314
int retval = 0;
315
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
316
unsigned char save_control, save_freq_select, rtc_minutes;
317
318
save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
319
RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
320
321
save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
322
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
323
324
rtc_minutes = RTC_READ (RTC_MINUTES);
325
if (!(save_control & RTC_DM_BINARY))
326
rtc_minutes = bcd2bin(rtc_minutes);
327
328
/* Since we're only adjusting minutes and seconds, don't interfere
329
with hour overflow. This avoids messing with unknown time zones
330
but requires your RTC not to be off by more than 30 minutes. */
331
if ((rtc_minutes < real_minutes
332
? real_minutes - rtc_minutes
333
: rtc_minutes - real_minutes) < 30)
334
{
335
if (!(save_control & RTC_DM_BINARY))
336
{
337
real_seconds = bin2bcd(real_seconds);
338
real_minutes = bin2bcd(real_minutes);
339
}
340
RTC_WRITE (RTC_SECONDS, real_seconds);
341
RTC_WRITE (RTC_MINUTES, real_minutes);
342
}
343
else
344
retval = -1;
345
346
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
347
RTC_WRITE (RTC_CONTROL, save_control);
348
return retval;
349
}
350
351
/*
352
* Local variables:
353
* c-indent-level: 4
354
* tab-width: 8
355
* End:
356
*/
357
358