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