blob: f4c304adec42a645674ebb19b48cafdfea33e430 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Paul Mundt5ac54962009-05-08 16:44:00 +09002 * arch/sh/kernel/time.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
5 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
Paul Mundt42786002009-04-28 23:12:10 +09006 * Copyright (C) 2002 - 2009 Paul Mundt
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
8 *
Paul Mundt5ac54962009-05-08 16:44:00 +09009 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
11 * for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/kernel.h>
Paul Mundt36ddf312006-01-16 22:14:17 -080014#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/profile.h>
Paul Mundt65e5d902006-12-06 11:24:48 +090017#include <linux/timex.h>
18#include <linux/sched.h>
Paul Mundt57be2b42007-05-09 17:33:24 +090019#include <linux/clockchips.h>
Paul Mundtfa439722008-09-04 18:53:58 +090020#include <linux/mc146818rtc.h> /* for rtc_lock */
Magnus Dammeaab8912009-04-15 10:50:12 +000021#include <linux/platform_device.h>
Paul Mundt8c245942008-08-06 18:37:07 +090022#include <linux/smp.h>
Paul Mundt47c8a082009-04-27 17:34:39 +090023#include <linux/rtc.h>
Paul Mundt36ddf312006-01-16 22:14:17 -080024#include <asm/clock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <asm/rtc.h>
Paul Mundt36ddf312006-01-16 22:14:17 -080026#include <asm/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
Paul Mundt36ddf312006-01-16 22:14:17 -080028struct sys_timer *sys_timer;
29
30/* Move this somewhere more sensible.. */
31DEFINE_SPINLOCK(rtc_lock);
32EXPORT_SYMBOL(rtc_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Paul Mundt91550f72006-09-27 17:45:01 +090034/* Dummy RTC ops */
35static void null_rtc_get_time(struct timespec *tv)
36{
37 tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
38 tv->tv_nsec = 0;
39}
40
41static int null_rtc_set_time(const time_t secs)
42{
43 return 0;
44}
45
46void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
47int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Paul Mundt6d134b92009-05-08 16:36:13 +090049#ifdef CONFIG_GENERIC_CMOS_UPDATE
50unsigned long read_persistent_clock(void)
51{
52 struct timespec tv;
53 rtc_sh_get_time(&tv);
54 return tv.tv_sec;
55}
56
57int update_persistent_clock(struct timespec now)
58{
59 return rtc_sh_set_time(now.tv_sec);
60}
61#endif
62
Paul Mundt47c8a082009-04-27 17:34:39 +090063unsigned int get_rtc_time(struct rtc_time *tm)
64{
65 if (rtc_sh_get_time != null_rtc_get_time) {
66 struct timespec tv;
67
68 rtc_sh_get_time(&tv);
69 rtc_time_to_tm(tv.tv_sec, tm);
70 }
71
72 return RTC_24H;
73}
74EXPORT_SYMBOL(get_rtc_time);
75
76int set_rtc_time(struct rtc_time *tm)
77{
78 unsigned long secs;
79
80 rtc_tm_to_time(tm, &secs);
81 return rtc_sh_set_time(secs);
82}
83EXPORT_SYMBOL(set_rtc_time);
84
Paul Mundt42786002009-04-28 23:12:10 +090085static int __init rtc_generic_init(void)
86{
87 struct platform_device *pdev;
88
89 if (rtc_sh_get_time == null_rtc_get_time)
90 return -ENODEV;
91
92 pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
93 if (IS_ERR(pdev))
94 return PTR_ERR(pdev);
95
96 return 0;
97}
98module_init(rtc_generic_init);
99
Andriy Skulysh3aa770e2006-09-27 16:20:22 +0900100#ifdef CONFIG_PM
101int timer_suspend(struct sys_device *dev, pm_message_t state)
102{
103 struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
104
105 sys_timer->ops->stop();
106
107 return 0;
108}
109
110int timer_resume(struct sys_device *dev)
111{
112 struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
113
114 sys_timer->ops->start();
115
116 return 0;
117}
118#else
119#define timer_suspend NULL
120#define timer_resume NULL
121#endif
122
Paul Mundt36ddf312006-01-16 22:14:17 -0800123static struct sysdev_class timer_sysclass = {
Kay Sieversaf5ca3f2007-12-20 02:09:39 +0100124 .name = "timer",
Andriy Skulysh3aa770e2006-09-27 16:20:22 +0900125 .suspend = timer_suspend,
126 .resume = timer_resume,
Paul Mundt36ddf312006-01-16 22:14:17 -0800127};
128
129static int __init timer_init_sysfs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Magnus Damm07821d32009-01-22 09:55:49 +0000131 int ret;
132
133 if (!sys_timer)
134 return 0;
135
136 ret = sysdev_class_register(&timer_sysclass);
Paul Mundt36ddf312006-01-16 22:14:17 -0800137 if (ret != 0)
138 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Paul Mundt36ddf312006-01-16 22:14:17 -0800140 sys_timer->dev.cls = &timer_sysclass;
Paul Mundt57be2b42007-05-09 17:33:24 +0900141 return sysdev_register(&sys_timer->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
Paul Mundt36ddf312006-01-16 22:14:17 -0800143device_initcall(timer_init_sysfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145void (*board_time_init)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Magnus Damm955c0772009-01-22 09:55:31 +0000147struct clocksource clocksource_sh = {
Paul Mundt57be2b42007-05-09 17:33:24 +0900148 .name = "SuperH",
Paul Mundt57be2b42007-05-09 17:33:24 +0900149};
150
Paul Mundt57be2b42007-05-09 17:33:24 +0900151unsigned long long sched_clock(void)
152{
Magnus Damm955c0772009-01-22 09:55:31 +0000153 unsigned long long cycles;
154
155 /* jiffies based sched_clock if no clocksource is installed */
156 if (!clocksource_sh.rating)
157 return (unsigned long long)jiffies * (NSEC_PER_SEC / HZ);
158
Magnus Damm8e196082009-04-21 12:24:00 -0700159 cycles = clocksource_sh.read(&clocksource_sh);
Magnus Damm955c0772009-01-22 09:55:31 +0000160 return cyc2ns(&clocksource_sh, cycles);
Paul Mundt57be2b42007-05-09 17:33:24 +0900161}
Paul Mundt57be2b42007-05-09 17:33:24 +0900162
Magnus Damm8e0b8422009-04-28 08:19:50 +0000163static void __init sh_late_time_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 /*
Magnus Dammeaab8912009-04-15 10:50:12 +0000166 * Make sure all compiled-in early timers register themselves.
167 * Run probe() for one "earlytimer" device.
168 */
169 early_platform_driver_register_all("earlytimer");
170 if (early_platform_driver_probe("earlytimer", 1, 0))
171 return;
172
173 /*
Paul Mundt36ddf312006-01-16 22:14:17 -0800174 * Find the timer to use as the system timer, it will be
175 * initialized for us.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 */
Paul Mundt36ddf312006-01-16 22:14:17 -0800177 sys_timer = get_sys_timer();
Magnus Damm07821d32009-01-22 09:55:49 +0000178 if (unlikely(!sys_timer))
179 panic("System timer missing.\n");
180
Paul Mundt36ddf312006-01-16 22:14:17 -0800181 printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182}
Magnus Damm8e0b8422009-04-28 08:19:50 +0000183
184void __init time_init(void)
185{
186 if (board_time_init)
187 board_time_init();
188
189 clk_init();
190
191 rtc_sh_get_time(&xtime);
192 set_normalized_timespec(&wall_to_monotonic,
193 -xtime.tv_sec, -xtime.tv_nsec);
194
195#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
196 local_timer_setup(smp_processor_id());
197#endif
198
199 late_time_init = sh_late_time_init;
200}