aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-pxa/pxa3xx.c
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2008-01-07 17:18:30 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-01-26 10:07:56 -0500
commit7b5dea12346f98b0624e00ef585246bfec8b0959 (patch)
treea0a04aa5101b716915e7256fca79d8db0d7fbe07 /arch/arm/mach-pxa/pxa3xx.c
parenta10476d4ca52039a9240ac26376e15308b748b19 (diff)
[ARM] pxa: Add PXA3 standby code hooked into the IRQ wake scheme
Wakeup sources on PXA3 are enabled at two levels. First, the MFP configuration has to be set to enable which edges a specific pin will trigger a wakeup. The pin also has to be routed to a functional unit. Lastly, the functional unit must be enabled as a wakeup source in the appropriate AD*ER registers (AD2D0ER for standby resume.) This doesn't fit well with the IRQ wake scheme - we currently do a best effort conversion from IRQ numbers to functional unit wake enable bits. For instance, there's several USB client related enable bits but there's no corresponding IRQs to determine which you'd want. Conversely, there's a single enable bit covering several functional units. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-pxa/pxa3xx.c')
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index fcb2359b3867..0b2a15ed3999 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -19,6 +19,7 @@
19#include <linux/pm.h> 19#include <linux/pm.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/irq.h> 21#include <linux/irq.h>
22#include <linux/io.h>
22 23
23#include <asm/hardware.h> 24#include <asm/hardware.h>
24#include <asm/arch/pxa3xx-regs.h> 25#include <asm/arch/pxa3xx-regs.h>
@@ -201,6 +202,225 @@ static struct clk pxa3xx_clks[] = {
201 PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev), 202 PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev),
202}; 203};
203 204
205#ifdef CONFIG_PM
206#define SLEEP_SAVE_SIZE 4
207
208#define ISRAM_START 0x5c000000
209#define ISRAM_SIZE SZ_256K
210
211static void __iomem *sram;
212static unsigned long wakeup_src;
213
214static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
215{
216 pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB);
217
218 if (CKENA & (1 << CKEN_USBH)) {
219 printk(KERN_ERR "PM: USB host clock not stopped?\n");
220 CKENA &= ~(1 << CKEN_USBH);
221 }
222// CKENA |= 1 << (CKEN_ISC & 31);
223
224 /*
225 * Low power modes require the HSIO2 clock to be enabled.
226 */
227 CKENB |= 1 << (CKEN_HSIO2 & 31);
228}
229
230static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save)
231{
232 CKENB &= ~(1 << (CKEN_HSIO2 & 31));
233}
234
235/*
236 * Enter a standby mode (S0D1C2 or S0D2C2). Upon wakeup, the dynamic
237 * memory controller has to be reinitialised, so we place some code
238 * in the SRAM to perform this function.
239 *
240 * We disable FIQs across the standby - otherwise, we might receive a
241 * FIQ while the SDRAM is unavailable.
242 */
243static void pxa3xx_cpu_standby(unsigned int pwrmode)
244{
245 extern const char pm_enter_standby_start[], pm_enter_standby_end[];
246 void (*fn)(unsigned int) = (void __force *)(sram + 0x8000);
247
248 memcpy_toio(sram + 0x8000, pm_enter_standby_start,
249 pm_enter_standby_end - pm_enter_standby_start);
250
251 AD2D0SR = ~0;
252 AD2D1SR = ~0;
253 AD2D0ER = wakeup_src;
254 AD2D1ER = 0;
255 ASCR = ASCR;
256 ARSR = ARSR;
257
258 local_fiq_disable();
259 fn(pwrmode);
260 local_fiq_enable();
261
262 AD2D0ER = 0;
263 AD2D1ER = 0;
264
265 printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR);
266}
267
268static void pxa3xx_cpu_pm_enter(suspend_state_t state)
269{
270 /*
271 * Don't sleep if no wakeup sources are defined
272 */
273 if (wakeup_src == 0)
274 return;
275
276 switch (state) {
277 case PM_SUSPEND_STANDBY:
278 pxa3xx_cpu_standby(PXA3xx_PM_S0D2C2);
279 break;
280
281 case PM_SUSPEND_MEM:
282 break;
283 }
284}
285
286static int pxa3xx_cpu_pm_valid(suspend_state_t state)
287{
288 return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY;
289}
290
291static struct pxa_cpu_pm_fns pxa3xx_cpu_pm_fns = {
292 .save_size = SLEEP_SAVE_SIZE,
293 .save = pxa3xx_cpu_pm_save,
294 .restore = pxa3xx_cpu_pm_restore,
295 .valid = pxa3xx_cpu_pm_valid,
296 .enter = pxa3xx_cpu_pm_enter,
297};
298
299static void __init pxa3xx_init_pm(void)
300{
301 sram = ioremap(ISRAM_START, ISRAM_SIZE);
302 if (!sram) {
303 printk(KERN_ERR "Unable to map ISRAM: disabling standby/suspend\n");
304 return;
305 }
306
307 /*
308 * Since we copy wakeup code into the SRAM, we need to ensure
309 * that it is preserved over the low power modes. Note: bit 8
310 * is undocumented in the developer manual, but must be set.
311 */
312 AD1R |= ADXR_L2 | ADXR_R0;
313 AD2R |= ADXR_L2 | ADXR_R0;
314 AD3R |= ADXR_L2 | ADXR_R0;
315
316 /*
317 * Clear the resume enable registers.
318 */
319 AD1D0ER = 0;
320 AD2D0ER = 0;
321 AD2D1ER = 0;
322 AD3ER = 0;
323
324 pxa_cpu_pm_fns = &pxa3xx_cpu_pm_fns;
325}
326
327static int pxa3xx_set_wake(unsigned int irq, unsigned int on)
328{
329 unsigned long flags, mask = 0;
330
331 switch (irq) {
332 case IRQ_SSP3:
333 mask = ADXER_MFP_WSSP3;
334 break;
335 case IRQ_MSL:
336 mask = ADXER_WMSL0;
337 break;
338 case IRQ_USBH2:
339 case IRQ_USBH1:
340 mask = ADXER_WUSBH;
341 break;
342 case IRQ_KEYPAD:
343 mask = ADXER_WKP;
344 break;
345 case IRQ_AC97:
346 mask = ADXER_MFP_WAC97;
347 break;
348 case IRQ_USIM:
349 mask = ADXER_WUSIM0;
350 break;
351 case IRQ_SSP2:
352 mask = ADXER_MFP_WSSP2;
353 break;
354 case IRQ_I2C:
355 mask = ADXER_MFP_WI2C;
356 break;
357 case IRQ_STUART:
358 mask = ADXER_MFP_WUART3;
359 break;
360 case IRQ_BTUART:
361 mask = ADXER_MFP_WUART2;
362 break;
363 case IRQ_FFUART:
364 mask = ADXER_MFP_WUART1;
365 break;
366 case IRQ_MMC:
367 mask = ADXER_MFP_WMMC1;
368 break;
369 case IRQ_SSP:
370 mask = ADXER_MFP_WSSP1;
371 break;
372 case IRQ_RTCAlrm:
373 mask = ADXER_WRTC;
374 break;
375 case IRQ_SSP4:
376 mask = ADXER_MFP_WSSP4;
377 break;
378 case IRQ_TSI:
379 mask = ADXER_WTSI;
380 break;
381 case IRQ_USIM2:
382 mask = ADXER_WUSIM1;
383 break;
384 case IRQ_MMC2:
385 mask = ADXER_MFP_WMMC2;
386 break;
387 case IRQ_NAND:
388 mask = ADXER_MFP_WFLASH;
389 break;
390 case IRQ_USB2:
391 mask = ADXER_WUSB2;
392 break;
393 case IRQ_WAKEUP0:
394 mask = ADXER_WEXTWAKE0;
395 break;
396 case IRQ_WAKEUP1:
397 mask = ADXER_WEXTWAKE1;
398 break;
399 case IRQ_MMC3:
400 mask = ADXER_MFP_GEN12;
401 break;
402 }
403
404 local_irq_save(flags);
405 if (on)
406 wakeup_src |= mask;
407 else
408 wakeup_src &= ~mask;
409 local_irq_restore(flags);
410
411 return 0;
412}
413
414static void pxa3xx_init_irq_pm(void)
415{
416 pxa_init_irq_set_wake(pxa3xx_set_wake);
417}
418
419#else
420static inline void pxa3xx_init_pm(void) {}
421static inline void pxa3xx_init_irq_pm(void) {}
422#endif
423
204void __init pxa3xx_init_irq(void) 424void __init pxa3xx_init_irq(void)
205{ 425{
206 /* enable CP6 access */ 426 /* enable CP6 access */
@@ -212,6 +432,7 @@ void __init pxa3xx_init_irq(void)
212 pxa_init_irq_low(); 432 pxa_init_irq_low();
213 pxa_init_irq_high(); 433 pxa_init_irq_high();
214 pxa_init_irq_gpio(128); 434 pxa_init_irq_gpio(128);
435 pxa3xx_init_irq_pm();
215} 436}
216 437
217/* 438/*
@@ -241,6 +462,8 @@ static int __init pxa3xx_init(void)
241 if ((ret = pxa_init_dma(32))) 462 if ((ret = pxa_init_dma(32)))
242 return ret; 463 return ret;
243 464
465 pxa3xx_init_pm();
466
244 return platform_add_devices(devices, ARRAY_SIZE(devices)); 467 return platform_add_devices(devices, ARRAY_SIZE(devices));
245 } 468 }
246 return 0; 469 return 0;