diff options
Diffstat (limited to 'arch/x86/kernel/rtc.c')
-rw-r--r-- | arch/x86/kernel/rtc.c | 69 |
1 files changed, 12 insertions, 57 deletions
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 2e8f3d3b5641..198eb201ed3b 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <asm/x86_init.h> | 13 | #include <asm/x86_init.h> |
14 | #include <asm/time.h> | 14 | #include <asm/time.h> |
15 | #include <asm/mrst.h> | 15 | #include <asm/mrst.h> |
16 | #include <asm/rtc.h> | ||
16 | 17 | ||
17 | #ifdef CONFIG_X86_32 | 18 | #ifdef CONFIG_X86_32 |
18 | /* | 19 | /* |
@@ -36,70 +37,24 @@ EXPORT_SYMBOL(rtc_lock); | |||
36 | * nowtime is written into the registers of the CMOS clock, it will | 37 | * nowtime is written into the registers of the CMOS clock, it will |
37 | * jump to the next second precisely 500 ms later. Check the Motorola | 38 | * jump to the next second precisely 500 ms later. Check the Motorola |
38 | * MC146818A or Dallas DS12887 data sheet for details. | 39 | * MC146818A or Dallas DS12887 data sheet for details. |
39 | * | ||
40 | * BUG: This routine does not handle hour overflow properly; it just | ||
41 | * sets the minutes. Usually you'll only notice that after reboot! | ||
42 | */ | 40 | */ |
43 | int mach_set_rtc_mmss(unsigned long nowtime) | 41 | int mach_set_rtc_mmss(unsigned long nowtime) |
44 | { | 42 | { |
45 | int real_seconds, real_minutes, cmos_minutes; | 43 | struct rtc_time tm; |
46 | unsigned char save_control, save_freq_select; | ||
47 | unsigned long flags; | ||
48 | int retval = 0; | 44 | int retval = 0; |
49 | 45 | ||
50 | spin_lock_irqsave(&rtc_lock, flags); | 46 | rtc_time_to_tm(nowtime, &tm); |
51 | 47 | if (!rtc_valid_tm(&tm)) { | |
52 | /* tell the clock it's being set */ | 48 | retval = set_rtc_time(&tm); |
53 | save_control = CMOS_READ(RTC_CONTROL); | 49 | if (retval) |
54 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | 50 | printk(KERN_ERR "%s: RTC write failed with error %d\n", |
55 | 51 | __FUNCTION__, retval); | |
56 | /* stop and reset prescaler */ | ||
57 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | ||
58 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
59 | |||
60 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
61 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
62 | cmos_minutes = bcd2bin(cmos_minutes); | ||
63 | |||
64 | /* | ||
65 | * since we're only adjusting minutes and seconds, | ||
66 | * don't interfere with hour overflow. This avoids | ||
67 | * messing with unknown time zones but requires your | ||
68 | * RTC not to be off by more than 15 minutes | ||
69 | */ | ||
70 | real_seconds = nowtime % 60; | ||
71 | real_minutes = nowtime / 60; | ||
72 | /* correct for half hour time zone */ | ||
73 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
74 | real_minutes += 30; | ||
75 | real_minutes %= 60; | ||
76 | |||
77 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
78 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
79 | real_seconds = bin2bcd(real_seconds); | ||
80 | real_minutes = bin2bcd(real_minutes); | ||
81 | } | ||
82 | CMOS_WRITE(real_seconds, RTC_SECONDS); | ||
83 | CMOS_WRITE(real_minutes, RTC_MINUTES); | ||
84 | } else { | 52 | } else { |
85 | printk_once(KERN_NOTICE | 53 | printk(KERN_ERR |
86 | "set_rtc_mmss: can't update from %d to %d\n", | 54 | "%s: Invalid RTC value: write of %lx to RTC failed\n", |
87 | cmos_minutes, real_minutes); | 55 | __FUNCTION__, nowtime); |
88 | retval = -1; | 56 | retval = -EINVAL; |
89 | } | 57 | } |
90 | |||
91 | /* The following flags have to be released exactly in this order, | ||
92 | * otherwise the DS12887 (popular MC146818A clone with integrated | ||
93 | * battery and quartz) will not reset the oscillator and will not | ||
94 | * update precisely 500 ms later. You won't find this mentioned in | ||
95 | * the Dallas Semiconductor data sheets, but who believes data | ||
96 | * sheets anyway ... -- Markus Kuhn | ||
97 | */ | ||
98 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
99 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
100 | |||
101 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
102 | |||
103 | return retval; | 58 | return retval; |
104 | } | 59 | } |
105 | 60 | ||