linux/arch/arm/kernel/time.c
<<
>>
Prefs
   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