2005-04-16 15:20:36 -07:00
/*
* include / asm - i386 / mach - default / mach_time . h
*
* Machine specific set RTC function for generic .
* Split out from time . c by Osamu Tomita < tomita @ cinet . co . jp >
*/
# ifndef _MACH_TIME_H
# define _MACH_TIME_H
# include <linux/mc146818rtc.h>
/* for check timing call set_rtc_mmss() 500ms */
/* used in arch/i386/time.c::do_timer_interrupt() */
# define USEC_AFTER 500000
# define USEC_BEFORE 500000
/*
* In order to set the CMOS clock precisely , set_rtc_mmss has to be
* called 500 ms after the second nowtime has started , because when
* nowtime is written into the registers of the CMOS clock , it will
* jump to the next second precisely 500 ms later . Check the Motorola
* MC146818A or Dallas DS12887 data sheet for details .
*
* BUG : This routine does not handle hour overflow properly ; it just
* sets the minutes . Usually you ' ll only notice that after reboot !
*/
static inline int mach_set_rtc_mmss ( unsigned long nowtime )
{
int retval = 0 ;
int real_seconds , real_minutes , cmos_minutes ;
unsigned char save_control , save_freq_select ;
save_control = CMOS_READ ( RTC_CONTROL ) ; /* tell the clock it's being set */
CMOS_WRITE ( ( save_control | RTC_SET ) , RTC_CONTROL ) ;
save_freq_select = CMOS_READ ( RTC_FREQ_SELECT ) ; /* stop and reset prescaler */
CMOS_WRITE ( ( save_freq_select | RTC_DIV_RESET2 ) , RTC_FREQ_SELECT ) ;
cmos_minutes = CMOS_READ ( RTC_MINUTES ) ;
if ( ! ( save_control & RTC_DM_BINARY ) | | RTC_ALWAYS_BCD )
BCD_TO_BIN ( cmos_minutes ) ;
/*
* since we ' re only adjusting minutes and seconds ,
* don ' t interfere with hour overflow . This avoids
* messing with unknown time zones but requires your
* RTC not to be off by more than 15 minutes
*/
real_seconds = nowtime % 60 ;
real_minutes = nowtime / 60 ;
if ( ( ( abs ( real_minutes - cmos_minutes ) + 15 ) / 30 ) & 1 )
real_minutes + = 30 ; /* correct for half hour time zone */
real_minutes % = 60 ;
if ( abs ( real_minutes - cmos_minutes ) < 30 ) {
if ( ! ( save_control & RTC_DM_BINARY ) | | RTC_ALWAYS_BCD ) {
BIN_TO_BCD ( real_seconds ) ;
BIN_TO_BCD ( real_minutes ) ;
}
CMOS_WRITE ( real_seconds , RTC_SECONDS ) ;
CMOS_WRITE ( real_minutes , RTC_MINUTES ) ;
} else {
printk ( KERN_WARNING
" set_rtc_mmss: can't update from %d to %d \n " ,
cmos_minutes , real_minutes ) ;
retval = - 1 ;
}
/* The following flags have to be released exactly in this order,
* otherwise the DS12887 ( popular MC146818A clone with integrated
* battery and quartz ) will not reset the oscillator and will not
* update precisely 500 ms later . You won ' t find this mentioned in
* the Dallas Semiconductor data sheets , but who believes data
* sheets anyway . . . - - Markus Kuhn
*/
CMOS_WRITE ( save_control , RTC_CONTROL ) ;
CMOS_WRITE ( save_freq_select , RTC_FREQ_SELECT ) ;
return retval ;
}
static inline unsigned long mach_get_cmos_time ( void )
{
unsigned int year , mon , day , hour , min , sec ;
2006-03-28 01:55:58 -08:00
do {
2005-04-16 15:20:36 -07:00
sec = CMOS_READ ( RTC_SECONDS ) ;
min = CMOS_READ ( RTC_MINUTES ) ;
hour = CMOS_READ ( RTC_HOURS ) ;
day = CMOS_READ ( RTC_DAY_OF_MONTH ) ;
mon = CMOS_READ ( RTC_MONTH ) ;
year = CMOS_READ ( RTC_YEAR ) ;
} while ( sec ! = CMOS_READ ( RTC_SECONDS ) ) ;
2006-03-28 01:55:58 -08:00
2006-03-28 01:56:09 -08:00
if ( ! ( CMOS_READ ( RTC_CONTROL ) & RTC_DM_BINARY ) | | RTC_ALWAYS_BCD ) {
BCD_TO_BIN ( sec ) ;
BCD_TO_BIN ( min ) ;
BCD_TO_BIN ( hour ) ;
BCD_TO_BIN ( day ) ;
BCD_TO_BIN ( mon ) ;
BCD_TO_BIN ( year ) ;
}
year + = 1900 ;
if ( year < 1970 )
2005-04-16 15:20:36 -07:00
year + = 100 ;
return mktime ( year , mon , day , hour , min , sec ) ;
}
# endif /* !_MACH_TIME_H */