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 51 unsigned 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 74 u32 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 84 static 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 */ 102 void 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 static void dummy_clock_access(struct timespec *ts) 114 { 115 ts->tv_sec = 0; 116 ts->tv_nsec = 0; 117 } 118 119 static clock_access_fn __read_persistent_clock = dummy_clock_access; 120 static clock_access_fn __read_boot_clock = dummy_clock_access;; 121 122 void read_persistent_clock(struct timespec *ts) 123 { 124 __read_persistent_clock(ts); 125 } 126 127 void read_boot_clock(struct timespec *ts) 128 { 129 __read_boot_clock(ts); 130 } 131 132 int __init register_persistent_clock(clock_access_fn read_boot, 133 clock_access_fn read_persistent) 134 { 135 /* Only allow the clockaccess functions to be registered once */ 136 if (__read_persistent_clock == dummy_clock_access && 137 __read_boot_clock == dummy_clock_access) { 138 if (read_boot) 139 __read_boot_clock = read_boot; 140 if (read_persistent) 141 __read_persistent_clock = read_persistent; 142 143 return 0; 144 } 145 146 return -EINVAL; 147 } 148 149 #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) 150 static int timer_suspend(void) 151 { 152 if (system_timer->suspend) 153 system_timer->suspend(); 154 155 return 0; 156 } 157 158 static void timer_resume(void) 159 { 160 if (system_timer->resume) 161 system_timer->resume(); 162 } 163 #else 164 #define timer_suspend NULL 165 #define timer_resume NULL 166 #endif 167 168 static struct syscore_ops timer_syscore_ops = { 169 .suspend = timer_suspend, 170 .resume = timer_resume, 171 }; 172 173 static int __init timer_init_syscore_ops(void) 174 { 175 register_syscore_ops(&timer_syscore_ops); 176 177 return 0; 178 } 179 180 device_initcall(timer_init_syscore_ops); 181 182 void __init time_init(void) 183 { 184 system_timer = machine_desc->timer; 185 system_timer->init(); 186 sched_clock_postinit(); 187 } 188 189