linux/arch/arm/kernel/time.c
Rafael J. Wysocki 328f5cc302 ARM: Use struct syscore_ops instead of sysdevs for PM in common code
Convert some ARM architecture's common code to using
struct syscore_ops objects for power management instead of sysdev
classes and sysdevs.

This simplifies the code and reduces the kernel's memory footprint.
It also is necessary for removing sysdevs from the kernel entirely in
the future.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-04-24 19:16:08 +02:00

159 lines
3.1 KiB
C

/*
* 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>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/timex.h>
#include <linux/errno.h>
#include <linux/profile.h>
#include <linux/syscore_ops.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/mc146818rtc.h>
#include <asm/leds.h>
#include <asm/thread_info.h>
#include <asm/sched_clock.h>
#include <asm/stacktrace.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
/*
* Our system timer.
*/
static struct sys_timer *system_timer;
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
/* this needs a better home */
DEFINE_SPINLOCK(rtc_lock);
#ifdef CONFIG_RTC_DRV_CMOS_MODULE
EXPORT_SYMBOL(rtc_lock);
#endif
#endif /* pc-style 'CMOS' RTC support */
/* 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)
{
struct stackframe frame;
if (!in_lock_functions(regs->ARM_pc))
return regs->ARM_pc;
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;
}
EXPORT_SYMBOL(profile_pc);
#endif
#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
u32 arch_gettimeoffset(void)
{
if (system_timer->offset != NULL)
return system_timer->offset() * 1000;
return 0;
}
#endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */
#ifdef CONFIG_LEDS_TIMER
static inline void do_leds(void)
{
static unsigned int count = HZ/2;
if (--count == 0) {
count = HZ/2;
leds_event(led_timer);
}
}
#else
#define do_leds()
#endif
#ifndef CONFIG_GENERIC_CLOCKEVENTS
/*
* Kernel system timer support.
*/
void timer_tick(void)
{
profile_tick(CPU_PROFILING);
do_leds();
xtime_update(1);
#ifndef CONFIG_SMP
update_process_times(user_mode(get_irq_regs()));
#endif
}
#endif
#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
static int timer_suspend(void)
{
if (system_timer->suspend)
system_timer->suspend();
return 0;
}
static void timer_resume(void)
{
if (system_timer->resume)
system_timer->resume();
}
#else
#define timer_suspend NULL
#define timer_resume NULL
#endif
static struct syscore_ops timer_syscore_ops = {
.suspend = timer_suspend,
.resume = timer_resume,
};
static int __init timer_init_syscore_ops(void)
{
register_syscore_ops(&timer_syscore_ops);
return 0;
}
device_initcall(timer_init_syscore_ops);
void __init time_init(void)
{
system_timer = machine_desc->timer;
system_timer->init();
#ifdef CONFIG_HAVE_SCHED_CLOCK
sched_clock_postinit();
#endif
}