1/* 2 * include/asm-i386/mach-default/mach_time.h 3 * 4 * Machine specific set RTC function for generic. 5 * Split out from time.c by Osamu Tomita <tomita@cinet.co.jp> 6 */ 7#ifndef _MACH_TIME_H 8#define _MACH_TIME_H 9 10#include <linux/mc146818rtc.h> 11 12/* for check timing call set_rtc_mmss() 500ms */ 13/* used in arch/i386/time.c::do_timer_interrupt() */ 14#define USEC_AFTER 500000 15#define USEC_BEFORE 500000 16 17/* 18 * In order to set the CMOS clock precisely, set_rtc_mmss has to be 19 * called 500 ms after the second nowtime has started, because when 20 * nowtime is written into the registers of the CMOS clock, it will 21 * jump to the next second precisely 500 ms later. Check the Motorola 22 * MC146818A or Dallas DS12887 data sheet for details. 23 * 24 * BUG: This routine does not handle hour overflow properly; it just 25 * sets the minutes. Usually you'll only notice that after reboot! 26 */ 27static inline int mach_set_rtc_mmss(unsigned long nowtime) 28{ 29 int retval = 0; 30 int real_seconds, real_minutes, cmos_minutes; 31 unsigned char save_control, save_freq_select; 32 33 save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ 34 CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); 35 36 save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ 37 CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); 38 39 cmos_minutes = CMOS_READ(RTC_MINUTES); 40 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) 41 BCD_TO_BIN(cmos_minutes); 42 43 /* 44 * since we're only adjusting minutes and seconds, 45 * don't interfere with hour overflow. This avoids 46 * messing with unknown time zones but requires your 47 * RTC not to be off by more than 15 minutes 48 */ 49 real_seconds = nowtime % 60; 50 real_minutes = nowtime / 60; 51 if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) 52 real_minutes += 30; /* correct for half hour time zone */ 53 real_minutes %= 60; 54 55 if (abs(real_minutes - cmos_minutes) < 30) { 56 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 57 BIN_TO_BCD(real_seconds); 58 BIN_TO_BCD(real_minutes); 59 } 60 CMOS_WRITE(real_seconds,RTC_SECONDS); 61 CMOS_WRITE(real_minutes,RTC_MINUTES); 62 } else { 63 printk(KERN_WARNING 64 "set_rtc_mmss: can't update from %d to %d\n", 65 cmos_minutes, real_minutes); 66 retval = -1; 67 } 68 69 /* The following flags have to be released exactly in this order, 70 * otherwise the DS12887 (popular MC146818A clone with integrated 71 * battery and quartz) will not reset the oscillator and will not 72 * update precisely 500 ms later. You won't find this mentioned in 73 * the Dallas Semiconductor data sheets, but who believes data 74 * sheets anyway ... -- Markus Kuhn 75 */ 76 CMOS_WRITE(save_control, RTC_CONTROL); 77 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); 78 79 return retval; 80} 81 82static inline unsigned long mach_get_cmos_time(void) 83{ 84 unsigned int year, mon, day, hour, min, sec; 85 86 do { 87 sec = CMOS_READ(RTC_SECONDS); 88 min = CMOS_READ(RTC_MINUTES); 89 hour = CMOS_READ(RTC_HOURS); 90 day = CMOS_READ(RTC_DAY_OF_MONTH); 91 mon = CMOS_READ(RTC_MONTH); 92 year = CMOS_READ(RTC_YEAR); 93 } while (sec != CMOS_READ(RTC_SECONDS)); 94 95 if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 96 BCD_TO_BIN(sec); 97 BCD_TO_BIN(min); 98 BCD_TO_BIN(hour); 99 BCD_TO_BIN(day); 100 BCD_TO_BIN(mon); 101 BCD_TO_BIN(year); 102 } 103 104 year += 1900; 105 if (year < 1970) 106 year += 100; 107 108 return mktime(year, mon, day, hour, min, sec); 109} 110 111#endif /* !_MACH_TIME_H */ 112