1 /* 2 * linux/arch/arm/kernel/time.c 3 * 4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds 5 * Modifications for ARM (C) 1994-2001 Russell King 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * This file contains the ARM-specific time handling details: 12 * reading the RTC at bootup, etc... 13 */ 14 #include <linux/export.h> 15 #include <linux/kernel.h> 16 #include <linux/interrupt.h> 17 #include <linux/time.h> 18 #include <linux/init.h> 19 #include <linux/sched.h> 20 #include <linux/smp.h> 21 #include <linux/timex.h> 22 #include <linux/errno.h> 23 #include <linux/profile.h> 24 #include <linux/syscore_ops.h> 25 #include <linux/timer.h> 26 #include <linux/irq.h> 27 28 #include <asm/leds.h> 29 #include <asm/thread_info.h> 30 #include <asm/sched_clock.h> 31 #include <asm/stacktrace.h> 32 #include <asm/mach/arch.h> 33 #include <asm/mach/time.h> 34 35 /* 36 * Our system timer. 37 */ 38 static struct sys_timer *system_timer; 39 40 #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \ 41 defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE) 42 /* this needs a better home */ 43 DEFINE_SPINLOCK(rtc_lock); 44 EXPORT_SYMBOL(rtc_lock); 45 #endif /* pc-style 'CMOS' RTC support */ 46 47 /* change this if you have some constant time drift */ 48 #define USECS_PER_JIFFY (1000000/HZ) 49 50 #ifdef CONFIG_SMP profile_pc(struct pt_regs * regs)51unsigned long profile_pc(struct pt_regs *regs) 52 { 53 struct stackframe frame; 54 55 if (!in_lock_functions(regs->ARM_pc)) 56 return regs->ARM_pc; 57 58 frame.fp = regs->ARM_fp; 59 frame.sp = regs->ARM_sp; 60 frame.lr = regs->ARM_lr; 61 frame.pc = regs->ARM_pc; 62 do { 63 int ret = unwind_frame(&frame); 64 if (ret < 0) 65 return 0; 66 } while (in_lock_functions(frame.pc)); 67 68 return frame.pc; 69 } 70 EXPORT_SYMBOL(profile_pc); 71 #endif 72 73 #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET arch_gettimeoffset(void)74u32 arch_gettimeoffset(void) 75 { 76 if (system_timer->offset != NULL) 77 return system_timer->offset() * 1000; 78 79 return 0; 80 } 81 #endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */ 82 83 #ifdef CONFIG_LEDS_TIMER do_leds(void)84static inline void do_leds(void) 85 { 86 static unsigned int count = HZ/2; 87 88 if (--count == 0) { 89 count = HZ/2; 90 leds_event(led_timer); 91 } 92 } 93 #else 94 #define do_leds() 95 #endif 96 97 98 #ifndef CONFIG_GENERIC_CLOCKEVENTS 99 /* 100 * Kernel system timer support. 101 */ timer_tick(void)102void timer_tick(void) 103 { 104 profile_tick(CPU_PROFILING); 105 do_leds(); 106 xtime_update(1); 107 #ifndef CONFIG_SMP 108 update_process_times(user_mode(get_irq_regs())); 109 #endif 110 } 111 #endif 112 113 #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) timer_suspend(void)114static int timer_suspend(void) 115 { 116 if (system_timer->suspend) 117 system_timer->suspend(); 118 119 return 0; 120 } 121 timer_resume(void)122static void timer_resume(void) 123 { 124 if (system_timer->resume) 125 system_timer->resume(); 126 } 127 #else 128 #define timer_suspend NULL 129 #define timer_resume NULL 130 #endif 131 132 static struct syscore_ops timer_syscore_ops = { 133 .suspend = timer_suspend, 134 .resume = timer_resume, 135 }; 136 timer_init_syscore_ops(void)137static int __init timer_init_syscore_ops(void) 138 { 139 register_syscore_ops(&timer_syscore_ops); 140 141 return 0; 142 } 143 144 device_initcall(timer_init_syscore_ops); 145 time_init(void)146void __init time_init(void) 147 { 148 system_timer = machine_desc->timer; 149 system_timer->init(); 150 sched_clock_postinit(); 151 } 152 153