1 /* 2 * linux/arch/arm/mach-omap2/pm.c 3 * 4 * OMAP2 Power Management Routines 5 * 6 * Copyright (C) 2006 Nokia Corporation 7 * Tony Lindgren <tony@atomide.com> 8 * 9 * Copyright (C) 2005 Texas Instruments, Inc. 10 * Richard Woodruff <r-woodruff2@ti.com> 11 * 12 * Based on pm.c for omap1 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License version 2 as 16 * published by the Free Software Foundation. 17 */ 18 19 #include <linux/pm.h> 20 #include <linux/sched.h> 21 #include <linux/proc_fs.h> 22 #include <linux/pm.h> 23 #include <linux/interrupt.h> 24 #include <linux/sysfs.h> 25 #include <linux/module.h> 26 27 #include <asm/io.h> 28 #include <asm/irq.h> 29 #include <asm/atomic.h> 30 #include <asm/mach/time.h> 31 #include <asm/mach/irq.h> 32 #include <asm/mach-types.h> 33 34 #include <asm/arch/irqs.h> 35 #include <asm/arch/clock.h> 36 #include <asm/arch/sram.h> 37 #include <asm/arch/pm.h> 38 39 static struct clk *vclk; 40 static void (*omap2_sram_idle)(void); 41 static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev); 42 static void (*saved_idle)(void); 43 44 void omap2_pm_idle(void) 45 { 46 local_irq_disable(); 47 local_fiq_disable(); 48 if (need_resched()) { 49 local_fiq_enable(); 50 local_irq_enable(); 51 return; 52 } 53 54 /* 55 * Since an interrupt may set up a timer, we don't want to 56 * reprogram the hardware timer with interrupts enabled. 57 * Re-enable interrupts only after returning from idle. 58 */ 59 timer_dyn_reprogram(); 60 61 omap2_sram_idle(); 62 local_fiq_enable(); 63 local_irq_enable(); 64 } 65 66 static int omap2_pm_prepare(suspend_state_t state) 67 { 68 int error = 0; 69 70 /* We cannot sleep in idle until we have resumed */ 71 saved_idle = pm_idle; 72 pm_idle = NULL; 73 74 switch (state) 75 { 76 case PM_SUSPEND_STANDBY: 77 case PM_SUSPEND_MEM: 78 break; 79 80 case PM_SUSPEND_DISK: 81 return -ENOTSUPP; 82 83 default: 84 return -EINVAL; 85 } 86 87 return error; 88 } 89 90 static int omap2_pm_enter(suspend_state_t state) 91 { 92 switch (state) 93 { 94 case PM_SUSPEND_STANDBY: 95 case PM_SUSPEND_MEM: 96 /* FIXME: Add suspend */ 97 break; 98 99 case PM_SUSPEND_DISK: 100 return -ENOTSUPP; 101 102 default: 103 return -EINVAL; 104 } 105 106 return 0; 107 } 108 109 static int omap2_pm_finish(suspend_state_t state) 110 { 111 pm_idle = saved_idle; 112 return 0; 113 } 114 115 static struct pm_ops omap_pm_ops = { 116 .pm_disk_mode = 0, 117 .prepare = omap2_pm_prepare, 118 .enter = omap2_pm_enter, 119 .finish = omap2_pm_finish, 120 }; 121 122 int __init omap2_pm_init(void) 123 { 124 printk("Power Management for TI OMAP.\n"); 125 126 vclk = clk_get(NULL, "virt_prcm_set"); 127 if (IS_ERR(vclk)) { 128 printk(KERN_ERR "Could not get PM vclk\n"); 129 return -ENODEV; 130 } 131 132 /* 133 * We copy the assembler sleep/wakeup routines to SRAM. 134 * These routines need to be in SRAM as that's the only 135 * memory the MPU can see when it wakes up. 136 */ 137 omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, 138 omap24xx_idle_loop_suspend_sz); 139 140 omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, 141 omap24xx_cpu_suspend_sz); 142 143 pm_set_ops(&omap_pm_ops); 144 pm_idle = omap2_pm_idle; 145 146 return 0; 147 } 148 149 __initcall(omap2_pm_init); 150