/* linux/arch/arm/mach-s3c2416/pm.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks * * http://armlinux.simtec.co.uk/. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_PM_CPU_MODE extern unsigned char pm_cpu_mode; #endif static void s3c2416_cpu_suspend(void) { unsigned long tmp; #if 0 /* This is the USB driver work not PM */ /* USB Physical power */ __raw_writel(__raw_readl(S3C2443_PHYPWR) | 0xf, S3C2443_PHYPWR); /* USB Suspend mode */ __raw_writel(__raw_readl(S3C2410_MISCCR)|(1<<12)|(1<<13), S3C2410_MISCCR); #endif #if 0 /* What the heck??? We configure (even badly) MASK & PENDING ints, and we * set them after to a more bad value ???? */ __raw_writel(0xffffffff, S3C2410_INTMSK); __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); __raw_writel(0xffffffff, S3C2410_EINTPEND); __raw_writel(0xffffffff, S3C2410_EINTMASK); __raw_writel(0xffffffff, S3C2410_SRCPND); __raw_writel(0xffffffff, S3C2410_INTPND); __raw_writel((0xffffffff & ~((1<<0) | (1<<3) | (1<<30))) , S3C2410_INTMSK); #endif /* TODO: Need verification */ __raw_writel(0xff80, S3C2443_RSTCON); __raw_writel(0xffff, S3C2443_OSCSET); /* Allow wakeup even if BATT_FLT is asserted */ __raw_writel( (1<<15), S3C2443_PWRCFG); #if 0 /* Test */ /* shutdown as many device as possible */ /* Disable USB power */ /* Disable SD Power */ tmp = __raw_readl(S3C2410_GPHCON); tmp &= ~((3<<28)|(3<<8)); tmp |= (1<<28)|(1<<8); __raw_writel(tmp, S3C2410_GPHCON); tmp = __raw_readl(S3C2410_GPHUP); tmp &= ~((3<<28)|(3<<8)); __raw_writel(tmp, S3C2410_GPHUP); tmp = __raw_readl(S3C2410_GPHDAT); tmp &= ~((1<<14)|(1<<4)); __raw_writel(tmp, S3C2410_GPHDAT); /* Disable TCON power */ tmp = __raw_readl(S3C2410_GPBCON); tmp &= ~((3<<6)); tmp |= (1<<6); __raw_writel(tmp, S3C2410_GPBCON); tmp = __raw_readl(S3C2410_GPBUP); tmp &= ~((3<<6)); __raw_writel(tmp, S3C2410_GPBUP); tmp = __raw_readl(S3C2410_GPBDAT); tmp &= ~(1<<3); __raw_writel(tmp, S3C2410_GPBDAT); /* Disable Touch power */ /* Disable wifi/bt power */ tmp = __raw_readl(S3C2410_GPDCON); tmp &= ~((3<<20)|(3<22)); tmp |= (1<<20)|(1<<22); __raw_writel(tmp, S3C2410_GPDCON); tmp = __raw_readl(S3C2410_GPDUP); tmp &= ~((3<<20)|(3<<22)); __raw_writel(tmp, S3C2410_GPDUP); tmp = __raw_readl(S3C2410_GPDDAT); tmp &= ~((1<<11)|(1<<10)); __raw_writel(tmp, S3C2410_GPDDAT); #endif #ifdef CONFIG_PM_CPU_MODE /* set our standby method to sleep */ switch(pm_cpu_mode) { case PM_CPU_DEVICE_MODE_SUSPEND: __raw_writel(0x2BED, S3C2443_PWRMODE); break; case PM_CPU_MODE_STOP: __raw_writel(((__raw_readl(S3C2443_PWRMODE) & ~(1<<16))| (1<<16)), S3C2443_PWRMODE); break; case PM_CPU_MODE_DEEP_STOP: __raw_writel(((__raw_readl(S3C2443_PWRCFG) & ~(1<<16))| (1<<16)), S3C2443_PWRCFG); __raw_writel(((__raw_readl(S3C2443_PWRMODE) & ~(1<<16))| (1<<16)), S3C2443_PWRMODE); break; case PM_CPU_MODE_IDLE: __raw_writel(((__raw_readl(S3C2443_PWRCFG) & ~(1<<17))| (1<<17)), S3C2443_PWRCFG); asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt "STANDBYWFI" */ break; case PM_CPU_MODE_SLEEP: __raw_writel(0x2BED, S3C2443_PWRMODE); break; default: __raw_writel(0x2BED, S3C2443_PWRMODE); break; } #else __raw_writel(0x2BED, S3C2443_PWRMODE); #endif } static void s3c2416_pm_prepare(void) { /* set flag to wake up */ __raw_writel(0x2BED, S3C2443_INFORM0); /* Set Power_Mode to low */ //s3c2410_gpio_cfgpin(S3C2410_GPD12, S3C2410_GPD12_OUTP); /* <- D12 should already be configured */ /* TODO: have a "charger/battery driver" (maybe inside the USB driver?) */ s3c2410_gpio_setpin(S3C2410_GPD12, 0); } static int s3c2416_pm_add(struct sys_device *sysdev) { pm_cpu_prep = s3c2416_pm_prepare; pm_cpu_sleep = s3c2416_cpu_suspend; return 0; } static int s3c2416_pm_suspend(struct sys_device *dev, pm_message_t state) { return 0; } static int s3c2416_pm_resume(struct sys_device *dev) { __raw_writel(0x0, S3C2443_INFORM0); /* set PowerMode as high */ // s3c2410_gpio_cfgpin(S3C2410_GPD12, S3C2410_GPD12_OUTP); /* <- D12 should already be configured */ s3c2410_gpio_setpin(S3C2410_GPD12, 1); return 0; } static struct sysdev_driver s3c2416_pm_driver = { .add = s3c2416_pm_add, .suspend = s3c2416_pm_suspend, .resume = s3c2416_pm_resume, }; static __init int s3c2416_pm_init(void) { return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_pm_driver); } arch_initcall(s3c2416_pm_init);