#define RO_CLK         60000000
 
 #define ACCR_D0CS      (1 << 26)
+#define ACCR_PCCE      (1 << 11)
 
 /* crystal frequency to static memory controller multiplier (SMCFS) */
 static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
 };
 
 #ifdef CONFIG_PM
-#define SLEEP_SAVE_SIZE        4
 
 #define ISRAM_START    0x5c000000
 #define ISRAM_SIZE     SZ_256K
 static void __iomem *sram;
 static unsigned long wakeup_src;
 
-static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
-{
-       pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB);
+#define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
 
-       if (CKENA & (1 << CKEN_USBH)) {
-               printk(KERN_ERR "PM: USB host clock not stopped?\n");
-               CKENA &= ~(1 << CKEN_USBH);
-       }
-//     CKENA |= 1 << (CKEN_ISC & 31);
+enum { SLEEP_SAVE_START = 0,
+       SLEEP_SAVE_CKENA,
+       SLEEP_SAVE_CKENB,
+       SLEEP_SAVE_ACCR,
 
-       /*
-        * Low power modes require the HSIO2 clock to be enabled.
-        */
-       CKENB |= 1 << (CKEN_HSIO2 & 31);
+       SLEEP_SAVE_SIZE,
+};
+
+static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
+{
+       SAVE(CKENA);
+       SAVE(CKENB);
+       SAVE(ACCR);
 }
 
 static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save)
 {
-       CKENB &= ~(1 << (CKEN_HSIO2 & 31));
+       RESTORE(ACCR);
+       RESTORE(CKENA);
+       RESTORE(CKENB);
 }
 
 /*
        printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR);
 }
 
+/*
+ * NOTE:  currently, the OBM (OEM Boot Module) binary comes along with
+ * PXA3xx development kits assumes that the resuming process continues
+ * with the address stored within the first 4 bytes of SDRAM. The PSPR
+ * register is used privately by BootROM and OBM, and _must_ be set to
+ * 0x5c014000 for the moment.
+ */
+static void pxa3xx_cpu_pm_suspend(void)
+{
+       volatile unsigned long *p = (volatile void *)0xc0000000;
+       unsigned long saved_data = *p;
+
+       extern void pxa3xx_cpu_suspend(void);
+       extern void pxa3xx_cpu_resume(void);
+
+       /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
+       CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
+       CKENB |= 1 << (CKEN_HSIO2 & 0x1f);
+
+       /* clear and setup wakeup source */
+       AD3SR = ~0;
+       AD3ER = wakeup_src;
+       ASCR = ASCR;
+       ARSR = ARSR;
+
+       PCFR |= (1u << 13);                     /* L1_DIS */
+       PCFR &= ~((1u << 12) | (1u << 1));      /* L0_EN | SL_ROD */
+
+       PSPR = 0x5c014000;
+
+       /* overwrite with the resume address */
+       *p = virt_to_phys(pxa3xx_cpu_resume);
+
+       pxa3xx_cpu_suspend();
+
+       *p = saved_data;
+
+       AD3ER = 0;
+}
+
 static void pxa3xx_cpu_pm_enter(suspend_state_t state)
 {
        /*
                break;
 
        case PM_SUSPEND_MEM:
+               pxa3xx_cpu_pm_suspend();
                break;
        }
 }
 
        str     r0, [r1]
        ldr     pc, [sp], #4
 
+#ifdef CONFIG_PXA3xx
+/*
+ * pxa3xx_cpu_suspend() - forces CPU into sleep state (S2D3C4)
+ *
+ * NOTE:  unfortunately, pxa_cpu_save_cp can not be reused here since
+ * the auxiliary control register address is different between pxa3xx
+ * and pxa{25x,27x}
+ */
+
+ENTRY(pxa3xx_cpu_suspend)
+
+#ifndef CONFIG_IWMMXT
+       mra     r2, r3, acc0
+#endif
+       stmfd   sp!, {r2 - r12, lr}     @ save registers on stack
+
+       mrc     p14, 0, r3, c6, c0, 0           @ clock configuration, for turbo mode
+       mrc     p15, 0, r4, c15, c1, 0          @ CP access reg
+       mrc     p15, 0, r5, c13, c0, 0          @ PID
+       mrc     p15, 0, r6, c3, c0, 0           @ domain ID
+       mrc     p15, 0, r7, c2, c0, 0           @ translation table base addr
+       mrc     p15, 0, r8, c1, c0, 1           @ auxiliary control reg
+       mrc     p15, 0, r9, c1, c0, 0           @ control reg
+
+       bic     r3, r3, #2                      @ clear frequency change bit
+
+       @ store them plus current virtual stack ptr on stack
+       mov     r10, sp
+       stmfd   sp!, {r3 - r10}
+
+       @ store physical address of stack pointer
+       mov     r0, sp
+       bl      sleep_phys_sp
+       ldr     r1, =sleep_save_sp
+       str     r0, [r1]
+
+       @ clean data cache
+       bl      xsc3_flush_kern_cache_all
+
+       mov     r0, #0x06               @ S2D3C4 mode
+       mcr     p14, 0, r0, c7, c0, 0   @ enter sleep
+
+20:    b       20b                     @ waiting for sleep
+
+       .data
+       .align 5
+/*
+ * pxa3xx_cpu_resume
+ */
+
+ENTRY(pxa3xx_cpu_resume)
+
+       mov     r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE   @ set SVC, irqs off
+       msr     cpsr_c, r0
+
+       ldr     r0, sleep_save_sp               @ stack phys addr
+       ldmfd   r0, {r3 - r9, sp}               @ CP regs + virt stack ptr
+
+       mov     r1, #0
+       mcr     p15, 0, r1, c7, c7, 0           @ invalidate I & D caches, BTB
+       mcr     p15, 0, r1, c7, c10, 4          @ drain write (&fill) buffer
+       mcr     p15, 0, r1, c7, c5, 4           @ flush prefetch buffer
+       mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+
+       mcr     p14, 0, r3, c6, c0, 0           @ clock configuration, turbo mode.
+       mcr     p15, 0, r4, c15, c1, 0          @ CP access reg
+       mcr     p15, 0, r5, c13, c0, 0          @ PID
+       mcr     p15, 0, r6, c3, c0, 0           @ domain ID
+       mcr     p15, 0, r7, c2, c0, 0           @ translation table base addr
+       mcr     p15, 0, r8, c1, c0, 1           @ auxiliary control reg
+
+       @ temporarily map resume_turn_on_mmu into the page table,
+       @ otherwise prefetch abort occurs after MMU is turned on
+       mov     r1, r7
+       bic     r1, r1, #0x00ff
+       bic     r1, r1, #0x3f00
+       ldr     r2, =0x542e
+
+       adr     r3, resume_turn_on_mmu
+       mov     r3, r3, lsr #20
+       orr     r4, r2, r3, lsl #20
+       ldr     r5, [r1, r3, lsl #2]
+       str     r4, [r1, r3, lsl #2]
+
+       @ Mapping page table address in the page table
+       mov     r6, r1, lsr #20
+       orr     r7, r2, r6, lsl #20
+       ldr     r8, [r1, r6, lsl #2]
+       str     r7, [r1, r6, lsl #2]
+
+       ldr     r2, =pxa3xx_resume_after_mmu    @ absolute virtual address
+       b       resume_turn_on_mmu              @ cache align execution
+
+       .text
+pxa3xx_resume_after_mmu:
+       /* restore the temporary mapping */
+       str     r5, [r1, r3, lsl #2]
+       str     r8, [r1, r6, lsl #2]
+       b       resume_after_mmu
+
+#endif /* CONFIG_PXA3xx */
+
 #ifdef CONFIG_PXA27x
 /*
  * pxa27x_cpu_suspend()