pm.c (4263B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// Copyright 2008 Openmoko, Inc. 4// Copyright 2004-2008 Simtec Electronics 5// Ben Dooks <ben@simtec.co.uk> 6// http://armlinux.simtec.co.uk/ 7// 8// S3C common power management (suspend to ram) support. 9 10#include <linux/init.h> 11#include <linux/suspend.h> 12#include <linux/errno.h> 13#include <linux/delay.h> 14#include <linux/of.h> 15#include <linux/serial_s3c.h> 16#include <linux/io.h> 17 18#include <asm/cacheflush.h> 19#include <asm/suspend.h> 20 21#include "map.h" 22#include "regs-clock.h" 23#include "regs-irq.h" 24#include "irqs.h" 25 26#include <asm/irq.h> 27 28#include "cpu.h" 29#include "pm.h" 30#include "pm-core.h" 31 32/* for external use */ 33 34unsigned long s3c_pm_flags; 35 36/* The IRQ ext-int code goes here, it is too small to currently bother 37 * with its own file. */ 38 39unsigned long s3c_irqwake_intmask = 0xffffffffL; 40unsigned long s3c_irqwake_eintmask = 0xffffffffL; 41 42int s3c_irqext_wake(struct irq_data *data, unsigned int state) 43{ 44 unsigned long bit = 1L << IRQ_EINT_BIT(data->irq); 45 46 if (!(s3c_irqwake_eintallow & bit)) 47 return -ENOENT; 48 49 printk(KERN_INFO "wake %s for irq %d\n", 50 state ? "enabled" : "disabled", data->irq); 51 52 if (!state) 53 s3c_irqwake_eintmask |= bit; 54 else 55 s3c_irqwake_eintmask &= ~bit; 56 57 return 0; 58} 59 60void (*pm_cpu_prep)(void); 61int (*pm_cpu_sleep)(unsigned long); 62 63#define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) 64 65/* s3c_pm_enter 66 * 67 * central control for sleep/resume process 68*/ 69 70static int s3c_pm_enter(suspend_state_t state) 71{ 72 int ret; 73 /* ensure the debug is initialised (if enabled) */ 74 s3c_pm_debug_init_uart(); 75 76 S3C_PMDBG("%s(%d)\n", __func__, state); 77 78 if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { 79 printk(KERN_ERR "%s: error: no cpu sleep function\n", __func__); 80 return -EINVAL; 81 } 82 83 /* check if we have anything to wake-up with... bad things seem 84 * to happen if you suspend with no wakeup (system will often 85 * require a full power-cycle) 86 */ 87 88 if (!of_have_populated_dt() && 89 !any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && 90 !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { 91 printk(KERN_ERR "%s: No wake-up sources!\n", __func__); 92 printk(KERN_ERR "%s: Aborting sleep\n", __func__); 93 return -EINVAL; 94 } 95 96 /* save all necessary core registers not covered by the drivers */ 97 98 if (!of_have_populated_dt()) { 99 samsung_pm_save_gpios(); 100 samsung_pm_saved_gpios(); 101 } 102 103 s3c_pm_save_uarts(soc_is_s3c2410()); 104 s3c_pm_save_core(); 105 106 /* set the irq configuration for wake */ 107 108 s3c_pm_configure_extint(); 109 110 S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n", 111 s3c_irqwake_intmask, s3c_irqwake_eintmask); 112 113 s3c_pm_arch_prepare_irqs(); 114 115 /* call cpu specific preparation */ 116 117 pm_cpu_prep(); 118 119 /* flush cache back to ram */ 120 121 flush_cache_all(); 122 123 s3c_pm_check_store(); 124 125 /* send the cpu to sleep... */ 126 127 s3c_pm_arch_stop_clocks(); 128 129 /* this will also act as our return point from when 130 * we resume as it saves its own register state and restores it 131 * during the resume. */ 132 133 ret = cpu_suspend(0, pm_cpu_sleep); 134 if (ret) 135 return ret; 136 137 /* restore the system state */ 138 139 s3c_pm_restore_core(); 140 s3c_pm_restore_uarts(soc_is_s3c2410()); 141 142 if (!of_have_populated_dt()) { 143 samsung_pm_restore_gpios(); 144 s3c_pm_restored_gpios(); 145 } 146 147 s3c_pm_debug_init_uart(); 148 149 /* check what irq (if any) restored the system */ 150 151 s3c_pm_arch_show_resume_irqs(); 152 153 S3C_PMDBG("%s: post sleep, preparing to return\n", __func__); 154 155 /* LEDs should now be 1110 */ 156 s3c_pm_debug_smdkled(1 << 1, 0); 157 158 s3c_pm_check_restore(); 159 160 /* ok, let's return from sleep */ 161 162 S3C_PMDBG("S3C PM Resume (post-restore)\n"); 163 return 0; 164} 165 166static int s3c_pm_prepare(void) 167{ 168 /* prepare check area if configured */ 169 170 s3c_pm_check_prepare(); 171 return 0; 172} 173 174static void s3c_pm_finish(void) 175{ 176 s3c_pm_check_cleanup(); 177} 178 179static const struct platform_suspend_ops s3c_pm_ops = { 180 .enter = s3c_pm_enter, 181 .prepare = s3c_pm_prepare, 182 .finish = s3c_pm_finish, 183 .valid = suspend_valid_only_mem, 184}; 185 186/* s3c_pm_init 187 * 188 * Attach the power management functions. This should be called 189 * from the board specific initialisation if the board supports 190 * it. 191*/ 192 193int __init s3c_pm_init(void) 194{ 195 printk("S3C Power Management, Copyright 2004 Simtec Electronics\n"); 196 197 suspend_set_ops(&s3c_pm_ops); 198 return 0; 199}