aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/Kconfig5
-rw-r--r--arch/powerpc/platforms/powermac/time.c38
-rw-r--r--arch/powerpc/sysdev/Makefile3
-rw-r--r--arch/powerpc/sysdev/timer.c70
4 files changed, 78 insertions, 38 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index e7205273ff37..ec092b7ea242 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -11,6 +11,11 @@ config PPC64
11 This option selects whether a 32-bit or a 64-bit kernel 11 This option selects whether a 32-bit or a 64-bit kernel
12 will be built. 12 will be built.
13 13
14config PPC_PM_NEEDS_RTC_LIB
15 bool
16 select RTC_LIB
17 default y if PM
18
14config PPC32 19config PPC32
15 bool 20 bool
16 default y if !PPC64 21 default y if !PPC64
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index a4173906e945..bf9da56942e8 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -297,49 +297,11 @@ int __init via_calibrate_decr(void)
297} 297}
298#endif 298#endif
299 299
300#ifdef CONFIG_PM
301/*
302 * Reset the time after a sleep.
303 */
304static int
305time_sleep_notify(struct pmu_sleep_notifier *self, int when)
306{
307 static unsigned long time_diff;
308 unsigned long flags;
309 unsigned long seq;
310 struct timespec tv;
311
312 switch (when) {
313 case PBOOK_SLEEP_NOW:
314 do {
315 seq = read_seqbegin_irqsave(&xtime_lock, flags);
316 time_diff = xtime.tv_sec - pmac_get_boot_time();
317 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
318 break;
319 case PBOOK_WAKE:
320 tv.tv_sec = pmac_get_boot_time() + time_diff;
321 tv.tv_nsec = 0;
322 do_settimeofday(&tv);
323 break;
324 }
325 return PBOOK_SLEEP_OK;
326}
327
328static struct pmu_sleep_notifier time_sleep_notifier = {
329 time_sleep_notify, SLEEP_LEVEL_MISC,
330};
331#endif /* CONFIG_PM */
332
333/* 300/*
334 * Query the OF and get the decr frequency. 301 * Query the OF and get the decr frequency.
335 */ 302 */
336void __init pmac_calibrate_decr(void) 303void __init pmac_calibrate_decr(void)
337{ 304{
338#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
339 /* XXX why here? */
340 pmu_register_sleep_notifier(&time_sleep_notifier);
341#endif
342
343 generic_calibrate_decr(); 305 generic_calibrate_decr();
344 306
345#ifdef CONFIG_PPC32 307#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 26ca3ffbc1de..e57379d22b61 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -14,6 +14,9 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o
14obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o 14obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
15obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ 15obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
16 16
17# contains only the suspend handler for time
18obj-$(CONFIG_PM) += timer.o
19
17ifeq ($(CONFIG_PPC_MERGE),y) 20ifeq ($(CONFIG_PPC_MERGE),y)
18obj-$(CONFIG_PPC_I8259) += i8259.o 21obj-$(CONFIG_PPC_I8259) += i8259.o
19obj-$(CONFIG_PPC_83xx) += ipic.o 22obj-$(CONFIG_PPC_83xx) += ipic.o
diff --git a/arch/powerpc/sysdev/timer.c b/arch/powerpc/sysdev/timer.c
new file mode 100644
index 000000000000..bdbf8fe520e4
--- /dev/null
+++ b/arch/powerpc/sysdev/timer.c
@@ -0,0 +1,70 @@
1/*
2 * Common code to keep time when machine suspends.
3 *
4 * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
5 *
6 * GPLv2
7 */
8
9#include <linux/time.h>
10#include <asm/rtc.h>
11
12static unsigned long suspend_rtc_time;
13
14/*
15 * Reset the time after a sleep.
16 */
17static int timer_resume(struct sys_device *dev)
18{
19 struct timeval tv;
20 struct timespec ts;
21 struct rtc_time cur_rtc_tm;
22 unsigned long cur_rtc_time, diff;
23
24 /* get current RTC time and convert to seconds */
25 get_rtc_time(&cur_rtc_tm);
26 rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time);
27
28 diff = cur_rtc_time - suspend_rtc_time;
29
30 /* adjust time of day by seconds that elapsed while
31 * we were suspended */
32 do_gettimeofday(&tv);
33 ts.tv_sec = tv.tv_sec + diff;
34 ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
35 do_settimeofday(&ts);
36
37 return 0;
38}
39
40static int timer_suspend(struct sys_device *dev, pm_message_t state)
41{
42 struct rtc_time suspend_rtc_tm;
43 WARN_ON(!ppc_md.get_rtc_time);
44
45 get_rtc_time(&suspend_rtc_tm);
46 rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time);
47
48 return 0;
49}
50
51static struct sysdev_class timer_sysclass = {
52 .resume = timer_resume,
53 .suspend = timer_suspend,
54 set_kset_name("timer"),
55};
56
57static struct sys_device device_timer = {
58 .id = 0,
59 .cls = &timer_sysclass,
60};
61
62static int time_init_device(void)
63{
64 int error = sysdev_class_register(&timer_sysclass);
65 if (!error)
66 error = sysdev_register(&device_timer);
67 return error;
68}
69
70device_initcall(time_init_device);