diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2013-04-03 06:27:29 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2013-04-03 06:27:29 -0400 |
| commit | 0ed2aef9b3bffe598045b62a31a50d912eee92d8 (patch) | |
| tree | d7dda12955c838f531727d2775d09c4e04bdf066 /arch/x86/kernel/rtc.c | |
| parent | cfea7d7e452f57682a0bb55a55e9f79c569558c2 (diff) | |
| parent | 8011657b9e63cb2e914b9a0f75233b910c1854cb (diff) | |
Merge branch 'fortglx/3.10/time' of git://git.linaro.org/people/jstultz/linux into timers/core
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 | ||
