This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / arm / mach-pnx4008 / pm.c
diff --git a/arch/arm/mach-pnx4008/pm.c b/arch/arm/mach-pnx4008/pm.c
new file mode 100644 (file)
index 0000000..3649cd3
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * arch/arm/mach-pnx4008/pm.c
+ *
+ * Power Management driver for PNX4008
+ *
+ * Authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/pm.h>
+#include <linux/rtc.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/cacheflush.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/clock.h>
+
+#define SRAM_VA IO_ADDRESS(PNX4008_IRAM_BASE)
+
+static void *saved_sram;
+
+static struct clk *pll4_clk;
+
+static inline void pnx4008_standby(void)
+{
+       void (*pnx4008_cpu_standby_ptr) (void);
+
+       local_irq_disable();
+       local_fiq_disable();
+
+       clk_disable(pll4_clk);
+
+       /*saving portion of SRAM to be used by suspend function. */
+       memcpy(saved_sram, (void *)SRAM_VA, pnx4008_cpu_standby_sz);
+
+       /*make sure SRAM copy gets physically written into SDRAM.
+          SDRAM will be placed into self-refresh during power down */
+       flush_cache_all();
+
+       /*copy suspend function into SRAM */
+       memcpy((void *)SRAM_VA, pnx4008_cpu_standby, pnx4008_cpu_standby_sz);
+
+       /*do suspend */
+       pnx4008_cpu_standby_ptr = (void *)SRAM_VA;
+       pnx4008_cpu_standby_ptr();
+
+       /*restoring portion of SRAM that was used by suspend function */
+       memcpy((void *)SRAM_VA, saved_sram, pnx4008_cpu_standby_sz);
+
+       clk_enable(pll4_clk);
+
+       local_fiq_enable();
+       local_irq_enable();
+}
+
+static inline void pnx4008_suspend(void)
+{
+       void (*pnx4008_cpu_suspend_ptr) (void);
+
+       local_irq_disable();
+       local_fiq_disable();
+
+       clk_disable(pll4_clk);
+
+       __raw_writel(0xffffffff, START_INT_RSR_REG(SE_PIN_BASE_INT));
+       __raw_writel(0xffffffff, START_INT_RSR_REG(SE_INT_BASE_INT));
+
+       /*saving portion of SRAM to be used by suspend function. */
+       memcpy(saved_sram, (void *)SRAM_VA, pnx4008_cpu_suspend_sz);
+
+       /*make sure SRAM copy gets physically written into SDRAM.
+          SDRAM will be placed into self-refresh during power down */
+       flush_cache_all();
+
+       /*copy suspend function into SRAM */
+       memcpy((void *)SRAM_VA, pnx4008_cpu_suspend, pnx4008_cpu_suspend_sz);
+
+       /*do suspend */
+       pnx4008_cpu_suspend_ptr = (void *)SRAM_VA;
+       pnx4008_cpu_suspend_ptr();
+
+       /*restoring portion of SRAM that was used by suspend function */
+       memcpy((void *)SRAM_VA, saved_sram, pnx4008_cpu_suspend_sz);
+
+       clk_enable(pll4_clk);
+
+       local_fiq_enable();
+       local_irq_enable();
+}
+
+static int pnx4008_pm_enter(suspend_state_t state)
+{
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+               pnx4008_standby();
+               break;
+       case PM_SUSPEND_MEM:
+               pnx4008_suspend();
+               break;
+       case PM_SUSPEND_DISK:
+               return -ENOTSUPP;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int pnx4008_pm_prepare(suspend_state_t state)
+{
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               break;
+
+       case PM_SUSPEND_DISK:
+               return -ENOTSUPP;
+               break;
+
+       default:
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static int pnx4008_pm_finish(suspend_state_t state)
+{
+       return 0;
+}
+
+/*
+ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
+ */
+static struct pm_ops pnx4008_pm_ops = {
+       .prepare = pnx4008_pm_prepare,
+       .enter = pnx4008_pm_enter,
+       .finish = pnx4008_pm_finish,
+};
+
+static int __init pnx4008_pm_init(void)
+{
+       u32 sram_size_to_allocate;
+
+       pll4_clk = clk_get(0, "ck_pll4");
+       if (IS_ERR(pll4_clk)) {
+               printk(KERN_ERR
+                      "PM Suspend cannot acquire ARM(PLL4) clock control\n");
+               return PTR_ERR(pll4_clk);
+       }
+
+       if (pnx4008_cpu_standby_sz > pnx4008_cpu_suspend_sz)
+               sram_size_to_allocate = pnx4008_cpu_standby_sz;
+       else
+               sram_size_to_allocate = pnx4008_cpu_suspend_sz;
+
+       saved_sram = kmalloc(sram_size_to_allocate, GFP_ATOMIC);
+       if (!saved_sram) {
+               printk(KERN_ERR
+                      "PM Suspend: cannot allocate memory to save portion of SRAM\n");
+               clk_put(pll4_clk);
+               return -ENOMEM;
+       }
+
+       pm_set_ops(&pnx4008_pm_ops);
+       return 0;
+}
+
+late_initcall(pnx4008_pm_init);