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 */ 38static 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 */ 43DEFINE_SPINLOCK(rtc_lock); 44EXPORT_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 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} 70EXPORT_SYMBOL(profile_pc); 71#endif 72 73#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET 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 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 */ 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 113static void dummy_clock_access(struct timespec *ts) 114{ 115 ts->tv_sec = 0; 116 ts->tv_nsec = 0; 117} 118 119static clock_access_fn __read_persistent_clock = dummy_clock_access; 120static clock_access_fn __read_boot_clock = dummy_clock_access;; 121 122void read_persistent_clock(struct timespec *ts) 123{ 124 __read_persistent_clock(ts); 125} 126 127void read_boot_clock(struct timespec *ts) 128{ 129 __read_boot_clock(ts); 130} 131 132int __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) 150static int timer_suspend(void) 151{ 152 if (system_timer->suspend) 153 system_timer->suspend(); 154 155 return 0; 156} 157 158static 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 168static struct syscore_ops timer_syscore_ops = { 169 .suspend = timer_suspend, 170 .resume = timer_resume, 171}; 172 173static int __init timer_init_syscore_ops(void) 174{ 175 register_syscore_ops(&timer_syscore_ops); 176 177 return 0; 178} 179 180device_initcall(timer_init_syscore_ops); 181 182void __init time_init(void) 183{ 184 system_timer = machine_desc->timer; 185 system_timer->init(); 186 sched_clock_postinit(); 187} 188 189