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