2011-09-21 21:46:20 +08:00
/*
* power management entry for CSR SiRFprimaII
*
* Copyright ( c ) 2011 Cambridge Silicon Radio Limited , a CSR plc group company .
*
* Licensed under GPLv2 or later .
*/
# include <linux/kernel.h>
# include <linux/suspend.h>
# include <linux/slab.h>
2011-11-17 22:27:22 +08:00
# include <linux/module.h>
2011-09-21 21:46:20 +08:00
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_device.h>
# include <linux/of_platform.h>
# include <linux/io.h>
# include <linux/rtc/sirfsoc_rtciobrg.h>
# include <asm/suspend.h>
# include <asm/hardware/cache-l2x0.h>
# include "pm.h"
/*
* suspend asm codes will access these to make DRAM become self - refresh and
* system sleep
*/
u32 sirfsoc_pwrc_base ;
void __iomem * sirfsoc_memc_base ;
static void sirfsoc_set_wakeup_source ( void )
{
u32 pwr_trigger_en_reg ;
pwr_trigger_en_reg = sirfsoc_rtc_iobrg_readl ( sirfsoc_pwrc_base +
SIRFSOC_PWRC_TRIGGER_EN ) ;
# define X_ON_KEY_B (1 << 0)
sirfsoc_rtc_iobrg_writel ( pwr_trigger_en_reg | X_ON_KEY_B ,
sirfsoc_pwrc_base + SIRFSOC_PWRC_TRIGGER_EN ) ;
}
static void sirfsoc_set_sleep_mode ( u32 mode )
{
u32 sleep_mode = sirfsoc_rtc_iobrg_readl ( sirfsoc_pwrc_base +
SIRFSOC_PWRC_PDN_CTRL ) ;
sleep_mode & = ~ ( SIRFSOC_SLEEP_MODE_MASK < < 1 ) ;
sleep_mode | = mode < < 1 ;
sirfsoc_rtc_iobrg_writel ( sleep_mode , sirfsoc_pwrc_base +
SIRFSOC_PWRC_PDN_CTRL ) ;
}
static int sirfsoc_pre_suspend_power_off ( void )
{
u32 wakeup_entry = virt_to_phys ( cpu_resume ) ;
sirfsoc_rtc_iobrg_writel ( wakeup_entry , sirfsoc_pwrc_base +
SIRFSOC_PWRC_SCRATCH_PAD1 ) ;
sirfsoc_set_wakeup_source ( ) ;
sirfsoc_set_sleep_mode ( SIRFSOC_DEEP_SLEEP_MODE ) ;
return 0 ;
}
static int sirfsoc_pm_enter ( suspend_state_t state )
{
switch ( state ) {
case PM_SUSPEND_MEM :
sirfsoc_pre_suspend_power_off ( ) ;
outer_flush_all ( ) ;
outer_disable ( ) ;
/* go zzz */
cpu_suspend ( 0 , sirfsoc_finish_suspend ) ;
2011-10-10 02:50:54 -07:00
outer_resume ( ) ;
2011-09-21 21:46:20 +08:00
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static const struct platform_suspend_ops sirfsoc_pm_ops = {
. enter = sirfsoc_pm_enter ,
. valid = suspend_valid_only_mem ,
} ;
2012-04-26 20:51:36 +08:00
int __init sirfsoc_pm_init ( void )
2011-09-21 21:46:20 +08:00
{
suspend_set_ops ( & sirfsoc_pm_ops ) ;
return 0 ;
}
static const struct of_device_id pwrc_ids [ ] = {
{ . compatible = " sirf,prima2-pwrc " } ,
{ }
} ;
static int __init sirfsoc_of_pwrc_init ( void )
{
struct device_node * np ;
np = of_find_matching_node ( NULL , pwrc_ids ) ;
if ( ! np )
panic ( " unable to find compatible pwrc node in dtb \n " ) ;
/*
* pwrc behind rtciobrg is not located in memory space
* though the property is named reg . reg only means base
* offset for pwrc . then of_iomap is not suitable here .
*/
if ( of_property_read_u32 ( np , " reg " , & sirfsoc_pwrc_base ) )
panic ( " unable to find base address of pwrc node in dtb \n " ) ;
of_node_put ( np ) ;
return 0 ;
}
postcore_initcall ( sirfsoc_of_pwrc_init ) ;
static const struct of_device_id memc_ids [ ] = {
{ . compatible = " sirf,prima2-memc " } ,
{ }
} ;
2012-12-21 14:02:24 -08:00
static int sirfsoc_memc_probe ( struct platform_device * op )
2011-09-21 21:46:20 +08:00
{
struct device_node * np = op - > dev . of_node ;
sirfsoc_memc_base = of_iomap ( np , 0 ) ;
if ( ! sirfsoc_memc_base )
panic ( " unable to map memc registers \n " ) ;
return 0 ;
}
static struct platform_driver sirfsoc_memc_driver = {
. probe = sirfsoc_memc_probe ,
. driver = {
. name = " sirfsoc-memc " ,
. owner = THIS_MODULE ,
. of_match_table = memc_ids ,
} ,
} ;
static int __init sirfsoc_memc_init ( void )
{
return platform_driver_register ( & sirfsoc_memc_driver ) ;
}
postcore_initcall ( sirfsoc_memc_init ) ;