2 * SA1100 Power Management Routines
4 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License.
11 * 2001-02-06: Cliff Brake Initial code
13 * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> &
14 * Chester Kuo <chester@linux.org.tw>
15 * Save more value for the resume function! Support
16 * Bitsy/Assabet/Freebird board
18 * 2001-08-29: Nicolas Pitre <nico@cam.org>
19 * Cleaned up, pushed platform dependent stuff
20 * in the platform specific files.
22 * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array.
23 * Storage is local on the stack now.
25 #include <linux/config.h>
26 #include <linux/init.h>
28 #include <linux/sched.h>
29 #include <linux/interrupt.h>
30 #include <linux/sysctl.h>
31 #include <linux/errno.h>
33 #include <asm/hardware.h>
34 #include <asm/memory.h>
35 #include <asm/system.h>
44 extern void sa1100_cpu_suspend(void);
45 extern void sa1100_cpu_resume(void);
47 #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
48 #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
51 * List of global SA11x0 peripheral registers to preserve.
52 * More ones like CP and general purpose register values are preserved
53 * with the stack location in sleep.S.
55 enum { SLEEP_SAVE_START = 0,
57 SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
58 SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
60 SLEEP_SAVE_GPDR, SLEEP_SAVE_GRER, SLEEP_SAVE_GFER, SLEEP_SAVE_GAFR,
61 SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
70 int pm_do_suspend(void)
72 unsigned long sleep_save[SLEEP_SAVE_SIZE];
78 /* preserve current time */
81 /* save vital registers */
103 /* ... maybe a global variable initialized by arch code to set this? */
108 /* Clear previous reset status */
109 RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
111 /* set resume return address */
112 PSPR = virt_to_phys(sa1100_cpu_resume);
115 sa1100_cpu_suspend();
117 /* ensure not to come back here if it wasn't intended */
121 printk(KERN_DEBUG "*** made it back from resume\n");
124 /* restore registers */
130 /* clear any edge detect bit */
153 /* restore current time */
156 leds_event(led_start);
161 * Restore the CPU frequency settings.
163 #ifdef CONFIG_CPU_FREQ
170 unsigned long sleep_phys_sp(void *sp)
172 return virt_to_phys(sp);
177 * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than
180 * This means our interface here won't survive long - it needs a new
181 * interface. Quick hack to get this working - use sysctl id 9999.
183 #warning ACPI broke the kernel, this interface needs to be fixed up.
184 #define CTL_ACPI 9999
185 #define ACPI_S1_SLP_TYP 19
190 static int sysctl_pm_do_suspend(void)
194 retval = pm_send_all(PM_SUSPEND, (void *)3);
197 retval = pm_do_suspend();
199 pm_send_all(PM_RESUME, (void *)0);
205 static struct ctl_table pm_table[] =
207 {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
211 static struct ctl_table pm_dir_table[] =
213 {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
218 * Initialize power interface
220 static int __init pm_init(void)
222 register_sysctl_table(pm_dir_table, 1);