Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
time.c
Go to the documentation of this file.
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 
24 DEFINE_SPINLOCK(rtc_lock);
25 EXPORT_SYMBOL_GPL(rtc_lock);
26 
27 void __init
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. */
45 unsigned 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 
64 static 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 
78 static 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 
108 int 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 
167 int 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;
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
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 );
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 );
243  RTC_WRITE( RTC_HOURS, hour + pm);
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;
283  t->tm_wday = wday - 1;
284  }
285 
286  return( 0 );
287 }
288 
289 
290 int 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 
313 int 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  */