1 /* 2 * arch/arm/mach-at91/pm.c 3 * AT91 Power Management 4 * 5 * Copyright (C) 2005 David Brownell 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 */ 12 13 #include <linux/pm.h> 14 #include <linux/sched.h> 15 #include <linux/proc_fs.h> 16 #include <linux/pm.h> 17 #include <linux/interrupt.h> 18 #include <linux/sysfs.h> 19 #include <linux/module.h> 20 #include <linux/platform_device.h> 21 22 #include <asm/io.h> 23 #include <asm/irq.h> 24 #include <asm/atomic.h> 25 #include <asm/mach/time.h> 26 #include <asm/mach/irq.h> 27 #include <asm/mach-types.h> 28 29 #include <asm/arch/at91_pmc.h> 30 #include <asm/arch/at91rm9200_mc.h> 31 #include <asm/arch/gpio.h> 32 #include <asm/arch/cpu.h> 33 34 #include "generic.h" 35 36 37 static int at91_pm_valid_state(suspend_state_t state) 38 { 39 switch (state) { 40 case PM_SUSPEND_ON: 41 case PM_SUSPEND_STANDBY: 42 case PM_SUSPEND_MEM: 43 return 1; 44 45 default: 46 return 0; 47 } 48 } 49 50 51 static suspend_state_t target_state; 52 53 /* 54 * Called after processes are frozen, but before we shutdown devices. 55 */ 56 static int at91_pm_prepare(suspend_state_t state) 57 { 58 target_state = state; 59 return 0; 60 } 61 62 /* 63 * Verify that all the clocks are correct before entering 64 * slow-clock mode. 65 */ 66 static int at91_pm_verify_clocks(void) 67 { 68 unsigned long scsr; 69 int i; 70 71 scsr = at91_sys_read(AT91_PMC_SCSR); 72 73 /* USB must not be using PLLB */ 74 if (cpu_is_at91rm9200()) { 75 if ((scsr & (AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP)) != 0) { 76 pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n"); 77 return 0; 78 } 79 } else if (cpu_is_at91sam9260()) { 80 #warning "Check SAM9260 USB clocks" 81 } else if (cpu_is_at91sam9261()) { 82 #warning "Check SAM9261 USB clocks" 83 } else if (cpu_is_at91sam9263()) { 84 #warning "Check SAM9263 USB clocks" 85 } 86 87 #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS 88 /* PCK0..PCK3 must be disabled, or configured to use clk32k */ 89 for (i = 0; i < 4; i++) { 90 u32 css; 91 92 if ((scsr & (AT91_PMC_PCK0 << i)) == 0) 93 continue; 94 95 css = at91_sys_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS; 96 if (css != AT91_PMC_CSS_SLOW) { 97 pr_debug("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css); 98 return 0; 99 } 100 } 101 #endif 102 103 return 1; 104 } 105 106 /* 107 * Call this from platform driver suspend() to see how deeply to suspend. 108 * For example, some controllers (like OHCI) need one of the PLL clocks 109 * in order to act as a wakeup source, and those are not available when 110 * going into slow clock mode. 111 * 112 * REVISIT: generalize as clk_will_be_available(clk)? Other platforms have 113 * the very same problem (but not using at91 main_clk), and it'd be better 114 * to add one generic API rather than lots of platform-specific ones. 115 */ 116 int at91_suspend_entering_slow_clock(void) 117 { 118 return (target_state == PM_SUSPEND_MEM); 119 } 120 EXPORT_SYMBOL(at91_suspend_entering_slow_clock); 121 122 123 static void (*slow_clock)(void); 124 125 126 static int at91_pm_enter(suspend_state_t state) 127 { 128 at91_gpio_suspend(); 129 at91_irq_suspend(); 130 131 pr_debug("AT91: PM - wake mask %08x, pm state %d\n", 132 /* remember all the always-wake irqs */ 133 (at91_sys_read(AT91_PMC_PCSR) 134 | (1 << AT91_ID_FIQ) 135 | (1 << AT91_ID_SYS) 136 | (at91_extern_irq)) 137 & at91_sys_read(AT91_AIC_IMR), 138 state); 139 140 switch (state) { 141 /* 142 * Suspend-to-RAM is like STANDBY plus slow clock mode, so 143 * drivers must suspend more deeply: only the master clock 144 * controller may be using the main oscillator. 145 */ 146 case PM_SUSPEND_MEM: 147 /* 148 * Ensure that clocks are in a valid state. 149 */ 150 if (!at91_pm_verify_clocks()) 151 goto error; 152 153 /* 154 * Enter slow clock mode by switching over to clk32k and 155 * turning off the main oscillator; reverse on wakeup. 156 */ 157 if (slow_clock) { 158 slow_clock(); 159 break; 160 } else { 161 /* DEVELOPMENT ONLY */ 162 pr_info("AT91: PM - no slow clock mode yet ...\n"); 163 /* FALLTHROUGH leaving master clock alone */ 164 } 165 166 /* 167 * STANDBY mode has *all* drivers suspended; ignores irqs not 168 * marked as 'wakeup' event sources; and reduces DRAM power. 169 * But otherwise it's identical to PM_SUSPEND_ON: cpu idle, and 170 * nothing fancy done with main or cpu clocks. 171 */ 172 case PM_SUSPEND_STANDBY: 173 /* 174 * NOTE: the Wait-for-Interrupt instruction needs to be 175 * in icache so the SDRAM stays in self-refresh mode until 176 * the wakeup IRQ occurs. 177 */ 178 asm("b 1f; .align 5; 1:"); 179 asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ 180 at91_sys_write(AT91_SDRAMC_SRR, 1); /* self-refresh mode */ 181 /* fall though to next state */ 182 183 case PM_SUSPEND_ON: 184 asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ 185 break; 186 187 default: 188 pr_debug("AT91: PM - bogus suspend state %d\n", state); 189 goto error; 190 } 191 192 pr_debug("AT91: PM - wakeup %08x\n", 193 at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR)); 194 195 error: 196 target_state = PM_SUSPEND_ON; 197 at91_irq_resume(); 198 at91_gpio_resume(); 199 return 0; 200 } 201 202 203 static struct pm_ops at91_pm_ops ={ 204 .pm_disk_mode = 0, 205 .valid = at91_pm_valid_state, 206 .prepare = at91_pm_prepare, 207 .enter = at91_pm_enter, 208 }; 209 210 static int __init at91_pm_init(void) 211 { 212 printk("AT91: Power Management\n"); 213 214 #ifdef CONFIG_AT91_PM_SLOW_CLOCK 215 /* REVISIT allocations of SRAM should be dynamically managed. 216 * FIQ handlers and other components will want SRAM/TCM too... 217 */ 218 slow_clock = (void *) (AT91_VA_BASE_SRAM + (3 * SZ_4K)); 219 memcpy(slow_clock, at91rm9200_slow_clock, at91rm9200_slow_clock_sz); 220 #endif 221 222 /* Disable SDRAM low-power mode. Cannot be used with self-refresh. */ 223 at91_sys_write(AT91_SDRAMC_LPR, 0); 224 225 pm_set_ops(&at91_pm_ops); 226 227 return 0; 228 } 229 arch_initcall(at91_pm_init); 230