Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/m68k/atari/time.c
26424 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/clocksource.h>
20
#include <linux/delay.h>
21
#include <linux/export.h>
22
23
#include <asm/atariints.h>
24
#include <asm/machdep.h>
25
26
#include "atari.h"
27
28
DEFINE_SPINLOCK(rtc_lock);
29
EXPORT_SYMBOL_GPL(rtc_lock);
30
31
static u64 atari_read_clk(struct clocksource *cs);
32
33
static struct clocksource atari_clk = {
34
.name = "mfp",
35
.rating = 100,
36
.read = atari_read_clk,
37
.mask = CLOCKSOURCE_MASK(32),
38
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
39
};
40
41
static u32 clk_total;
42
static u8 last_timer_count;
43
44
static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id)
45
{
46
unsigned long flags;
47
48
local_irq_save(flags);
49
do {
50
last_timer_count = st_mfp.tim_dt_c;
51
} while (last_timer_count == 1);
52
clk_total += INT_TICKS;
53
legacy_timer_tick(1);
54
timer_heartbeat();
55
local_irq_restore(flags);
56
57
return IRQ_HANDLED;
58
}
59
60
void __init
61
atari_sched_init(void)
62
{
63
/* set Timer C data Register */
64
st_mfp.tim_dt_c = INT_TICKS;
65
/* start timer C, div = 1:100 */
66
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
67
/* install interrupt service routine for MFP Timer C */
68
if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, IRQF_TIMER, "timer",
69
NULL))
70
pr_err("Couldn't register timer interrupt\n");
71
72
clocksource_register_hz(&atari_clk, INT_CLK);
73
}
74
75
/* ++andreas: gettimeoffset fixed to check for pending interrupt */
76
77
static u64 atari_read_clk(struct clocksource *cs)
78
{
79
unsigned long flags;
80
u8 count;
81
u32 ticks;
82
83
local_irq_save(flags);
84
/* Ensure that the count is monotonically decreasing, even though
85
* the result may briefly stop changing after counter wrap-around.
86
*/
87
count = min(st_mfp.tim_dt_c, last_timer_count);
88
last_timer_count = count;
89
90
ticks = INT_TICKS - count;
91
ticks += clk_total;
92
local_irq_restore(flags);
93
94
return ticks;
95
}
96
97
98
static void mste_read(struct MSTE_RTC *val)
99
{
100
#define COPY(v) val->v=(mste_rtc.v & 0xf)
101
do {
102
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
103
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
104
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
105
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
106
COPY(year_tens) ;
107
/* prevent from reading the clock while it changed */
108
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
109
#undef COPY
110
}
111
112
static void mste_write(struct MSTE_RTC *val)
113
{
114
#define COPY(v) mste_rtc.v=val->v
115
do {
116
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
117
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
118
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
119
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
120
COPY(year_tens) ;
121
/* prevent from writing the clock while it changed */
122
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
123
#undef COPY
124
}
125
126
#define RTC_READ(reg) \
127
({ unsigned char __val; \
128
(void) atari_writeb(reg,&tt_rtc.regsel); \
129
__val = tt_rtc.data; \
130
__val; \
131
})
132
133
#define RTC_WRITE(reg,val) \
134
do { \
135
atari_writeb(reg,&tt_rtc.regsel); \
136
tt_rtc.data = (val); \
137
} while(0)
138
139
140
#define HWCLK_POLL_INTERVAL 5
141
142
int atari_mste_hwclk( int op, struct rtc_time *t )
143
{
144
int hour, year;
145
int hr24=0;
146
struct MSTE_RTC val;
147
148
mste_rtc.mode=(mste_rtc.mode | 1);
149
hr24=mste_rtc.mon_tens & 1;
150
mste_rtc.mode=(mste_rtc.mode & ~1);
151
152
if (op) {
153
/* write: prepare values */
154
155
val.sec_ones = t->tm_sec % 10;
156
val.sec_tens = t->tm_sec / 10;
157
val.min_ones = t->tm_min % 10;
158
val.min_tens = t->tm_min / 10;
159
hour = t->tm_hour;
160
if (!hr24) {
161
if (hour > 11)
162
hour += 20 - 12;
163
if (hour == 0 || hour == 20)
164
hour += 12;
165
}
166
val.hr_ones = hour % 10;
167
val.hr_tens = hour / 10;
168
val.day_ones = t->tm_mday % 10;
169
val.day_tens = t->tm_mday / 10;
170
val.mon_ones = (t->tm_mon+1) % 10;
171
val.mon_tens = (t->tm_mon+1) / 10;
172
year = t->tm_year - 80;
173
val.year_ones = year % 10;
174
val.year_tens = year / 10;
175
val.weekday = t->tm_wday;
176
mste_write(&val);
177
mste_rtc.mode=(mste_rtc.mode | 1);
178
val.year_ones = (year % 4); /* leap year register */
179
mste_rtc.mode=(mste_rtc.mode & ~1);
180
}
181
else {
182
mste_read(&val);
183
t->tm_sec = val.sec_ones + val.sec_tens * 10;
184
t->tm_min = val.min_ones + val.min_tens * 10;
185
hour = val.hr_ones + val.hr_tens * 10;
186
if (!hr24) {
187
if (hour == 12 || hour == 12 + 20)
188
hour -= 12;
189
if (hour >= 20)
190
hour += 12 - 20;
191
}
192
t->tm_hour = hour;
193
t->tm_mday = val.day_ones + val.day_tens * 10;
194
t->tm_mon = val.mon_ones + val.mon_tens * 10 - 1;
195
t->tm_year = val.year_ones + val.year_tens * 10 + 80;
196
t->tm_wday = val.weekday;
197
}
198
return 0;
199
}
200
201
int atari_tt_hwclk( int op, struct rtc_time *t )
202
{
203
int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
204
unsigned long flags;
205
unsigned char ctrl;
206
int pm = 0;
207
208
ctrl = RTC_READ(RTC_CONTROL); /* control registers are
209
* independent from the UIP */
210
211
if (op) {
212
/* write: prepare values */
213
214
sec = t->tm_sec;
215
min = t->tm_min;
216
hour = t->tm_hour;
217
day = t->tm_mday;
218
mon = t->tm_mon + 1;
219
year = t->tm_year - atari_rtc_year_offset;
220
wday = t->tm_wday + (t->tm_wday >= 0);
221
222
if (!(ctrl & RTC_24H)) {
223
if (hour > 11) {
224
pm = 0x80;
225
if (hour != 12)
226
hour -= 12;
227
}
228
else if (hour == 0)
229
hour = 12;
230
}
231
232
if (!(ctrl & RTC_DM_BINARY)) {
233
sec = bin2bcd(sec);
234
min = bin2bcd(min);
235
hour = bin2bcd(hour);
236
day = bin2bcd(day);
237
mon = bin2bcd(mon);
238
year = bin2bcd(year);
239
if (wday >= 0)
240
wday = bin2bcd(wday);
241
}
242
}
243
244
/* Reading/writing the clock registers is a bit critical due to
245
* the regular update cycle of the RTC. While an update is in
246
* progress, registers 0..9 shouldn't be touched.
247
* The problem is solved like that: If an update is currently in
248
* progress (the UIP bit is set), the process sleeps for a while
249
* (50ms). This really should be enough, since the update cycle
250
* normally needs 2 ms.
251
* If the UIP bit reads as 0, we have at least 244 usecs until the
252
* update starts. This should be enough... But to be sure,
253
* additionally the RTC_SET bit is set to prevent an update cycle.
254
*/
255
256
while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
257
if (in_atomic() || irqs_disabled())
258
mdelay(1);
259
else
260
schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
261
}
262
263
local_irq_save(flags);
264
RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
265
if (!op) {
266
sec = RTC_READ( RTC_SECONDS );
267
min = RTC_READ( RTC_MINUTES );
268
hour = RTC_READ( RTC_HOURS );
269
day = RTC_READ( RTC_DAY_OF_MONTH );
270
mon = RTC_READ( RTC_MONTH );
271
year = RTC_READ( RTC_YEAR );
272
wday = RTC_READ( RTC_DAY_OF_WEEK );
273
}
274
else {
275
RTC_WRITE( RTC_SECONDS, sec );
276
RTC_WRITE( RTC_MINUTES, min );
277
RTC_WRITE( RTC_HOURS, hour + pm);
278
RTC_WRITE( RTC_DAY_OF_MONTH, day );
279
RTC_WRITE( RTC_MONTH, mon );
280
RTC_WRITE( RTC_YEAR, year );
281
if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
282
}
283
RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
284
local_irq_restore(flags);
285
286
if (!op) {
287
/* read: adjust values */
288
289
if (hour & 0x80) {
290
hour &= ~0x80;
291
pm = 1;
292
}
293
294
if (!(ctrl & RTC_DM_BINARY)) {
295
sec = bcd2bin(sec);
296
min = bcd2bin(min);
297
hour = bcd2bin(hour);
298
day = bcd2bin(day);
299
mon = bcd2bin(mon);
300
year = bcd2bin(year);
301
wday = bcd2bin(wday);
302
}
303
304
if (!(ctrl & RTC_24H)) {
305
if (!pm && hour == 12)
306
hour = 0;
307
else if (pm && hour != 12)
308
hour += 12;
309
}
310
311
t->tm_sec = sec;
312
t->tm_min = min;
313
t->tm_hour = hour;
314
t->tm_mday = day;
315
t->tm_mon = mon - 1;
316
t->tm_year = year + atari_rtc_year_offset;
317
t->tm_wday = wday - 1;
318
}
319
320
return( 0 );
321
}
322
323