diff options
Diffstat (limited to 'arch/arm/kernel/time.c')
| -rw-r--r-- | arch/arm/kernel/time.c | 187 |
1 files changed, 46 insertions, 141 deletions
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 28753805d2d..829a96d4a17 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -11,39 +11,32 @@ * 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/clk-provider.h> +#include <linux/clocksource.h> +#include <linux/errno.h> +#include <linux/export.h> #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/profile.h> #include <linux/sched.h> +#include <linux/sched_clock.h> #include <linux/smp.h> +#include <linux/time.h> #include <linux/timex.h> -#include <linux/errno.h> -#include <linux/profile.h> -#include <linux/sysdev.h> #include <linux/timer.h> -#include <linux/irq.h> - -#include <linux/mc146818rtc.h> -#include <asm/leds.h> -#include <asm/thread_info.h> -#include <asm/stacktrace.h> +#include <asm/mach/arch.h> #include <asm/mach/time.h> +#include <asm/stacktrace.h> +#include <asm/thread_info.h> -/* - * Our system timer. - */ -struct sys_timer *system_timer; - -#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) +#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \ + defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_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 */ @@ -72,85 +65,6 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); #endif -#ifndef CONFIG_GENERIC_TIME -static unsigned long dummy_gettimeoffset(void) -{ - return 0; -} -#endif - -#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_TIME -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long seq; - unsigned long usec, sec; - - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - usec = system_timer->offset(); - sec = xtime.tv_sec; - usec += xtime.tv_nsec / 1000; - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - /* usec may have gone up a lot: be safe */ - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - /* - * This is revolting. We need to set "xtime" correctly. However, the - * value in this location is the value at the most recent update of - * wall time. Discover what correction gettimeofday() would have - * done, and then undo it! - */ - nsec -= system_timer->offset() * NSEC_PER_USEC; - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - ntp_clear(); - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); -#endif /* !CONFIG_GENERIC_TIME */ - #ifndef CONFIG_GENERIC_CLOCKEVENTS /* * Kernel system timer support. @@ -158,66 +72,57 @@ EXPORT_SYMBOL(do_settimeofday); void timer_tick(void) { profile_tick(CPU_PROFILING); - do_leds(); - write_seqlock(&xtime_lock); - do_timer(1); - write_sequnlock(&xtime_lock); + 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(struct sys_device *dev, pm_message_t state) +static void dummy_clock_access(struct timespec *ts) { - struct sys_timer *timer = container_of(dev, struct sys_timer, dev); + ts->tv_sec = 0; + ts->tv_nsec = 0; +} - if (timer->suspend != NULL) - timer->suspend(); +static clock_access_fn __read_persistent_clock = dummy_clock_access; +static clock_access_fn __read_boot_clock = dummy_clock_access;; - return 0; +void read_persistent_clock(struct timespec *ts) +{ + __read_persistent_clock(ts); } -static int timer_resume(struct sys_device *dev) +void read_boot_clock(struct timespec *ts) { - struct sys_timer *timer = container_of(dev, struct sys_timer, dev); - - if (timer->resume != NULL) - timer->resume(); - - return 0; + __read_boot_clock(ts); } -#else -#define timer_suspend NULL -#define timer_resume NULL -#endif - -static struct sysdev_class timer_sysclass = { - .name = "timer", - .suspend = timer_suspend, - .resume = timer_resume, -}; -static int __init timer_init_sysfs(void) +int __init register_persistent_clock(clock_access_fn read_boot, + clock_access_fn read_persistent) { - int ret = sysdev_class_register(&timer_sysclass); - if (ret == 0) { - system_timer->dev.cls = &timer_sysclass; - ret = sysdev_register(&system_timer->dev); + /* Only allow the clockaccess functions to be registered once */ + if (__read_persistent_clock == dummy_clock_access && + __read_boot_clock == dummy_clock_access) { + if (read_boot) + __read_boot_clock = read_boot; + if (read_persistent) + __read_persistent_clock = read_persistent; + + return 0; } - return ret; + return -EINVAL; } -device_initcall(timer_init_sysfs); - void __init time_init(void) { -#ifndef CONFIG_GENERIC_TIME - if (system_timer->offset == NULL) - system_timer->offset = dummy_gettimeoffset; + if (machine_desc->init_time) { + machine_desc->init_time(); + } else { +#ifdef CONFIG_COMMON_CLK + of_clk_init(NULL); #endif - system_timer->init(); + clocksource_of_init(); + } } - |
