2005-04-17 02:20:36 +04:00
/*
* SA1100 Power Management Routines
*
* Copyright ( c ) 2001 Cliff Brake < cbrake @ accelent . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License .
*
* History :
*
* 2001 - 02 - 06 : Cliff Brake Initial code
*
* 2001 - 02 - 25 : Sukjae Cho < sjcho @ east . isi . edu > &
* Chester Kuo < chester @ linux . org . tw >
* Save more value for the resume function ! Support
* Bitsy / Assabet / Freebird board
*
* 2001 - 08 - 29 : Nicolas Pitre < nico @ cam . org >
* Cleaned up , pushed platform dependent stuff
* in the platform specific files .
*
* 2002 - 05 - 27 : Nicolas Pitre Killed sleep . h and the kmalloced save array .
* Storage is local on the stack now .
*/
# include <linux/init.h>
# include <linux/suspend.h>
# include <linux/errno.h>
# include <linux/time.h>
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2005-04-17 02:20:36 +04:00
# include <asm/memory.h>
# include <asm/system.h>
# include <asm/mach/time.h>
extern void sa1100_cpu_suspend ( void ) ;
extern void sa1100_cpu_resume ( void ) ;
# define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
# define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
/*
* List of global SA11x0 peripheral registers to preserve .
* More ones like CP and general purpose register values are preserved
* on the stack and then the stack pointer is stored last in sleep . S .
*/
2008-05-03 00:17:06 +04:00
enum { SLEEP_SAVE_GPDR , SLEEP_SAVE_GAFR ,
2005-04-17 02:20:36 +04:00
SLEEP_SAVE_PPDR , SLEEP_SAVE_PPSR , SLEEP_SAVE_PPAR , SLEEP_SAVE_PSDR ,
SLEEP_SAVE_Ser1SDCR0 ,
2008-05-03 00:17:06 +04:00
SLEEP_SAVE_COUNT
2005-04-17 02:20:36 +04:00
} ;
static int sa11x0_pm_enter ( suspend_state_t state )
{
2008-05-03 00:17:06 +04:00
unsigned long gpio , sleep_save [ SLEEP_SAVE_COUNT ] ;
2005-04-17 02:20:36 +04:00
gpio = GPLR ;
/* save vital registers */
SAVE ( GPDR ) ;
SAVE ( GAFR ) ;
SAVE ( PPDR ) ;
SAVE ( PPSR ) ;
SAVE ( PPAR ) ;
SAVE ( PSDR ) ;
SAVE ( Ser1SDCR0 ) ;
/* Clear previous reset status */
RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR ;
/* set resume return address */
PSPR = virt_to_phys ( sa1100_cpu_resume ) ;
/* go zzz */
sa1100_cpu_suspend ( ) ;
2005-06-19 21:39:33 +04:00
cpu_init ( ) ;
2005-04-17 02:20:36 +04:00
/*
* Ensure not to come back here if it wasn ' t intended
*/
PSPR = 0 ;
/*
* Ensure interrupt sources are disabled ; we will re - init
* the interrupt subsystem via the device manager .
*/
ICLR = 0 ;
ICCR = 1 ;
ICMR = 0 ;
/* restore registers */
RESTORE ( GPDR ) ;
RESTORE ( GAFR ) ;
RESTORE ( PPDR ) ;
RESTORE ( PPSR ) ;
RESTORE ( PPAR ) ;
RESTORE ( PSDR ) ;
RESTORE ( Ser1SDCR0 ) ;
GPSR = gpio ;
GPCR = ~ gpio ;
/*
* Clear the peripheral sleep - hold bit .
*/
PSSR = PSSR_PH ;
return 0 ;
}
unsigned long sleep_phys_sp ( void * sp )
{
return virt_to_phys ( sp ) ;
}
2007-10-18 14:04:40 +04:00
static struct platform_suspend_ops sa11x0_pm_ops = {
2005-04-17 02:20:36 +04:00
. enter = sa11x0_pm_enter ,
2007-10-18 14:04:40 +04:00
. valid = suspend_valid_only_mem ,
2005-04-17 02:20:36 +04:00
} ;
static int __init sa11x0_pm_init ( void )
{
2007-10-18 14:04:40 +04:00
suspend_set_ops ( & sa11x0_pm_ops ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
late_initcall ( sa11x0_pm_init ) ;