Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * SA1100 Power Management Routines
0003  *
0004  * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License.
0008  *
0009  * History:
0010  *
0011  * 2001-02-06:  Cliff Brake         Initial code
0012  *
0013  * 2001-02-25:  Sukjae Cho <sjcho@east.isi.edu> &
0014  *      Chester Kuo <chester@linux.org.tw>
0015  *          Save more value for the resume function! Support
0016  *          Bitsy/Assabet/Freebird board
0017  *
0018  * 2001-08-29:  Nicolas Pitre <nico@fluxnic.net>
0019  *          Cleaned up, pushed platform dependent stuff
0020  *          in the platform specific files.
0021  *
0022  * 2002-05-27:  Nicolas Pitre   Killed sleep.h and the kmalloced save array.
0023  *              Storage is local on the stack now.
0024  */
0025 #include <linux/init.h>
0026 #include <linux/io.h>
0027 #include <linux/suspend.h>
0028 #include <linux/errno.h>
0029 #include <linux/time.h>
0030 
0031 #include <mach/hardware.h>
0032 #include <asm/memory.h>
0033 #include <asm/suspend.h>
0034 #include <asm/mach/time.h>
0035 
0036 extern int sa1100_finish_suspend(unsigned long);
0037 
0038 #define SAVE(x)     sleep_save[SLEEP_SAVE_##x] = x
0039 #define RESTORE(x)  x = sleep_save[SLEEP_SAVE_##x]
0040 
0041 /*
0042  * List of global SA11x0 peripheral registers to preserve.
0043  * More ones like CP and general purpose register values are preserved
0044  * on the stack and then the stack pointer is stored last in sleep.S.
0045  */
0046 enum {  SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR,
0047     SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
0048 
0049     SLEEP_SAVE_Ser1SDCR0,
0050 
0051     SLEEP_SAVE_COUNT
0052 };
0053 
0054 
0055 static int sa11x0_pm_enter(suspend_state_t state)
0056 {
0057     unsigned long gpio, sleep_save[SLEEP_SAVE_COUNT];
0058 
0059     gpio = GPLR;
0060 
0061     /* save vital registers */
0062     SAVE(GPDR);
0063     SAVE(GAFR);
0064 
0065     SAVE(PPDR);
0066     SAVE(PPSR);
0067     SAVE(PPAR);
0068     SAVE(PSDR);
0069 
0070     SAVE(Ser1SDCR0);
0071 
0072     /* Clear previous reset status */
0073     RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
0074 
0075     /* set resume return address */
0076     PSPR = __pa_symbol(cpu_resume);
0077 
0078     /* go zzz */
0079     cpu_suspend(0, sa1100_finish_suspend);
0080 
0081     /*
0082      * Ensure not to come back here if it wasn't intended
0083      */
0084     RCSR = RCSR_SMR;
0085     PSPR = 0;
0086 
0087     /*
0088      * Ensure interrupt sources are disabled; we will re-init
0089      * the interrupt subsystem via the device manager.
0090      */
0091     ICLR = 0;
0092     ICCR = 1;
0093     ICMR = 0;
0094 
0095     /* restore registers */
0096     RESTORE(GPDR);
0097     RESTORE(GAFR);
0098 
0099     RESTORE(PPDR);
0100     RESTORE(PPSR);
0101     RESTORE(PPAR);
0102     RESTORE(PSDR);
0103 
0104     RESTORE(Ser1SDCR0);
0105 
0106     GPSR = gpio;
0107     GPCR = ~gpio;
0108 
0109     /*
0110      * Clear the peripheral sleep-hold bit.
0111      */
0112     PSSR = PSSR_PH;
0113 
0114     return 0;
0115 }
0116 
0117 static const struct platform_suspend_ops sa11x0_pm_ops = {
0118     .enter      = sa11x0_pm_enter,
0119     .valid      = suspend_valid_only_mem,
0120 };
0121 
0122 int __init sa11x0_pm_init(void)
0123 {
0124     suspend_set_ops(&sa11x0_pm_ops);
0125     return 0;
0126 }