2005-04-16 15:20:36 -07:00
/*
* arch / sh / kernel / time . c
*
* Copyright ( C ) 1999 Tetsuya Okada & Niibe Yutaka
* Copyright ( C ) 2000 Philipp Rumpf < prumpf @ tux . org >
2007-05-09 17:33:24 +09:00
* Copyright ( C ) 2002 - 2007 Paul Mundt
2005-04-16 15:20:36 -07:00
* Copyright ( C ) 2002 M . R . Brown < mrbrown @ linux - sh . org >
*
* Some code taken from i386 version .
* Copyright ( C ) 1991 , 1992 , 1995 Linus Torvalds
*/
# include <linux/kernel.h>
2006-01-16 22:14:17 -08:00
# include <linux/module.h>
2005-04-16 15:20:36 -07:00
# include <linux/init.h>
# include <linux/profile.h>
2006-12-06 11:24:48 +09:00
# include <linux/timex.h>
# include <linux/sched.h>
2007-05-09 17:33:24 +09:00
# include <linux/clockchips.h>
2006-01-16 22:14:17 -08:00
# include <asm/clock.h>
2005-04-16 15:20:36 -07:00
# include <asm/rtc.h>
2006-01-16 22:14:17 -08:00
# include <asm/timer.h>
2005-04-16 15:20:36 -07:00
# include <asm/kgdb.h>
2006-01-16 22:14:17 -08:00
struct sys_timer * sys_timer ;
/* Move this somewhere more sensible.. */
DEFINE_SPINLOCK ( rtc_lock ) ;
EXPORT_SYMBOL ( rtc_lock ) ;
2005-04-16 15:20:36 -07:00
2006-09-27 17:45:01 +09:00
/* Dummy RTC ops */
static void null_rtc_get_time ( struct timespec * tv )
{
tv - > tv_sec = mktime ( 2000 , 1 , 1 , 0 , 0 , 0 ) ;
tv - > tv_nsec = 0 ;
}
static int null_rtc_set_time ( const time_t secs )
{
return 0 ;
}
2007-05-09 17:33:24 +09:00
/*
* Null high precision timer functions for systems lacking one .
*/
static cycle_t null_hpt_read ( void )
{
return 0 ;
}
2006-09-27 17:45:01 +09:00
void ( * rtc_sh_get_time ) ( struct timespec * ) = null_rtc_get_time ;
int ( * rtc_sh_set_time ) ( const time_t ) = null_rtc_set_time ;
2005-04-16 15:20:36 -07:00
2006-10-04 13:21:45 +09:00
# ifndef CONFIG_GENERIC_TIME
2005-04-16 15:20:36 -07:00
void do_gettimeofday ( struct timeval * tv )
{
2006-12-01 13:12:05 +09:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
unsigned long seq ;
unsigned long usec , sec ;
do {
2006-12-01 13:12:05 +09:00
/*
* Turn off IRQs when grabbing xtime_lock , so that
* the sys_timer get_offset code doesn ' t have to handle it .
*/
seq = read_seqbegin_irqsave ( & xtime_lock , flags ) ;
2006-01-16 22:14:17 -08:00
usec = get_timer_offset ( ) ;
2005-04-16 15:20:36 -07:00
sec = xtime . tv_sec ;
2006-12-01 13:12:05 +09:00
usec + = xtime . tv_nsec / NSEC_PER_USEC ;
} while ( read_seqretry_irqrestore ( & xtime_lock , seq , flags ) ) ;
2005-04-16 15:20:36 -07:00
while ( usec > = 1000000 ) {
usec - = 1000000 ;
sec + + ;
}
tv - > tv_sec = sec ;
tv - > tv_usec = usec ;
}
EXPORT_SYMBOL ( do_gettimeofday ) ;
int do_settimeofday ( struct timespec * tv )
{
time_t wtm_sec , sec = tv - > tv_sec ;
long wtm_nsec , nsec = tv - > tv_nsec ;
if ( ( unsigned long ) tv - > tv_nsec > = NSEC_PER_SEC )
return - EINVAL ;
write_seqlock_irq ( & xtime_lock ) ;
/*
* This is revolting . We need to set " xtime " correctly . However , the
* value in this location is the value at the most recent update of
* wall time . Discover what correction gettimeofday ( ) would have
* made , and then undo it !
*/
2006-12-01 13:12:05 +09:00
nsec - = get_timer_offset ( ) * NSEC_PER_USEC ;
2005-04-16 15:20:36 -07:00
wtm_sec = wall_to_monotonic . tv_sec + ( xtime . tv_sec - sec ) ;
wtm_nsec = wall_to_monotonic . tv_nsec + ( xtime . tv_nsec - nsec ) ;
set_normalized_timespec ( & xtime , sec , nsec ) ;
set_normalized_timespec ( & wall_to_monotonic , wtm_sec , wtm_nsec ) ;
2005-09-06 15:17:46 -07:00
ntp_clear ( ) ;
2005-04-16 15:20:36 -07:00
write_sequnlock_irq ( & xtime_lock ) ;
clock_was_set ( ) ;
return 0 ;
}
EXPORT_SYMBOL ( do_settimeofday ) ;
2006-10-04 13:21:45 +09:00
# endif /* !CONFIG_GENERIC_TIME */
2005-04-16 15:20:36 -07:00
2007-05-09 17:33:24 +09:00
# ifndef CONFIG_GENERIC_CLOCKEVENTS
2005-04-16 15:20:36 -07:00
/* last time the RTC clock got updated */
static long last_rtc_update ;
/*
2006-01-16 22:14:17 -08:00
* handle_timer_tick ( ) needs to keep up the real - time clock ,
2005-04-16 15:20:36 -07:00
* as well as call the " do_timer() " routine every clocktick
*/
2006-10-06 15:31:16 +09:00
void handle_timer_tick ( void )
2005-04-16 15:20:36 -07:00
{
2006-10-06 15:31:16 +09:00
if ( current - > pid )
profile_tick ( CPU_PROFILING ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_HEARTBEAT
if ( sh_mv . mv_heartbeat ! = NULL )
sh_mv . mv_heartbeat ( ) ;
# endif
2008-02-07 15:01:26 +09:00
/*
* Here we are in the timer irq handler . We just have irqs locally
* disabled but we don ' t know if the timer_bh is running on the other
* CPU . We need to avoid to SMP race with it . NOTE : we don ' t need
* the irq version of write_lock because as just said we have irq
* locally disabled . - arca
*/
write_seqlock ( & xtime_lock ) ;
do_timer ( 1 ) ;
2005-04-16 15:20:36 -07:00
/*
* If we have an externally synchronized Linux clock , then update
* RTC clock accordingly every ~ 11 minutes . Set_rtc_mmss ( ) has to be
* called as close as possible to 500 ms before the new second starts .
*/
2005-09-06 15:17:46 -07:00
if ( ntp_synced ( ) & &
2005-04-16 15:20:36 -07:00
xtime . tv_sec > last_rtc_update + 660 & &
( xtime . tv_nsec / 1000 ) > = 500000 - ( ( unsigned ) TICK_SIZE ) / 2 & &
( xtime . tv_nsec / 1000 ) < = 500000 + ( ( unsigned ) TICK_SIZE ) / 2 ) {
2006-09-27 17:11:32 +09:00
if ( rtc_sh_set_time ( xtime . tv_sec ) = = 0 )
2005-04-16 15:20:36 -07:00
last_rtc_update = xtime . tv_sec ;
else
2006-01-16 22:14:17 -08:00
/* do it again in 60s */
last_rtc_update = xtime . tv_sec - 600 ;
2005-04-16 15:20:36 -07:00
}
2008-02-07 15:01:26 +09:00
write_sequnlock ( & xtime_lock ) ;
# ifndef CONFIG_SMP
update_process_times ( user_mode ( get_irq_regs ( ) ) ) ;
# endif
2005-04-16 15:20:36 -07:00
}
2007-05-09 17:33:24 +09:00
# endif /* !CONFIG_GENERIC_CLOCKEVENTS */
2005-04-16 15:20:36 -07:00
2006-09-27 16:20:22 +09:00
# ifdef CONFIG_PM
int timer_suspend ( struct sys_device * dev , pm_message_t state )
{
struct sys_timer * sys_timer = container_of ( dev , struct sys_timer , dev ) ;
sys_timer - > ops - > stop ( ) ;
return 0 ;
}
int timer_resume ( struct sys_device * dev )
{
struct sys_timer * sys_timer = container_of ( dev , struct sys_timer , dev ) ;
sys_timer - > ops - > start ( ) ;
return 0 ;
}
# else
# define timer_suspend NULL
# define timer_resume NULL
# endif
2006-01-16 22:14:17 -08:00
static struct sysdev_class timer_sysclass = {
2007-12-20 02:09:39 +01:00
. name = " timer " ,
2006-09-27 16:20:22 +09:00
. suspend = timer_suspend ,
. resume = timer_resume ,
2005-04-16 15:20:36 -07:00
} ;
2007-05-09 17:33:24 +09:00
static int __init timer_init_sysfs ( void )
2006-12-01 13:23:47 +09:00
{
2007-05-09 17:33:24 +09:00
int ret = sysdev_class_register ( & timer_sysclass ) ;
if ( ret ! = 0 )
return ret ;
2006-12-01 13:23:47 +09:00
2007-05-09 17:33:24 +09:00
sys_timer - > dev . cls = & timer_sysclass ;
return sysdev_register ( & sys_timer - > dev ) ;
2006-12-01 13:23:47 +09:00
}
2007-05-09 17:33:24 +09:00
device_initcall ( timer_init_sysfs ) ;
2006-12-01 13:23:47 +09:00
2007-05-09 17:33:24 +09:00
void ( * board_time_init ) ( void ) ;
2006-12-01 13:23:47 +09:00
/*
2007-05-09 17:33:24 +09:00
* Shamelessly based on the MIPS and Sparc64 work .
2006-12-01 13:23:47 +09:00
*/
2007-05-09 17:33:24 +09:00
static unsigned long timer_ticks_per_nsec_quotient __read_mostly ;
unsigned long sh_hpt_frequency = 0 ;
# define NSEC_PER_CYC_SHIFT 10
struct clocksource clocksource_sh = {
. name = " SuperH " ,
. rating = 200 ,
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. read = null_hpt_read ,
. shift = 16 ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2006-12-01 13:23:47 +09:00
2007-05-09 17:33:24 +09:00
static void __init init_sh_clocksource ( void )
2006-12-01 13:23:47 +09:00
{
2007-05-09 17:33:24 +09:00
if ( ! sh_hpt_frequency | | clocksource_sh . read = = null_hpt_read )
return ;
2006-12-01 13:23:47 +09:00
2007-05-09 17:33:24 +09:00
clocksource_sh . mult = clocksource_hz2mult ( sh_hpt_frequency ,
clocksource_sh . shift ) ;
2006-12-01 13:23:47 +09:00
2007-05-09 17:33:24 +09:00
timer_ticks_per_nsec_quotient =
clocksource_hz2mult ( sh_hpt_frequency , NSEC_PER_CYC_SHIFT ) ;
2006-12-01 13:23:47 +09:00
2007-05-09 17:33:24 +09:00
clocksource_register ( & clocksource_sh ) ;
2006-12-01 13:23:47 +09:00
}
2007-05-09 17:33:24 +09:00
# ifdef CONFIG_GENERIC_TIME
unsigned long long sched_clock ( void )
2006-12-01 13:23:47 +09:00
{
2007-05-09 17:33:24 +09:00
unsigned long long ticks = clocksource_sh . read ( ) ;
return ( ticks * timer_ticks_per_nsec_quotient ) > > NSEC_PER_CYC_SHIFT ;
2006-12-01 13:23:47 +09:00
}
# endif
2005-04-16 15:20:36 -07:00
void __init time_init ( void )
{
if ( board_time_init )
board_time_init ( ) ;
2006-01-16 22:14:17 -08:00
clk_init ( ) ;
2005-04-16 15:20:36 -07:00
2006-09-27 17:45:01 +09:00
rtc_sh_get_time ( & xtime ) ;
set_normalized_timespec ( & wall_to_monotonic ,
- xtime . tv_sec , - xtime . tv_nsec ) ;
2005-04-16 15:20:36 -07:00
/*
2006-01-16 22:14:17 -08:00
* Find the timer to use as the system timer , it will be
* initialized for us .
2005-04-16 15:20:36 -07:00
*/
2006-01-16 22:14:17 -08:00
sys_timer = get_sys_timer ( ) ;
printk ( KERN_INFO " Using %s for system timer \n " , sys_timer - > name ) ;
2005-04-16 15:20:36 -07:00
2007-05-09 17:33:24 +09:00
if ( sys_timer - > ops - > read )
clocksource_sh . read = sys_timer - > ops - > read ;
init_sh_clocksource ( ) ;
if ( sh_hpt_frequency )
printk ( " Using %lu.%03lu MHz high precision timer. \n " ,
( ( sh_hpt_frequency + 500 ) / 1000 ) / 1000 ,
( ( sh_hpt_frequency + 500 ) / 1000 ) % 1000 ) ;
2006-12-01 13:23:47 +09:00
2005-04-16 15:20:36 -07:00
# if defined(CONFIG_SH_KGDB)
/*
* Set up kgdb as requested . We do it here because the serial
* init uses the timer vars we just set up for figuring baud .
*/
kgdb_init ( ) ;
# endif
}