ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-i386 / mach-pc9800 / mach_time.h
1 /*
2  *  include/asm-i386/mach-pc9800/mach_time.h
3  *
4  *  Machine specific set RTC function for PC-9800.
5  *  Written by Osamu Tomita <tomita@cinet.co.jp>
6  */
7 #ifndef _MACH_TIME_H
8 #define _MACH_TIME_H
9
10 #include <linux/bcd.h>
11 #include <linux/upd4990a.h>
12
13 /* for check timing call set_rtc_mmss() */
14 /* used in arch/i386/time.c::do_timer_interrupt() */
15 /*
16  * Because PC-9800's RTC (NEC uPD4990A) does not allow setting
17  * time partially, we always have to read-modify-write the
18  * entire time (including year) so that set_rtc_mmss() will
19  * take quite much time to execute.  You may want to relax
20  * RTC resetting interval (currently ~11 minuts)...
21  */
22 #define USEC_AFTER      1000000
23 #define USEC_BEFORE     0
24
25 static inline int mach_set_rtc_mmss(unsigned long nowtime)
26 {
27         int retval = 0;
28         int real_seconds, real_minutes, cmos_minutes;
29         struct upd4990a_raw_data data;
30
31         upd4990a_get_time(&data, 1);
32         cmos_minutes = BCD2BIN(data.min);
33
34         /*
35          * since we're only adjusting minutes and seconds,
36          * don't interfere with hour overflow. This avoids
37          * messing with unknown time zones but requires your
38          * RTC not to be off by more than 15 minutes
39          */
40         real_seconds = nowtime % 60;
41         real_minutes = nowtime / 60;
42         if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
43                 real_minutes += 30;     /* correct for half hour time zone */
44         real_minutes %= 60;
45
46         if (abs(real_minutes - cmos_minutes) < 30) {
47                 u8 temp_seconds = (real_seconds / 10) * 16 + real_seconds % 10;
48                 u8 temp_minutes = (real_minutes / 10) * 16 + real_minutes % 10;
49
50                 if (data.sec != temp_seconds || data.min != temp_minutes) {
51                         data.sec = temp_seconds;
52                         data.min = temp_minutes;
53                         upd4990a_set_time(&data, 1);
54                 }
55         } else {
56                 printk(KERN_WARNING
57                        "set_rtc_mmss: can't update from %d to %d\n",
58                        cmos_minutes, real_minutes);
59                 retval = -1;
60         }
61
62         /* uPD4990A users' manual says we should issue Register Hold
63          * command after reading time, or future Time Read command
64          * may not work.  When we have set the time, this also starts
65          * the clock.
66          */
67         upd4990a_serial_command(UPD4990A_REGISTER_HOLD);
68
69         return retval;
70 }
71
72 static inline unsigned long mach_get_cmos_time(void)
73 {
74         int i;
75         u8 prev, cur;
76         unsigned int year;
77         struct upd4990a_raw_data data;
78
79         /* Connect uPD4990A's DATA OUT pin to its 1Hz reference clock. */
80         upd4990a_serial_command(UPD4990A_REGISTER_HOLD);
81
82         /* Catch rising edge of reference clock.  */
83         prev = ~UPD4990A_READ_DATA();
84         for (i = 0; i < 1800000; i++) { /* may take up to 1 second... */
85                 __asm__ ("outb %%al,%0" : : "N" (0x5f)); /* 0.6usec delay */
86                 cur = UPD4990A_READ_DATA();
87                 if (!(prev & cur & 1))
88                         break;
89                 prev = ~cur;
90         }
91
92         upd4990a_get_time(&data, 0);
93
94         if ((year = BCD2BIN(data.year) + 1900) < 1995)
95                 year += 100;
96         return mktime(year, data.mon, BCD2BIN(data.mday), BCD2BIN(data.hour),
97                         BCD2BIN(data.min), BCD2BIN(data.sec));
98 }
99
100 #endif /* !_MACH_TIME_H */