Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[pandora-kernel.git] / arch / sh / kernel / time.c
index a3a67d1..9b352a1 100644 (file)
@@ -3,11 +3,12 @@
  *
  *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
  *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
- *  Copyright (C) 2002 - 2007  Paul Mundt
+ *  Copyright (C) 2002 - 2009  Paul Mundt
  *  Copyright (C) 2002  M. R. Brown  <mrbrown@linux-sh.org>
  *
- *  Some code taken from i386 version.
- *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/timex.h>
 #include <linux/sched.h>
 #include <linux/clockchips.h>
+#include <linux/platform_device.h>
+#include <linux/smp.h>
+#include <linux/rtc.h>
 #include <asm/clock.h>
 #include <asm/rtc.h>
-#include <asm/timer.h>
-#include <asm/kgdb.h>
-
-struct sys_timer *sys_timer;
-
-/* Move this somewhere more sensible.. */
-DEFINE_SPINLOCK(rtc_lock);
-EXPORT_SYMBOL(rtc_lock);
 
 /* Dummy RTC ops */
 static void null_rtc_get_time(struct timespec *tv)
@@ -39,197 +35,61 @@ static int null_rtc_set_time(const time_t secs)
        return 0;
 }
 
-/*
- * Null high precision timer functions for systems lacking one.
- */
-static cycle_t null_hpt_read(void)
-{
-       return 0;
-}
-
 void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
 int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
 
-#ifndef CONFIG_GENERIC_TIME
-void do_gettimeofday(struct timeval *tv)
+#ifdef CONFIG_GENERIC_CMOS_UPDATE
+unsigned long read_persistent_clock(void)
 {
-       unsigned long flags;
-       unsigned long seq;
-       unsigned long usec, sec;
-
-       do {
-               /*
-                * Turn off IRQs when grabbing xtime_lock, so that
-                * the sys_timer get_offset code doesn't have to handle it.
-                */
-               seq = read_seqbegin_irqsave(&xtime_lock, flags);
-               usec = get_timer_offset();
-               sec = xtime.tv_sec;
-               usec += xtime.tv_nsec / NSEC_PER_USEC;
-       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-       while (usec >= 1000000) {
-               usec -= 1000000;
-               sec++;
-       }
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
+       struct timespec tv;
+       rtc_sh_get_time(&tv);
+       return tv.tv_sec;
 }
-EXPORT_SYMBOL(do_gettimeofday);
 
-int do_settimeofday(struct timespec *tv)
+int update_persistent_clock(struct timespec now)
 {
-       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
-        * made, and then undo it!
-        */
-       nsec -= get_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;
+       return rtc_sh_set_time(now.tv_sec);
 }
-EXPORT_SYMBOL(do_settimeofday);
-#endif /* !CONFIG_GENERIC_TIME */
-
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
-/* last time the RTC clock got updated */
-static long last_rtc_update;
-
-/*
- * handle_timer_tick() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-void handle_timer_tick(void)
-{
-       do_timer(1);
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-       if (current->pid)
-               profile_tick(CPU_PROFILING);
-
-#ifdef CONFIG_HEARTBEAT
-       if (sh_mv.mv_heartbeat != NULL)
-               sh_mv.mv_heartbeat();
 #endif
 
-       /*
-        * If we have an externally synchronized Linux clock, then update
-        * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-        * called as close as possible to 500 ms before the new second starts.
-        */
-       if (ntp_synced() &&
-           xtime.tv_sec > last_rtc_update + 660 &&
-           (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
-           (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
-               if (rtc_sh_set_time(xtime.tv_sec) == 0)
-                       last_rtc_update = xtime.tv_sec;
-               else
-                       /* do it again in 60s */
-                       last_rtc_update = xtime.tv_sec - 600;
-       }
-}
-#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
-
-#ifdef CONFIG_PM
-int timer_suspend(struct sys_device *dev, pm_message_t state)
+unsigned int get_rtc_time(struct rtc_time *tm)
 {
-       struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
+       if (rtc_sh_get_time != null_rtc_get_time) {
+               struct timespec tv;
 
-       sys_timer->ops->stop();
+               rtc_sh_get_time(&tv);
+               rtc_time_to_tm(tv.tv_sec, tm);
+       }
 
-       return 0;
+       return RTC_24H;
 }
+EXPORT_SYMBOL(get_rtc_time);
 
-int timer_resume(struct sys_device *dev)
+int set_rtc_time(struct rtc_time *tm)
 {
-       struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
+       unsigned long secs;
 
-       sys_timer->ops->start();
-
-       return 0;
+       rtc_tm_to_time(tm, &secs);
+       return rtc_sh_set_time(secs);
 }
-#else
-#define timer_suspend NULL
-#define timer_resume NULL
-#endif
-
-static struct sysdev_class timer_sysclass = {
-       set_kset_name("timer"),
-       .suspend = timer_suspend,
-       .resume  = timer_resume,
-};
+EXPORT_SYMBOL(set_rtc_time);
 
-static int __init timer_init_sysfs(void)
+static int __init rtc_generic_init(void)
 {
-       int ret = sysdev_class_register(&timer_sysclass);
-       if (ret != 0)
-               return ret;
+       struct platform_device *pdev;
 
-       sys_timer->dev.cls = &timer_sysclass;
-       return sysdev_register(&sys_timer->dev);
-}
-device_initcall(timer_init_sysfs);
-
-void (*board_time_init)(void);
-
-/*
- * Shamelessly based on the MIPS and Sparc64 work.
- */
-static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
-unsigned long sh_hpt_frequency = 0;
+       if (rtc_sh_get_time == null_rtc_get_time)
+               return -ENODEV;
 
-#define NSEC_PER_CYC_SHIFT     10
+       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
 
-struct clocksource clocksource_sh = {
-       .name           = "SuperH",
-       .rating         = 200,
-       .mask           = CLOCKSOURCE_MASK(32),
-       .read           = null_hpt_read,
-       .shift          = 16,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static void __init init_sh_clocksource(void)
-{
-       if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
-               return;
-
-       clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
-                                                 clocksource_sh.shift);
-
-       timer_ticks_per_nsec_quotient =
-               clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
-
-       clocksource_register(&clocksource_sh);
+       return 0;
 }
+module_init(rtc_generic_init);
 
-#ifdef CONFIG_GENERIC_TIME
-unsigned long long sched_clock(void)
-{
-       unsigned long long ticks = clocksource_sh.read();
-       return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
-}
-#endif
+void (*board_time_init)(void);
 
 void __init time_init(void)
 {
@@ -242,28 +102,19 @@ void __init time_init(void)
        set_normalized_timespec(&wall_to_monotonic,
                                -xtime.tv_sec, -xtime.tv_nsec);
 
-       /*
-        * Find the timer to use as the system timer, it will be
-        * initialized for us.
-        */
-       sys_timer = get_sys_timer();
-       printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
-
-       if (sys_timer->ops->read)
-               clocksource_sh.read = sys_timer->ops->read;
-
-       init_sh_clocksource();
-
-       if (sh_hpt_frequency)
-               printk("Using %lu.%03lu MHz high precision timer.\n",
-                      ((sh_hpt_frequency + 500) / 1000) / 1000,
-                      ((sh_hpt_frequency + 500) / 1000) % 1000);
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+       local_timer_setup(smp_processor_id());
+#endif
 
-#if defined(CONFIG_SH_KGDB)
        /*
-        * Set up kgdb as requested. We do it here because the serial
-        * init uses the timer vars we just set up for figuring baud.
+        * Make sure all compiled-in early timers register themselves.
+        *
+        * Run probe() for two "earlytimer" devices, these will be the
+        * clockevents and clocksource devices respectively. In the event
+        * that only a clockevents device is available, we -ENODEV on the
+        * clocksource and the jiffies clocksource is used transparently
+        * instead. No error handling is necessary here.
         */
-       kgdb_init();
-#endif
+       early_platform_driver_register_all("earlytimer");
+       early_platform_driver_probe("earlytimer", 2, 0);
 }