1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * SA1100 Power Management Routines 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 7*1da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License. 8*1da177e4SLinus Torvalds * 9*1da177e4SLinus Torvalds * History: 10*1da177e4SLinus Torvalds * 11*1da177e4SLinus Torvalds * 2001-02-06: Cliff Brake Initial code 12*1da177e4SLinus Torvalds * 13*1da177e4SLinus Torvalds * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> & 14*1da177e4SLinus Torvalds * Chester Kuo <chester@linux.org.tw> 15*1da177e4SLinus Torvalds * Save more value for the resume function! Support 16*1da177e4SLinus Torvalds * Bitsy/Assabet/Freebird board 17*1da177e4SLinus Torvalds * 18*1da177e4SLinus Torvalds * 2001-08-29: Nicolas Pitre <nico@cam.org> 19*1da177e4SLinus Torvalds * Cleaned up, pushed platform dependent stuff 20*1da177e4SLinus Torvalds * in the platform specific files. 21*1da177e4SLinus Torvalds * 22*1da177e4SLinus Torvalds * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array. 23*1da177e4SLinus Torvalds * Storage is local on the stack now. 24*1da177e4SLinus Torvalds */ 25*1da177e4SLinus Torvalds #include <linux/init.h> 26*1da177e4SLinus Torvalds #include <linux/suspend.h> 27*1da177e4SLinus Torvalds #include <linux/errno.h> 28*1da177e4SLinus Torvalds #include <linux/time.h> 29*1da177e4SLinus Torvalds 30*1da177e4SLinus Torvalds #include <asm/hardware.h> 31*1da177e4SLinus Torvalds #include <asm/memory.h> 32*1da177e4SLinus Torvalds #include <asm/system.h> 33*1da177e4SLinus Torvalds #include <asm/mach/time.h> 34*1da177e4SLinus Torvalds 35*1da177e4SLinus Torvalds extern void sa1100_cpu_suspend(void); 36*1da177e4SLinus Torvalds extern void sa1100_cpu_resume(void); 37*1da177e4SLinus Torvalds 38*1da177e4SLinus Torvalds #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x 39*1da177e4SLinus Torvalds #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] 40*1da177e4SLinus Torvalds 41*1da177e4SLinus Torvalds /* 42*1da177e4SLinus Torvalds * List of global SA11x0 peripheral registers to preserve. 43*1da177e4SLinus Torvalds * More ones like CP and general purpose register values are preserved 44*1da177e4SLinus Torvalds * on the stack and then the stack pointer is stored last in sleep.S. 45*1da177e4SLinus Torvalds */ 46*1da177e4SLinus Torvalds enum { SLEEP_SAVE_SP = 0, 47*1da177e4SLinus Torvalds 48*1da177e4SLinus Torvalds SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR, 49*1da177e4SLinus Torvalds SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR, 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds SLEEP_SAVE_Ser1SDCR0, 52*1da177e4SLinus Torvalds 53*1da177e4SLinus Torvalds SLEEP_SAVE_SIZE 54*1da177e4SLinus Torvalds }; 55*1da177e4SLinus Torvalds 56*1da177e4SLinus Torvalds 57*1da177e4SLinus Torvalds static int sa11x0_pm_enter(suspend_state_t state) 58*1da177e4SLinus Torvalds { 59*1da177e4SLinus Torvalds unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE]; 60*1da177e4SLinus Torvalds struct timespec delta, rtc; 61*1da177e4SLinus Torvalds 62*1da177e4SLinus Torvalds if (state != PM_SUSPEND_MEM) 63*1da177e4SLinus Torvalds return -EINVAL; 64*1da177e4SLinus Torvalds 65*1da177e4SLinus Torvalds /* preserve current time */ 66*1da177e4SLinus Torvalds rtc.tv_sec = RCNR; 67*1da177e4SLinus Torvalds rtc.tv_nsec = 0; 68*1da177e4SLinus Torvalds save_time_delta(&delta, &rtc); 69*1da177e4SLinus Torvalds gpio = GPLR; 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds /* save vital registers */ 72*1da177e4SLinus Torvalds SAVE(GPDR); 73*1da177e4SLinus Torvalds SAVE(GAFR); 74*1da177e4SLinus Torvalds 75*1da177e4SLinus Torvalds SAVE(PPDR); 76*1da177e4SLinus Torvalds SAVE(PPSR); 77*1da177e4SLinus Torvalds SAVE(PPAR); 78*1da177e4SLinus Torvalds SAVE(PSDR); 79*1da177e4SLinus Torvalds 80*1da177e4SLinus Torvalds SAVE(Ser1SDCR0); 81*1da177e4SLinus Torvalds 82*1da177e4SLinus Torvalds /* Clear previous reset status */ 83*1da177e4SLinus Torvalds RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR; 84*1da177e4SLinus Torvalds 85*1da177e4SLinus Torvalds /* set resume return address */ 86*1da177e4SLinus Torvalds PSPR = virt_to_phys(sa1100_cpu_resume); 87*1da177e4SLinus Torvalds 88*1da177e4SLinus Torvalds /* go zzz */ 89*1da177e4SLinus Torvalds sa1100_cpu_suspend(); 90*1da177e4SLinus Torvalds 91*1da177e4SLinus Torvalds /* 92*1da177e4SLinus Torvalds * Ensure not to come back here if it wasn't intended 93*1da177e4SLinus Torvalds */ 94*1da177e4SLinus Torvalds PSPR = 0; 95*1da177e4SLinus Torvalds 96*1da177e4SLinus Torvalds /* 97*1da177e4SLinus Torvalds * Ensure interrupt sources are disabled; we will re-init 98*1da177e4SLinus Torvalds * the interrupt subsystem via the device manager. 99*1da177e4SLinus Torvalds */ 100*1da177e4SLinus Torvalds ICLR = 0; 101*1da177e4SLinus Torvalds ICCR = 1; 102*1da177e4SLinus Torvalds ICMR = 0; 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds /* restore registers */ 105*1da177e4SLinus Torvalds RESTORE(GPDR); 106*1da177e4SLinus Torvalds RESTORE(GAFR); 107*1da177e4SLinus Torvalds 108*1da177e4SLinus Torvalds RESTORE(PPDR); 109*1da177e4SLinus Torvalds RESTORE(PPSR); 110*1da177e4SLinus Torvalds RESTORE(PPAR); 111*1da177e4SLinus Torvalds RESTORE(PSDR); 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds RESTORE(Ser1SDCR0); 114*1da177e4SLinus Torvalds 115*1da177e4SLinus Torvalds GPSR = gpio; 116*1da177e4SLinus Torvalds GPCR = ~gpio; 117*1da177e4SLinus Torvalds 118*1da177e4SLinus Torvalds /* 119*1da177e4SLinus Torvalds * Clear the peripheral sleep-hold bit. 120*1da177e4SLinus Torvalds */ 121*1da177e4SLinus Torvalds PSSR = PSSR_PH; 122*1da177e4SLinus Torvalds 123*1da177e4SLinus Torvalds /* restore current time */ 124*1da177e4SLinus Torvalds rtc.tv_sec = RCNR; 125*1da177e4SLinus Torvalds restore_time_delta(&delta, &rtc); 126*1da177e4SLinus Torvalds 127*1da177e4SLinus Torvalds return 0; 128*1da177e4SLinus Torvalds } 129*1da177e4SLinus Torvalds 130*1da177e4SLinus Torvalds unsigned long sleep_phys_sp(void *sp) 131*1da177e4SLinus Torvalds { 132*1da177e4SLinus Torvalds return virt_to_phys(sp); 133*1da177e4SLinus Torvalds } 134*1da177e4SLinus Torvalds 135*1da177e4SLinus Torvalds /* 136*1da177e4SLinus Torvalds * Called after processes are frozen, but before we shut down devices. 137*1da177e4SLinus Torvalds */ 138*1da177e4SLinus Torvalds static int sa11x0_pm_prepare(suspend_state_t state) 139*1da177e4SLinus Torvalds { 140*1da177e4SLinus Torvalds return 0; 141*1da177e4SLinus Torvalds } 142*1da177e4SLinus Torvalds 143*1da177e4SLinus Torvalds /* 144*1da177e4SLinus Torvalds * Called after devices are re-setup, but before processes are thawed. 145*1da177e4SLinus Torvalds */ 146*1da177e4SLinus Torvalds static int sa11x0_pm_finish(suspend_state_t state) 147*1da177e4SLinus Torvalds { 148*1da177e4SLinus Torvalds return 0; 149*1da177e4SLinus Torvalds } 150*1da177e4SLinus Torvalds 151*1da177e4SLinus Torvalds /* 152*1da177e4SLinus Torvalds * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. 153*1da177e4SLinus Torvalds */ 154*1da177e4SLinus Torvalds static struct pm_ops sa11x0_pm_ops = { 155*1da177e4SLinus Torvalds .pm_disk_mode = PM_DISK_FIRMWARE, 156*1da177e4SLinus Torvalds .prepare = sa11x0_pm_prepare, 157*1da177e4SLinus Torvalds .enter = sa11x0_pm_enter, 158*1da177e4SLinus Torvalds .finish = sa11x0_pm_finish, 159*1da177e4SLinus Torvalds }; 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds static int __init sa11x0_pm_init(void) 162*1da177e4SLinus Torvalds { 163*1da177e4SLinus Torvalds pm_set_ops(&sa11x0_pm_ops); 164*1da177e4SLinus Torvalds return 0; 165*1da177e4SLinus Torvalds } 166*1da177e4SLinus Torvalds 167*1da177e4SLinus Torvalds late_initcall(sa11x0_pm_init); 168