time.c 3.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 *  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>
19
#include <linux/sched.h>
L
Linus Torvalds 已提交
20 21 22 23 24 25
#include <linux/smp.h>
#include <linux/timex.h>
#include <linux/errno.h>
#include <linux/profile.h>
#include <linux/sysdev.h>
#include <linux/timer.h>
26
#include <linux/irq.h>
L
Linus Torvalds 已提交
27

28 29
#include <linux/mc146818rtc.h>

L
Linus Torvalds 已提交
30 31
#include <asm/leds.h>
#include <asm/thread_info.h>
32
#include <asm/sched_clock.h>
33
#include <asm/stacktrace.h>
34
#include <asm/mach/arch.h>
L
Linus Torvalds 已提交
35 36 37 38 39
#include <asm/mach/time.h>

/*
 * Our system timer.
 */
40
static struct sys_timer *system_timer;
L
Linus Torvalds 已提交
41

42
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
L
Linus Torvalds 已提交
43 44 45
/* this needs a better home */
DEFINE_SPINLOCK(rtc_lock);

46
#ifdef CONFIG_RTC_DRV_CMOS_MODULE
L
Linus Torvalds 已提交
47 48
EXPORT_SYMBOL(rtc_lock);
#endif
49
#endif	/* pc-style 'CMOS' RTC support */
L
Linus Torvalds 已提交
50 51 52 53 54 55 56

/* 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)
{
57
	struct stackframe frame;
L
Linus Torvalds 已提交
58

59 60
	if (!in_lock_functions(regs->ARM_pc))
		return regs->ARM_pc;
L
Linus Torvalds 已提交
61

62 63 64 65 66 67 68 69 70 71 72
	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;
L
Linus Torvalds 已提交
73 74 75 76
}
EXPORT_SYMBOL(profile_pc);
#endif

77 78
#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
u32 arch_gettimeoffset(void)
L
Linus Torvalds 已提交
79
{
80 81 82
	if (system_timer->offset != NULL)
		return system_timer->offset() * 1000;

L
Linus Torvalds 已提交
83 84
	return 0;
}
85
#endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */
L
Linus Torvalds 已提交
86 87 88 89

#ifdef CONFIG_LEDS_TIMER
static inline void do_leds(void)
{
90
	static unsigned int count = HZ/2;
L
Linus Torvalds 已提交
91 92

	if (--count == 0) {
93
		count = HZ/2;
L
Linus Torvalds 已提交
94 95 96 97 98 99 100 101
		leds_event(led_timer);
	}
}
#else
#define	do_leds()
#endif


102
#ifndef CONFIG_GENERIC_CLOCKEVENTS
L
Linus Torvalds 已提交
103 104 105
/*
 * Kernel system timer support.
 */
106
void timer_tick(void)
L
Linus Torvalds 已提交
107
{
108
	profile_tick(CPU_PROFILING);
L
Linus Torvalds 已提交
109
	do_leds();
110
	write_seqlock(&xtime_lock);
111
	do_timer(1);
112
	write_sequnlock(&xtime_lock);
L
Linus Torvalds 已提交
113
#ifndef CONFIG_SMP
R
Russell King 已提交
114
	update_process_times(user_mode(get_irq_regs()));
L
Linus Torvalds 已提交
115 116
#endif
}
117
#endif
L
Linus Torvalds 已提交
118

119
#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
L
Linus Torvalds 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
static int timer_suspend(struct sys_device *dev, pm_message_t state)
{
	struct sys_timer *timer = container_of(dev, struct sys_timer, dev);

	if (timer->suspend != NULL)
		timer->suspend();

	return 0;
}

static int timer_resume(struct sys_device *dev)
{
	struct sys_timer *timer = container_of(dev, struct sys_timer, dev);

	if (timer->resume != NULL)
		timer->resume();

	return 0;
}
#else
#define timer_suspend NULL
#define timer_resume NULL
#endif

static struct sysdev_class timer_sysclass = {
145
	.name		= "timer",
L
Linus Torvalds 已提交
146 147 148 149 150 151 152 153 154 155 156
	.suspend	= timer_suspend,
	.resume		= timer_resume,
};

static int __init timer_init_sysfs(void)
{
	int ret = sysdev_class_register(&timer_sysclass);
	if (ret == 0) {
		system_timer->dev.cls = &timer_sysclass;
		ret = sysdev_register(&system_timer->dev);
	}
157

L
Linus Torvalds 已提交
158 159 160 161 162 163 164
	return ret;
}

device_initcall(timer_init_sysfs);

void __init time_init(void)
{
165
	system_timer = machine_desc->timer;
L
Linus Torvalds 已提交
166
	system_timer->init();
167 168 169
#ifdef CONFIG_HAVE_SCHED_CLOCK
	sched_clock_postinit();
#endif
L
Linus Torvalds 已提交
170 171
}