1/* linux/arch/arm/mach-s3c2410/pm.c 2 * 3 * Copyright (c) 2006 Simtec Electronics 4 * Ben Dooks <ben@simtec.co.uk> 5 * 6 * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21*/ 22 23#include <linux/init.h> 24#include <linux/suspend.h> 25#include <linux/errno.h> 26#include <linux/time.h> 27#include <linux/sysdev.h> 28#include <linux/gpio.h> 29#include <linux/io.h> 30 31#include <mach/hardware.h> 32 33#include <asm/mach-types.h> 34 35#include <mach/regs-gpio.h> 36#include <mach/h1940.h> 37 38#include <plat/cpu.h> 39#include <plat/pm.h> 40 41static void s3c2410_pm_prepare(void) 42{ 43 /* ensure at least GSTATUS3 has the resume address */ 44 45 __raw_writel(virt_to_phys(s3c_cpu_resume), S3C2410_GSTATUS3); 46 47 S3C_PMDBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); 48 S3C_PMDBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); 49 50 if (machine_is_h1940()) { 51 void *base = phys_to_virt(H1940_SUSPEND_CHECK); 52 unsigned long ptr; 53 unsigned long calc = 0; 54 55 /* generate check for the bootloader to check on resume */ 56 57 for (ptr = 0; ptr < 0x40000; ptr += 0x400) 58 calc += __raw_readl(base+ptr); 59 60 __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); 61 } 62 63 /* RX3715 and RX1950 use similar to H1940 code and the 64 * same offsets for resume and checksum pointers */ 65 66 if (machine_is_rx3715() || machine_is_rx1950()) { 67 void *base = phys_to_virt(H1940_SUSPEND_CHECK); 68 unsigned long ptr; 69 unsigned long calc = 0; 70 71 /* generate check for the bootloader to check on resume */ 72 73 for (ptr = 0; ptr < 0x40000; ptr += 0x4) 74 calc += __raw_readl(base+ptr); 75 76 __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); 77 } 78 79 if ( machine_is_aml_m5900() ) 80 s3c2410_gpio_setpin(S3C2410_GPF(2), 1); 81 82 if (machine_is_rx1950()) { 83 /* According to S3C2442 user's manual, page 7-17, 84 * when the system is operating in NAND boot mode, 85 * the hardware pin configuration - EINT[23:21] ��� 86 * must be set as input for starting up after 87 * wakeup from sleep mode 88 */ 89 s3c_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPIO_INPUT); 90 s3c_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPIO_INPUT); 91 s3c_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPIO_INPUT); 92 } 93} 94 95static int s3c2410_pm_resume(struct sys_device *dev) 96{ 97 unsigned long tmp; 98 99 /* unset the return-from-sleep flag, to ensure reset */ 100 101 tmp = __raw_readl(S3C2410_GSTATUS2); 102 tmp &= S3C2410_GSTATUS2_OFFRESET; 103 __raw_writel(tmp, S3C2410_GSTATUS2); 104 105 if ( machine_is_aml_m5900() ) 106 s3c2410_gpio_setpin(S3C2410_GPF(2), 0); 107 108 return 0; 109} 110 111static int s3c2410_pm_add(struct sys_device *dev) 112{ 113 pm_cpu_prep = s3c2410_pm_prepare; 114 pm_cpu_sleep = s3c2410_cpu_suspend; 115 116 return 0; 117} 118 119#if defined(CONFIG_CPU_S3C2410) 120static struct sysdev_driver s3c2410_pm_driver = { 121 .add = s3c2410_pm_add, 122 .resume = s3c2410_pm_resume, 123}; 124 125/* register ourselves */ 126 127static int __init s3c2410_pm_drvinit(void) 128{ 129 return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver); 130} 131 132arch_initcall(s3c2410_pm_drvinit); 133 134static struct sysdev_driver s3c2410a_pm_driver = { 135 .add = s3c2410_pm_add, 136 .resume = s3c2410_pm_resume, 137}; 138 139static int __init s3c2410a_pm_drvinit(void) 140{ 141 return sysdev_driver_register(&s3c2410a_sysclass, &s3c2410a_pm_driver); 142} 143 144arch_initcall(s3c2410a_pm_drvinit); 145#endif 146 147#if defined(CONFIG_CPU_S3C2440) 148static struct sysdev_driver s3c2440_pm_driver = { 149 .add = s3c2410_pm_add, 150 .resume = s3c2410_pm_resume, 151}; 152 153static int __init s3c2440_pm_drvinit(void) 154{ 155 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver); 156} 157 158arch_initcall(s3c2440_pm_drvinit); 159#endif 160 161#if defined(CONFIG_CPU_S3C2442) 162static struct sysdev_driver s3c2442_pm_driver = { 163 .add = s3c2410_pm_add, 164 .resume = s3c2410_pm_resume, 165}; 166 167static int __init s3c2442_pm_drvinit(void) 168{ 169 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver); 170} 171 172arch_initcall(s3c2442_pm_drvinit); 173#endif 174