2010-10-02 14:13:42 +04:00
/* linux/arch/arm/mach-s5pv210/pm.c
*
* Copyright ( c ) 2010 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com
*
* S5PV210 - Power Management support
*
* Based on arch / arm / mach - s3c2410 / pm . c
* Copyright ( c ) 2006 Simtec Electronics
* Ben Dooks < ben @ 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 <linux/init.h>
# include <linux/suspend.h>
2011-04-23 00:03:21 +04:00
# include <linux/syscore_ops.h>
2010-10-02 14:13:42 +04:00
# include <linux/io.h>
# include <plat/cpu.h>
# include <plat/pm.h>
# include <plat/regs-timer.h>
# include <mach/regs-irq.h>
# include <mach/regs-clock.h>
static struct sleep_save s5pv210_core_save [ ] = {
/* Clock source */
SAVE_ITEM ( S5P_CLK_SRC0 ) ,
SAVE_ITEM ( S5P_CLK_SRC1 ) ,
SAVE_ITEM ( S5P_CLK_SRC2 ) ,
SAVE_ITEM ( S5P_CLK_SRC3 ) ,
SAVE_ITEM ( S5P_CLK_SRC4 ) ,
SAVE_ITEM ( S5P_CLK_SRC5 ) ,
SAVE_ITEM ( S5P_CLK_SRC6 ) ,
/* Clock source Mask */
SAVE_ITEM ( S5P_CLK_SRC_MASK0 ) ,
SAVE_ITEM ( S5P_CLK_SRC_MASK1 ) ,
/* Clock Divider */
SAVE_ITEM ( S5P_CLK_DIV0 ) ,
SAVE_ITEM ( S5P_CLK_DIV1 ) ,
SAVE_ITEM ( S5P_CLK_DIV2 ) ,
SAVE_ITEM ( S5P_CLK_DIV3 ) ,
SAVE_ITEM ( S5P_CLK_DIV4 ) ,
SAVE_ITEM ( S5P_CLK_DIV5 ) ,
SAVE_ITEM ( S5P_CLK_DIV6 ) ,
SAVE_ITEM ( S5P_CLK_DIV7 ) ,
/* Clock Main Gate */
SAVE_ITEM ( S5P_CLKGATE_MAIN0 ) ,
SAVE_ITEM ( S5P_CLKGATE_MAIN1 ) ,
SAVE_ITEM ( S5P_CLKGATE_MAIN2 ) ,
/* Clock source Peri Gate */
SAVE_ITEM ( S5P_CLKGATE_PERI0 ) ,
SAVE_ITEM ( S5P_CLKGATE_PERI1 ) ,
/* Clock source SCLK Gate */
SAVE_ITEM ( S5P_CLKGATE_SCLK0 ) ,
SAVE_ITEM ( S5P_CLKGATE_SCLK1 ) ,
/* Clock IP Clock gate */
SAVE_ITEM ( S5P_CLKGATE_IP0 ) ,
SAVE_ITEM ( S5P_CLKGATE_IP1 ) ,
SAVE_ITEM ( S5P_CLKGATE_IP2 ) ,
SAVE_ITEM ( S5P_CLKGATE_IP3 ) ,
SAVE_ITEM ( S5P_CLKGATE_IP4 ) ,
/* Clock Blcok and Bus gate */
SAVE_ITEM ( S5P_CLKGATE_BLOCK ) ,
SAVE_ITEM ( S5P_CLKGATE_BUS0 ) ,
/* Clock ETC */
SAVE_ITEM ( S5P_CLK_OUT ) ,
SAVE_ITEM ( S5P_MDNIE_SEL ) ,
/* PWM Register */
SAVE_ITEM ( S3C2410_TCFG0 ) ,
SAVE_ITEM ( S3C2410_TCFG1 ) ,
SAVE_ITEM ( S3C64XX_TINT_CSTAT ) ,
SAVE_ITEM ( S3C2410_TCON ) ,
SAVE_ITEM ( S3C2410_TCNTB ( 0 ) ) ,
SAVE_ITEM ( S3C2410_TCMPB ( 0 ) ) ,
SAVE_ITEM ( S3C2410_TCNTO ( 0 ) ) ,
} ;
2011-08-13 05:34:56 +04:00
static int s5pv210_cpu_suspend ( unsigned long arg )
2010-10-02 14:13:42 +04:00
{
unsigned long tmp ;
/* issue the standby signal into the pm unit. Note, we
* issue a write - buffer drain just in case */
tmp = 0 ;
asm ( " b 1f \n \t "
" .align 5 \n \t "
" 1: \n \t "
" mcr p15, 0, %0, c7, c10, 5 \n \t "
" mcr p15, 0, %0, c7, c10, 4 \n \t "
" wfi " : : " r " ( tmp ) ) ;
/* we should never get past here */
panic ( " sleep resumed to originator? " ) ;
}
static void s5pv210_pm_prepare ( void )
{
unsigned int tmp ;
/* ensure at least INFORM0 has the resume address */
__raw_writel ( virt_to_phys ( s3c_cpu_resume ) , S5P_INFORM0 ) ;
tmp = __raw_readl ( S5P_SLEEP_CFG ) ;
tmp & = ~ ( S5P_SLEEP_CFG_OSC_EN | S5P_SLEEP_CFG_USBOSC_EN ) ;
__raw_writel ( tmp , S5P_SLEEP_CFG ) ;
/* WFI for SLEEP mode configuration by SYSCON */
tmp = __raw_readl ( S5P_PWR_CFG ) ;
tmp & = S5P_CFG_WFI_CLEAN ;
tmp | = S5P_CFG_WFI_SLEEP ;
__raw_writel ( tmp , S5P_PWR_CFG ) ;
/* SYSCON interrupt handling disable */
tmp = __raw_readl ( S5P_OTHERS ) ;
tmp | = S5P_OTHER_SYSC_INTOFF ;
__raw_writel ( tmp , S5P_OTHERS ) ;
s3c_pm_do_save ( s5pv210_core_save , ARRAY_SIZE ( s5pv210_core_save ) ) ;
}
static int s5pv210_pm_add ( struct sys_device * sysdev )
{
pm_cpu_prep = s5pv210_pm_prepare ;
pm_cpu_sleep = s5pv210_cpu_suspend ;
return 0 ;
}
2011-04-23 00:03:21 +04:00
static struct sysdev_driver s5pv210_pm_driver = {
. add = s5pv210_pm_add ,
} ;
static __init int s5pv210_pm_drvinit ( void )
{
return sysdev_driver_register ( & s5pv210_sysclass , & s5pv210_pm_driver ) ;
}
arch_initcall ( s5pv210_pm_drvinit ) ;
static void s5pv210_pm_resume ( void )
2010-10-02 14:13:42 +04:00
{
u32 tmp ;
tmp = __raw_readl ( S5P_OTHERS ) ;
tmp | = ( S5P_OTHERS_RET_IO | S5P_OTHERS_RET_CF | \
S5P_OTHERS_RET_MMC | S5P_OTHERS_RET_UART ) ;
__raw_writel ( tmp , S5P_OTHERS ) ;
s3c_pm_do_restore_core ( s5pv210_core_save , ARRAY_SIZE ( s5pv210_core_save ) ) ;
}
2011-04-23 00:03:21 +04:00
static struct syscore_ops s5pv210_pm_syscore_ops = {
2010-10-02 14:13:42 +04:00
. resume = s5pv210_pm_resume ,
} ;
2011-04-23 00:03:21 +04:00
static __init int s5pv210_pm_syscore_init ( void )
2010-10-02 14:13:42 +04:00
{
2011-04-23 00:03:21 +04:00
register_syscore_ops ( & s5pv210_pm_syscore_ops ) ;
return 0 ;
2010-10-02 14:13:42 +04:00
}
2011-04-23 00:03:21 +04:00
arch_initcall ( s5pv210_pm_syscore_init ) ;