Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
424 | giacomo | 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 */ |