mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 09:14:19 +08:00
328f5cc302
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>
159 lines
3.1 KiB
C
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
|
|
}
|
|
|