2005-04-16 15:20:36 -07:00
/*
* linux / arch / arm / kernel / time . c
*
* Copyright ( C ) 1991 , 1992 , 1995 Linus Torvalds
* Modifications for ARM ( C ) 1994 - 2001 Russell King
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This file contains the ARM - specific time handling details :
* reading the RTC at bootup , etc . . .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/time.h>
# include <linux/init.h>
2009-10-07 17:09:06 +04:00
# include <linux/sched.h>
2005-04-16 15:20:36 -07:00
# include <linux/smp.h>
# include <linux/timex.h>
# include <linux/errno.h>
# include <linux/profile.h>
2011-04-22 22:02:33 +02:00
# include <linux/syscore_ops.h>
2005-04-16 15:20:36 -07:00
# include <linux/timer.h>
2006-10-06 18:58:24 +00:00
# include <linux/irq.h>
2005-04-16 15:20:36 -07:00
2006-12-24 01:36:35 +01:00
# include <linux/mc146818rtc.h>
2005-04-16 15:20:36 -07:00
# include <asm/leds.h>
# include <asm/thread_info.h>
2011-01-11 16:23:04 +00:00
# include <asm/sched_clock.h>
2009-02-11 13:07:53 +01:00
# include <asm/stacktrace.h>
2010-12-20 10:18:36 +00:00
# include <asm/mach/arch.h>
2005-04-16 15:20:36 -07:00
# include <asm/mach/time.h>
/*
* Our system timer .
*/
2010-12-20 10:18:36 +00:00
static struct sys_timer * system_timer ;
2005-04-16 15:20:36 -07:00
2007-01-17 22:11:27 +01:00
# if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
2005-04-16 15:20:36 -07:00
/* this needs a better home */
DEFINE_SPINLOCK ( rtc_lock ) ;
2007-01-17 22:11:27 +01:00
# ifdef CONFIG_RTC_DRV_CMOS_MODULE
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( rtc_lock ) ;
# endif
2007-01-17 22:11:27 +01:00
# endif /* pc-style 'CMOS' RTC support */
2005-04-16 15:20:36 -07:00
/* change this if you have some constant time drift */
# define USECS_PER_JIFFY (1000000 / HZ)
# ifdef CONFIG_SMP
unsigned long profile_pc ( struct pt_regs * regs )
{
2009-02-11 13:07:53 +01:00
struct stackframe frame ;
2005-04-16 15:20:36 -07:00
2009-02-11 13:07:53 +01:00
if ( ! in_lock_functions ( regs - > ARM_pc ) )
return regs - > ARM_pc ;
2005-04-16 15:20:36 -07:00
2009-02-11 13:07:53 +01:00
frame . fp = regs - > ARM_fp ;
frame . sp = regs - > ARM_sp ;
frame . lr = regs - > ARM_lr ;
frame . pc = regs - > ARM_pc ;
do {
int ret = unwind_frame ( & frame ) ;
if ( ret < 0 )
return 0 ;
} while ( in_lock_functions ( frame . pc ) ) ;
return frame . pc ;
2005-04-16 15:20:36 -07:00
}
EXPORT_SYMBOL ( profile_pc ) ;
# endif
2010-03-24 00:22:36 +00:00
# ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
u32 arch_gettimeoffset ( void )
2005-04-16 15:20:36 -07:00
{
2010-03-24 00:22:36 +00:00
if ( system_timer - > offset ! = NULL )
return system_timer - > offset ( ) * 1000 ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2010-03-24 00:22:36 +00:00
# endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_LEDS_TIMER
static inline void do_leds ( void )
{
2006-11-06 19:29:16 +01:00
static unsigned int count = HZ / 2 ;
2005-04-16 15:20:36 -07:00
if ( - - count = = 0 ) {
2006-11-06 19:29:16 +01:00
count = HZ / 2 ;
2005-04-16 15:20:36 -07:00
leds_event ( led_timer ) ;
}
}
# else
# define do_leds()
# endif
2007-03-14 17:33:24 +01:00
# ifndef CONFIG_GENERIC_CLOCKEVENTS
2005-04-16 15:20:36 -07:00
/*
* Kernel system timer support .
*/
2006-10-06 10:53:39 -07:00
void timer_tick ( void )
2005-04-16 15:20:36 -07:00
{
2006-10-06 18:58:24 +00:00
profile_tick ( CPU_PROFILING ) ;
2005-04-16 15:20:36 -07:00
do_leds ( ) ;
2011-01-27 15:59:21 +01:00
xtime_update ( 1 ) ;
2005-04-16 15:20:36 -07:00
# ifndef CONFIG_SMP
2006-10-25 13:59:16 +01:00
update_process_times ( user_mode ( get_irq_regs ( ) ) ) ;
2005-04-16 15:20:36 -07:00
# endif
}
2007-03-14 17:33:24 +01:00
# endif
2005-04-16 15:20:36 -07:00
2007-03-14 17:33:24 +01:00
# if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
2011-04-22 22:02:33 +02:00
static int timer_suspend ( void )
2005-04-16 15:20:36 -07:00
{
2011-04-22 22:02:33 +02:00
if ( system_timer - > suspend )
system_timer - > suspend ( ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2011-04-22 22:02:33 +02:00
static void timer_resume ( void )
2005-04-16 15:20:36 -07:00
{
2011-04-22 22:02:33 +02:00
if ( system_timer - > resume )
system_timer - > resume ( ) ;
2005-04-16 15:20:36 -07:00
}
# else
# define timer_suspend NULL
# define timer_resume NULL
# endif
2011-04-22 22:02:33 +02:00
static struct syscore_ops timer_syscore_ops = {
2005-04-16 15:20:36 -07:00
. suspend = timer_suspend ,
. resume = timer_resume ,
} ;
2011-04-22 22:02:33 +02:00
static int __init timer_init_syscore_ops ( void )
2005-04-16 15:20:36 -07:00
{
2011-04-22 22:02:33 +02:00
register_syscore_ops ( & timer_syscore_ops ) ;
2005-06-25 19:39:45 +01:00
2011-04-22 22:02:33 +02:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2011-04-22 22:02:33 +02:00
device_initcall ( timer_init_syscore_ops ) ;
2005-04-16 15:20:36 -07:00
void __init time_init ( void )
{
2010-12-20 10:18:36 +00:00
system_timer = machine_desc - > timer ;
2005-04-16 15:20:36 -07:00
system_timer - > init ( ) ;
2011-01-11 16:23:04 +00:00
# ifdef CONFIG_HAVE_SCHED_CLOCK
sched_clock_postinit ( ) ;
# endif
2005-04-16 15:20:36 -07:00
}