1/* 2 * arch/arm/mach-pnx4008/pm.c 3 * 4 * Power Management driver for PNX4008 5 * 6 * Authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com> 7 * 8 * 2005 (c) MontaVista Software, Inc. This file is licensed under 9 * the terms of the GNU General Public License version 2. This program 10 * is licensed "as is" without any warranty of any kind, whether express 11 * or implied. 12 */ 13 14#include <linux/pm.h> 15#include <linux/rtc.h> 16#include <linux/sched.h> 17#include <linux/proc_fs.h> 18#include <linux/suspend.h> 19#include <linux/delay.h> 20#include <linux/clk.h> 21#include <linux/io.h> 22#include <linux/slab.h> 23 24#include <asm/cacheflush.h> 25 26#include <mach/hardware.h> 27#include <mach/pm.h> 28#include <mach/clock.h> 29 30#define SRAM_VA IO_ADDRESS(PNX4008_IRAM_BASE) 31 32static void *saved_sram; 33 34static struct clk *pll4_clk; 35 36static inline void pnx4008_standby(void) 37{ 38 void (*pnx4008_cpu_standby_ptr) (void); 39 40 local_irq_disable(); 41 local_fiq_disable(); 42 43 clk_disable(pll4_clk); 44 45 /*saving portion of SRAM to be used by suspend function. */ 46 memcpy(saved_sram, (void *)SRAM_VA, pnx4008_cpu_standby_sz); 47 48 /*make sure SRAM copy gets physically written into SDRAM. 49 SDRAM will be placed into self-refresh during power down */ 50 flush_cache_all(); 51 52 /*copy suspend function into SRAM */ 53 memcpy((void *)SRAM_VA, pnx4008_cpu_standby, pnx4008_cpu_standby_sz); 54 55 /*do suspend */ 56 pnx4008_cpu_standby_ptr = (void *)SRAM_VA; 57 pnx4008_cpu_standby_ptr(); 58 59 /*restoring portion of SRAM that was used by suspend function */ 60 memcpy((void *)SRAM_VA, saved_sram, pnx4008_cpu_standby_sz); 61 62 clk_enable(pll4_clk); 63 64 local_fiq_enable(); 65 local_irq_enable(); 66} 67 68static inline void pnx4008_suspend(void) 69{ 70 void (*pnx4008_cpu_suspend_ptr) (void); 71 72 local_irq_disable(); 73 local_fiq_disable(); 74 75 clk_disable(pll4_clk); 76 77 __raw_writel(0xffffffff, START_INT_RSR_REG(SE_PIN_BASE_INT)); 78 __raw_writel(0xffffffff, START_INT_RSR_REG(SE_INT_BASE_INT)); 79 80 /*saving portion of SRAM to be used by suspend function. */ 81 memcpy(saved_sram, (void *)SRAM_VA, pnx4008_cpu_suspend_sz); 82 83 /*make sure SRAM copy gets physically written into SDRAM. 84 SDRAM will be placed into self-refresh during power down */ 85 flush_cache_all(); 86 87 /*copy suspend function into SRAM */ 88 memcpy((void *)SRAM_VA, pnx4008_cpu_suspend, pnx4008_cpu_suspend_sz); 89 90 /*do suspend */ 91 pnx4008_cpu_suspend_ptr = (void *)SRAM_VA; 92 pnx4008_cpu_suspend_ptr(); 93 94 /*restoring portion of SRAM that was used by suspend function */ 95 memcpy((void *)SRAM_VA, saved_sram, pnx4008_cpu_suspend_sz); 96 97 clk_enable(pll4_clk); 98 99 local_fiq_enable(); 100 local_irq_enable(); 101} 102 103static int pnx4008_pm_enter(suspend_state_t state) 104{ 105 switch (state) { 106 case PM_SUSPEND_STANDBY: 107 pnx4008_standby(); 108 break; 109 case PM_SUSPEND_MEM: 110 pnx4008_suspend(); 111 break; 112 } 113 return 0; 114} 115 116static int pnx4008_pm_valid(suspend_state_t state) 117{ 118 return (state == PM_SUSPEND_STANDBY) || 119 (state == PM_SUSPEND_MEM); 120} 121 122static struct platform_suspend_ops pnx4008_pm_ops = { 123 .enter = pnx4008_pm_enter, 124 .valid = pnx4008_pm_valid, 125}; 126 127static int __init pnx4008_pm_init(void) 128{ 129 u32 sram_size_to_allocate; 130 131 pll4_clk = clk_get(0, "ck_pll4"); 132 if (IS_ERR(pll4_clk)) { 133 printk(KERN_ERR 134 "PM Suspend cannot acquire ARM(PLL4) clock control\n"); 135 return PTR_ERR(pll4_clk); 136 } 137 138 if (pnx4008_cpu_standby_sz > pnx4008_cpu_suspend_sz) 139 sram_size_to_allocate = pnx4008_cpu_standby_sz; 140 else 141 sram_size_to_allocate = pnx4008_cpu_suspend_sz; 142 143 saved_sram = kmalloc(sram_size_to_allocate, GFP_ATOMIC); 144 if (!saved_sram) { 145 printk(KERN_ERR 146 "PM Suspend: cannot allocate memory to save portion of SRAM\n"); 147 clk_put(pll4_clk); 148 return -ENOMEM; 149 } 150 151 suspend_set_ops(&pnx4008_pm_ops); 152 return 0; 153} 154 155late_initcall(pnx4008_pm_init); 156