18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * SA1100 Power Management Routines 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 78c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * History: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * 2001-02-06: Cliff Brake Initial code 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> & 148c2ecf20Sopenharmony_ci * Chester Kuo <chester@linux.org.tw> 158c2ecf20Sopenharmony_ci * Save more value for the resume function! Support 168c2ecf20Sopenharmony_ci * Bitsy/Assabet/Freebird board 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * 2001-08-29: Nicolas Pitre <nico@fluxnic.net> 198c2ecf20Sopenharmony_ci * Cleaned up, pushed platform dependent stuff 208c2ecf20Sopenharmony_ci * in the platform specific files. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array. 238c2ecf20Sopenharmony_ci * Storage is local on the stack now. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci#include <linux/init.h> 268c2ecf20Sopenharmony_ci#include <linux/io.h> 278c2ecf20Sopenharmony_ci#include <linux/suspend.h> 288c2ecf20Sopenharmony_ci#include <linux/errno.h> 298c2ecf20Sopenharmony_ci#include <linux/time.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <mach/hardware.h> 328c2ecf20Sopenharmony_ci#include <asm/memory.h> 338c2ecf20Sopenharmony_ci#include <asm/suspend.h> 348c2ecf20Sopenharmony_ci#include <asm/mach/time.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ciextern int sa1100_finish_suspend(unsigned long); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x 398c2ecf20Sopenharmony_ci#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * List of global SA11x0 peripheral registers to preserve. 438c2ecf20Sopenharmony_ci * More ones like CP and general purpose register values are preserved 448c2ecf20Sopenharmony_ci * on the stack and then the stack pointer is stored last in sleep.S. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cienum { SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR, 478c2ecf20Sopenharmony_ci SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR, 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci SLEEP_SAVE_Ser1SDCR0, 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci SLEEP_SAVE_COUNT 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int sa11x0_pm_enter(suspend_state_t state) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci unsigned long gpio, sleep_save[SLEEP_SAVE_COUNT]; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci gpio = GPLR; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* save vital registers */ 628c2ecf20Sopenharmony_ci SAVE(GPDR); 638c2ecf20Sopenharmony_ci SAVE(GAFR); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci SAVE(PPDR); 668c2ecf20Sopenharmony_ci SAVE(PPSR); 678c2ecf20Sopenharmony_ci SAVE(PPAR); 688c2ecf20Sopenharmony_ci SAVE(PSDR); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci SAVE(Ser1SDCR0); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Clear previous reset status */ 738c2ecf20Sopenharmony_ci RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* set resume return address */ 768c2ecf20Sopenharmony_ci PSPR = __pa_symbol(cpu_resume); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* go zzz */ 798c2ecf20Sopenharmony_ci cpu_suspend(0, sa1100_finish_suspend); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* 828c2ecf20Sopenharmony_ci * Ensure not to come back here if it wasn't intended 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci RCSR = RCSR_SMR; 858c2ecf20Sopenharmony_ci PSPR = 0; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* 888c2ecf20Sopenharmony_ci * Ensure interrupt sources are disabled; we will re-init 898c2ecf20Sopenharmony_ci * the interrupt subsystem via the device manager. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci ICLR = 0; 928c2ecf20Sopenharmony_ci ICCR = 1; 938c2ecf20Sopenharmony_ci ICMR = 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* restore registers */ 968c2ecf20Sopenharmony_ci RESTORE(GPDR); 978c2ecf20Sopenharmony_ci RESTORE(GAFR); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci RESTORE(PPDR); 1008c2ecf20Sopenharmony_ci RESTORE(PPSR); 1018c2ecf20Sopenharmony_ci RESTORE(PPAR); 1028c2ecf20Sopenharmony_ci RESTORE(PSDR); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci RESTORE(Ser1SDCR0); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci GPSR = gpio; 1078c2ecf20Sopenharmony_ci GPCR = ~gpio; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Clear the peripheral sleep-hold bit. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci PSSR = PSSR_PH; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic const struct platform_suspend_ops sa11x0_pm_ops = { 1188c2ecf20Sopenharmony_ci .enter = sa11x0_pm_enter, 1198c2ecf20Sopenharmony_ci .valid = suspend_valid_only_mem, 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ciint __init sa11x0_pm_init(void) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci suspend_set_ops(&sa11x0_pm_ops); 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 127