2005-11-14 07:49:48 +03:00
# include <linux/kernel.h>
# include <linux/time.h>
# include <linux/timer.h>
# include <linux/init.h>
# include <linux/rtc.h>
# include <linux/delay.h>
2011-06-04 09:35:47 +04:00
# include <linux/ratelimit.h>
2005-11-14 07:49:48 +03:00
# include <asm/prom.h>
# include <asm/rtas.h>
# include <asm/time.h>
# define MAX_RTC_WAIT 5000 /* 5 sec */
# define RTAS_CLOCK_BUSY (-2)
unsigned long __init rtas_get_boot_time ( void )
{
int ret [ 8 ] ;
2006-06-06 01:31:48 +04:00
int error ;
unsigned int wait_time ;
2005-11-18 07:52:38 +03:00
u64 max_wait_tb ;
2005-11-14 07:49:48 +03:00
max_wait_tb = get_tb ( ) + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT ;
do {
error = rtas_call ( rtas_token ( " get-time-of-day " ) , 0 , 8 , ret ) ;
2006-06-06 01:31:48 +04:00
wait_time = rtas_busy_delay_time ( error ) ;
if ( wait_time ) {
2005-11-14 07:49:48 +03:00
/* This is boot time so we spin. */
udelay ( wait_time * 1000 ) ;
}
2006-06-06 01:31:48 +04:00
} while ( wait_time & & ( get_tb ( ) < max_wait_tb ) ) ;
2005-11-14 07:49:48 +03:00
2011-06-04 09:35:47 +04:00
if ( error ! = 0 ) {
printk_ratelimited ( KERN_WARNING
" error: reading the clock failed (%d) \n " ,
error ) ;
2005-11-14 07:49:48 +03:00
return 0 ;
}
return mktime ( ret [ 0 ] , ret [ 1 ] , ret [ 2 ] , ret [ 3 ] , ret [ 4 ] , ret [ 5 ] ) ;
}
/* NOTE: get_rtc_time will get an error if executed in interrupt context
* and if a delay is needed to read the clock . In this case we just
* silently return without updating rtc_tm .
*/
void rtas_get_rtc_time ( struct rtc_time * rtc_tm )
{
int ret [ 8 ] ;
2006-06-06 01:31:48 +04:00
int error ;
unsigned int wait_time ;
2005-11-18 07:52:38 +03:00
u64 max_wait_tb ;
2005-11-14 07:49:48 +03:00
max_wait_tb = get_tb ( ) + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT ;
do {
error = rtas_call ( rtas_token ( " get-time-of-day " ) , 0 , 8 , ret ) ;
2006-06-06 01:31:48 +04:00
wait_time = rtas_busy_delay_time ( error ) ;
if ( wait_time ) {
2011-06-04 09:35:47 +04:00
if ( in_interrupt ( ) ) {
2006-03-14 09:11:51 +03:00
memset ( rtc_tm , 0 , sizeof ( struct rtc_time ) ) ;
2011-06-04 09:35:47 +04:00
printk_ratelimited ( KERN_WARNING
" error: reading clock "
" would delay interrupt \n " ) ;
2005-11-14 07:49:48 +03:00
return ; /* delay not allowed */
}
msleep ( wait_time ) ;
}
2006-06-06 01:31:48 +04:00
} while ( wait_time & & ( get_tb ( ) < max_wait_tb ) ) ;
2005-11-14 07:49:48 +03:00
2011-06-04 09:35:47 +04:00
if ( error ! = 0 ) {
printk_ratelimited ( KERN_WARNING
" error: reading the clock failed (%d) \n " ,
error ) ;
2005-11-14 07:49:48 +03:00
return ;
}
rtc_tm - > tm_sec = ret [ 5 ] ;
rtc_tm - > tm_min = ret [ 4 ] ;
rtc_tm - > tm_hour = ret [ 3 ] ;
rtc_tm - > tm_mday = ret [ 2 ] ;
rtc_tm - > tm_mon = ret [ 1 ] - 1 ;
rtc_tm - > tm_year = ret [ 0 ] - 1900 ;
}
int rtas_set_rtc_time ( struct rtc_time * tm )
{
int error , wait_time ;
2005-11-18 07:52:38 +03:00
u64 max_wait_tb ;
2005-11-14 07:49:48 +03:00
max_wait_tb = get_tb ( ) + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT ;
do {
error = rtas_call ( rtas_token ( " set-time-of-day " ) , 7 , 1 , NULL ,
tm - > tm_year + 1900 , tm - > tm_mon + 1 ,
tm - > tm_mday , tm - > tm_hour , tm - > tm_min ,
tm - > tm_sec , 0 ) ;
2006-06-06 01:31:48 +04:00
wait_time = rtas_busy_delay_time ( error ) ;
if ( wait_time ) {
2005-11-14 07:49:48 +03:00
if ( in_interrupt ( ) )
return 1 ; /* probably decrementer */
msleep ( wait_time ) ;
}
2006-06-06 01:31:48 +04:00
} while ( wait_time & & ( get_tb ( ) < max_wait_tb ) ) ;
2005-11-14 07:49:48 +03:00
2011-06-04 09:35:47 +04:00
if ( error ! = 0 )
printk_ratelimited ( KERN_WARNING
" error: setting the clock failed (%d) \n " ,
error ) ;
2005-11-14 07:49:48 +03:00
return 0 ;
}