[POWERPC] Generic time suspend/resume code
This removes the time suspend/restore code that was done through a PMU notifier in arch/platforms/powermac/time.c. Instead, introduce arch/powerpc/sysdev/timer.c which creates a sys device and handles time of day suspend/resume through that. This should probably be replaced by using the generic RTC framework but for now it gets rid of the arcane powermac specific hack. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
committed by
Paul Mackerras
parent
ec5f77e789
commit
17e638bc28
@@ -11,6 +11,11 @@ config PPC64
|
|||||||
This option selects whether a 32-bit or a 64-bit kernel
|
This option selects whether a 32-bit or a 64-bit kernel
|
||||||
will be built.
|
will be built.
|
||||||
|
|
||||||
|
config PPC_PM_NEEDS_RTC_LIB
|
||||||
|
bool
|
||||||
|
select RTC_LIB
|
||||||
|
default y if PM
|
||||||
|
|
||||||
config PPC32
|
config PPC32
|
||||||
bool
|
bool
|
||||||
default y if !PPC64
|
default y if !PPC64
|
||||||
|
|||||||
@@ -297,49 +297,11 @@ int __init via_calibrate_decr(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
/*
|
|
||||||
* Reset the time after a sleep.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
time_sleep_notify(struct pmu_sleep_notifier *self, int when)
|
|
||||||
{
|
|
||||||
static unsigned long time_diff;
|
|
||||||
unsigned long flags;
|
|
||||||
unsigned long seq;
|
|
||||||
struct timespec tv;
|
|
||||||
|
|
||||||
switch (when) {
|
|
||||||
case PBOOK_SLEEP_NOW:
|
|
||||||
do {
|
|
||||||
seq = read_seqbegin_irqsave(&xtime_lock, flags);
|
|
||||||
time_diff = xtime.tv_sec - pmac_get_boot_time();
|
|
||||||
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
|
|
||||||
break;
|
|
||||||
case PBOOK_WAKE:
|
|
||||||
tv.tv_sec = pmac_get_boot_time() + time_diff;
|
|
||||||
tv.tv_nsec = 0;
|
|
||||||
do_settimeofday(&tv);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return PBOOK_SLEEP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct pmu_sleep_notifier time_sleep_notifier = {
|
|
||||||
time_sleep_notify, SLEEP_LEVEL_MISC,
|
|
||||||
};
|
|
||||||
#endif /* CONFIG_PM */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Query the OF and get the decr frequency.
|
* Query the OF and get the decr frequency.
|
||||||
*/
|
*/
|
||||||
void __init pmac_calibrate_decr(void)
|
void __init pmac_calibrate_decr(void)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
|
|
||||||
/* XXX why here? */
|
|
||||||
pmu_register_sleep_notifier(&time_sleep_notifier);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
generic_calibrate_decr();
|
generic_calibrate_decr();
|
||||||
|
|
||||||
#ifdef CONFIG_PPC32
|
#ifdef CONFIG_PPC32
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o
|
|||||||
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
|
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
|
||||||
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
|
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
|
||||||
|
|
||||||
|
# contains only the suspend handler for time
|
||||||
|
obj-$(CONFIG_PM) += timer.o
|
||||||
|
|
||||||
ifeq ($(CONFIG_PPC_MERGE),y)
|
ifeq ($(CONFIG_PPC_MERGE),y)
|
||||||
obj-$(CONFIG_PPC_I8259) += i8259.o
|
obj-$(CONFIG_PPC_I8259) += i8259.o
|
||||||
obj-$(CONFIG_PPC_83xx) += ipic.o
|
obj-$(CONFIG_PPC_83xx) += ipic.o
|
||||||
|
|||||||
70
arch/powerpc/sysdev/timer.c
Normal file
70
arch/powerpc/sysdev/timer.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Common code to keep time when machine suspends.
|
||||||
|
*
|
||||||
|
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||||
|
*
|
||||||
|
* GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include <asm/rtc.h>
|
||||||
|
|
||||||
|
static unsigned long suspend_rtc_time;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset the time after a sleep.
|
||||||
|
*/
|
||||||
|
static int timer_resume(struct sys_device *dev)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
struct timespec ts;
|
||||||
|
struct rtc_time cur_rtc_tm;
|
||||||
|
unsigned long cur_rtc_time, diff;
|
||||||
|
|
||||||
|
/* get current RTC time and convert to seconds */
|
||||||
|
get_rtc_time(&cur_rtc_tm);
|
||||||
|
rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time);
|
||||||
|
|
||||||
|
diff = cur_rtc_time - suspend_rtc_time;
|
||||||
|
|
||||||
|
/* adjust time of day by seconds that elapsed while
|
||||||
|
* we were suspended */
|
||||||
|
do_gettimeofday(&tv);
|
||||||
|
ts.tv_sec = tv.tv_sec + diff;
|
||||||
|
ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
|
||||||
|
do_settimeofday(&ts);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int timer_suspend(struct sys_device *dev, pm_message_t state)
|
||||||
|
{
|
||||||
|
struct rtc_time suspend_rtc_tm;
|
||||||
|
WARN_ON(!ppc_md.get_rtc_time);
|
||||||
|
|
||||||
|
get_rtc_time(&suspend_rtc_tm);
|
||||||
|
rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sysdev_class timer_sysclass = {
|
||||||
|
.resume = timer_resume,
|
||||||
|
.suspend = timer_suspend,
|
||||||
|
set_kset_name("timer"),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sys_device device_timer = {
|
||||||
|
.id = 0,
|
||||||
|
.cls = &timer_sysclass,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int time_init_device(void)
|
||||||
|
{
|
||||||
|
int error = sysdev_class_register(&timer_sysclass);
|
||||||
|
if (!error)
|
||||||
|
error = sysdev_register(&device_timer);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_initcall(time_init_device);
|
||||||
Reference in New Issue
Block a user