18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/arch/arm/mach-omap1/pm.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * OMAP Power Management Routines 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Original code for the SA11x0: 78c2ecf20Sopenharmony_ci * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Modified for the PXA250 by Nicolas Pitre: 108c2ecf20Sopenharmony_ci * Copyright (c) 2002 Monta Vista Software, Inc. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Modified for the OMAP1510 by David Singleton: 138c2ecf20Sopenharmony_ci * Copyright (c) 2002 Monta Vista Software, Inc. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 188c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License as published by the 198c2ecf20Sopenharmony_ci * Free Software Foundation; either version 2 of the License, or (at your 208c2ecf20Sopenharmony_ci * option) any later version. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 238c2ecf20Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 248c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 258c2ecf20Sopenharmony_ci * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 268c2ecf20Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 278c2ecf20Sopenharmony_ci * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 288c2ecf20Sopenharmony_ci * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 298c2ecf20Sopenharmony_ci * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 308c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 318c2ecf20Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License along 348c2ecf20Sopenharmony_ci * with this program; if not, write to the Free Software Foundation, Inc., 358c2ecf20Sopenharmony_ci * 675 Mass Ave, Cambridge, MA 02139, USA. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <linux/suspend.h> 398c2ecf20Sopenharmony_ci#include <linux/sched.h> 408c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 418c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 428c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 438c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 448c2ecf20Sopenharmony_ci#include <linux/module.h> 458c2ecf20Sopenharmony_ci#include <linux/io.h> 468c2ecf20Sopenharmony_ci#include <linux/atomic.h> 478c2ecf20Sopenharmony_ci#include <linux/cpu.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <asm/fncpy.h> 508c2ecf20Sopenharmony_ci#include <asm/system_misc.h> 518c2ecf20Sopenharmony_ci#include <asm/irq.h> 528c2ecf20Sopenharmony_ci#include <asm/mach/time.h> 538c2ecf20Sopenharmony_ci#include <asm/mach/irq.h> 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#include <mach/tc.h> 568c2ecf20Sopenharmony_ci#include <mach/mux.h> 578c2ecf20Sopenharmony_ci#include <linux/omap-dma.h> 588c2ecf20Sopenharmony_ci#include <clocksource/timer-ti-dm.h> 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#include <mach/irqs.h> 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#include "iomap.h" 638c2ecf20Sopenharmony_ci#include "clock.h" 648c2ecf20Sopenharmony_ci#include "pm.h" 658c2ecf20Sopenharmony_ci#include "soc.h" 668c2ecf20Sopenharmony_ci#include "sram.h" 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE]; 698c2ecf20Sopenharmony_cistatic unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE]; 708c2ecf20Sopenharmony_cistatic unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE]; 718c2ecf20Sopenharmony_cistatic unsigned int mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_SIZE]; 728c2ecf20Sopenharmony_cistatic unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE]; 738c2ecf20Sopenharmony_cistatic unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic unsigned short enable_dyn_sleep; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr, 788c2ecf20Sopenharmony_ci char *buf) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci return sprintf(buf, "%hu\n", enable_dyn_sleep); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr, 848c2ecf20Sopenharmony_ci const char * buf, size_t n) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci unsigned short value; 878c2ecf20Sopenharmony_ci if (sscanf(buf, "%hu", &value) != 1 || 888c2ecf20Sopenharmony_ci (value != 0 && value != 1) || 898c2ecf20Sopenharmony_ci (value != 0 && !IS_ENABLED(CONFIG_OMAP_32K_TIMER))) { 908c2ecf20Sopenharmony_ci pr_err("idle_sleep_store: Invalid value\n"); 918c2ecf20Sopenharmony_ci return -EINVAL; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci enable_dyn_sleep = value; 948c2ecf20Sopenharmony_ci return n; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic struct kobj_attribute sleep_while_idle_attr = 988c2ecf20Sopenharmony_ci __ATTR(sleep_while_idle, 0644, idle_show, idle_store); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * Let's power down on idle, but only if we are really 1058c2ecf20Sopenharmony_ci * idle, because once we start down the path of 1068c2ecf20Sopenharmony_ci * going idle we continue to do idle even if we get 1078c2ecf20Sopenharmony_ci * a clock tick interrupt . . 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_civoid omap1_pm_idle(void) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci extern __u32 arm_idlect1_mask; 1128c2ecf20Sopenharmony_ci __u32 use_idlect1 = arm_idlect1_mask; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci local_fiq_disable(); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#if defined(CONFIG_OMAP_MPU_TIMER) && !defined(CONFIG_OMAP_DM_TIMER) 1178c2ecf20Sopenharmony_ci use_idlect1 = use_idlect1 & ~(1 << 9); 1188c2ecf20Sopenharmony_ci#endif 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci#ifdef CONFIG_OMAP_DM_TIMER 1218c2ecf20Sopenharmony_ci use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1); 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (omap_dma_running()) 1258c2ecf20Sopenharmony_ci use_idlect1 &= ~(1 << 6); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * We should be able to remove the do_sleep variable and multiple 1298c2ecf20Sopenharmony_ci * tests above as soon as drivers, timer and DMA code have been fixed. 1308c2ecf20Sopenharmony_ci * Even the sleep block count should become obsolete. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci if ((use_idlect1 != ~0) || !enable_dyn_sleep) { 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci __u32 saved_idlect1 = omap_readl(ARM_IDLECT1); 1358c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) 1368c2ecf20Sopenharmony_ci use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST; 1378c2ecf20Sopenharmony_ci else 1388c2ecf20Sopenharmony_ci use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL; 1398c2ecf20Sopenharmony_ci omap_writel(use_idlect1, ARM_IDLECT1); 1408c2ecf20Sopenharmony_ci __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4"); 1418c2ecf20Sopenharmony_ci omap_writel(saved_idlect1, ARM_IDLECT1); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci local_fiq_enable(); 1448c2ecf20Sopenharmony_ci return; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci omap_sram_suspend(omap_readl(ARM_IDLECT1), 1478c2ecf20Sopenharmony_ci omap_readl(ARM_IDLECT2)); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci local_fiq_enable(); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * Configuration of the wakeup event is board specific. For the 1548c2ecf20Sopenharmony_ci * moment we put it into this helper function. Later it may move 1558c2ecf20Sopenharmony_ci * to board specific files. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistatic void omap_pm_wakeup_setup(void) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci u32 level1_wake = 0; 1608c2ecf20Sopenharmony_ci u32 level2_wake = OMAP_IRQ_BIT(INT_UART2); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* 1638c2ecf20Sopenharmony_ci * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade, 1648c2ecf20Sopenharmony_ci * and the L2 wakeup interrupts: keypad and UART2. Note that the 1658c2ecf20Sopenharmony_ci * drivers must still separately call omap_set_gpio_wakeup() to 1668c2ecf20Sopenharmony_ci * wake up to a GPIO interrupt. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_ci if (cpu_is_omap7xx()) 1698c2ecf20Sopenharmony_ci level1_wake = OMAP_IRQ_BIT(INT_7XX_GPIO_BANK1) | 1708c2ecf20Sopenharmony_ci OMAP_IRQ_BIT(INT_7XX_IH2_IRQ); 1718c2ecf20Sopenharmony_ci else if (cpu_is_omap15xx()) 1728c2ecf20Sopenharmony_ci level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | 1738c2ecf20Sopenharmony_ci OMAP_IRQ_BIT(INT_1510_IH2_IRQ); 1748c2ecf20Sopenharmony_ci else if (cpu_is_omap16xx()) 1758c2ecf20Sopenharmony_ci level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | 1768c2ecf20Sopenharmony_ci OMAP_IRQ_BIT(INT_1610_IH2_IRQ); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci omap_writel(~level1_wake, OMAP_IH1_MIR); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (cpu_is_omap7xx()) { 1818c2ecf20Sopenharmony_ci omap_writel(~level2_wake, OMAP_IH2_0_MIR); 1828c2ecf20Sopenharmony_ci omap_writel(~(OMAP_IRQ_BIT(INT_7XX_WAKE_UP_REQ) | 1838c2ecf20Sopenharmony_ci OMAP_IRQ_BIT(INT_7XX_MPUIO_KEYPAD)), 1848c2ecf20Sopenharmony_ci OMAP_IH2_1_MIR); 1858c2ecf20Sopenharmony_ci } else if (cpu_is_omap15xx()) { 1868c2ecf20Sopenharmony_ci level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); 1878c2ecf20Sopenharmony_ci omap_writel(~level2_wake, OMAP_IH2_MIR); 1888c2ecf20Sopenharmony_ci } else if (cpu_is_omap16xx()) { 1898c2ecf20Sopenharmony_ci level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); 1908c2ecf20Sopenharmony_ci omap_writel(~level2_wake, OMAP_IH2_0_MIR); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */ 1938c2ecf20Sopenharmony_ci omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), 1948c2ecf20Sopenharmony_ci OMAP_IH2_1_MIR); 1958c2ecf20Sopenharmony_ci omap_writel(~0x0, OMAP_IH2_2_MIR); 1968c2ecf20Sopenharmony_ci omap_writel(~0x0, OMAP_IH2_3_MIR); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* New IRQ agreement, recalculate in cascade order */ 2008c2ecf20Sopenharmony_ci omap_writel(1, OMAP_IH2_CONTROL); 2018c2ecf20Sopenharmony_ci omap_writel(1, OMAP_IH1_CONTROL); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#define EN_DSPCK 13 /* ARM_CKCTL */ 2058c2ecf20Sopenharmony_ci#define EN_APICK 6 /* ARM_IDLECT2 */ 2068c2ecf20Sopenharmony_ci#define DSP_EN 1 /* ARM_RSTCT1 */ 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_civoid omap1_pm_suspend(void) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci unsigned long arg0 = 0, arg1 = 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci printk(KERN_INFO "PM: OMAP%x is trying to enter deep sleep...\n", 2138c2ecf20Sopenharmony_ci omap_rev()); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci omap_serial_wake_trigger(1); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (!cpu_is_omap15xx()) 2188c2ecf20Sopenharmony_ci omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * Step 1: turn off interrupts (FIXME: NOTE: already disabled) 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci local_irq_disable(); 2258c2ecf20Sopenharmony_ci local_fiq_disable(); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * Step 2: save registers 2298c2ecf20Sopenharmony_ci * 2308c2ecf20Sopenharmony_ci * The omap is a strange/beautiful device. The caches, memory 2318c2ecf20Sopenharmony_ci * and register state are preserved across power saves. 2328c2ecf20Sopenharmony_ci * We have to save and restore very little register state to 2338c2ecf20Sopenharmony_ci * idle the omap. 2348c2ecf20Sopenharmony_ci * 2358c2ecf20Sopenharmony_ci * Save interrupt, MPUI, ARM and UPLD control registers. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (cpu_is_omap7xx()) { 2398c2ecf20Sopenharmony_ci MPUI7XX_SAVE(OMAP_IH1_MIR); 2408c2ecf20Sopenharmony_ci MPUI7XX_SAVE(OMAP_IH2_0_MIR); 2418c2ecf20Sopenharmony_ci MPUI7XX_SAVE(OMAP_IH2_1_MIR); 2428c2ecf20Sopenharmony_ci MPUI7XX_SAVE(MPUI_CTRL); 2438c2ecf20Sopenharmony_ci MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG); 2448c2ecf20Sopenharmony_ci MPUI7XX_SAVE(MPUI_DSP_API_CONFIG); 2458c2ecf20Sopenharmony_ci MPUI7XX_SAVE(EMIFS_CONFIG); 2468c2ecf20Sopenharmony_ci MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci } else if (cpu_is_omap15xx()) { 2498c2ecf20Sopenharmony_ci MPUI1510_SAVE(OMAP_IH1_MIR); 2508c2ecf20Sopenharmony_ci MPUI1510_SAVE(OMAP_IH2_MIR); 2518c2ecf20Sopenharmony_ci MPUI1510_SAVE(MPUI_CTRL); 2528c2ecf20Sopenharmony_ci MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); 2538c2ecf20Sopenharmony_ci MPUI1510_SAVE(MPUI_DSP_API_CONFIG); 2548c2ecf20Sopenharmony_ci MPUI1510_SAVE(EMIFS_CONFIG); 2558c2ecf20Sopenharmony_ci MPUI1510_SAVE(EMIFF_SDRAM_CONFIG); 2568c2ecf20Sopenharmony_ci } else if (cpu_is_omap16xx()) { 2578c2ecf20Sopenharmony_ci MPUI1610_SAVE(OMAP_IH1_MIR); 2588c2ecf20Sopenharmony_ci MPUI1610_SAVE(OMAP_IH2_0_MIR); 2598c2ecf20Sopenharmony_ci MPUI1610_SAVE(OMAP_IH2_1_MIR); 2608c2ecf20Sopenharmony_ci MPUI1610_SAVE(OMAP_IH2_2_MIR); 2618c2ecf20Sopenharmony_ci MPUI1610_SAVE(OMAP_IH2_3_MIR); 2628c2ecf20Sopenharmony_ci MPUI1610_SAVE(MPUI_CTRL); 2638c2ecf20Sopenharmony_ci MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG); 2648c2ecf20Sopenharmony_ci MPUI1610_SAVE(MPUI_DSP_API_CONFIG); 2658c2ecf20Sopenharmony_ci MPUI1610_SAVE(EMIFS_CONFIG); 2668c2ecf20Sopenharmony_ci MPUI1610_SAVE(EMIFF_SDRAM_CONFIG); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ARM_SAVE(ARM_CKCTL); 2708c2ecf20Sopenharmony_ci ARM_SAVE(ARM_IDLECT1); 2718c2ecf20Sopenharmony_ci ARM_SAVE(ARM_IDLECT2); 2728c2ecf20Sopenharmony_ci if (!(cpu_is_omap15xx())) 2738c2ecf20Sopenharmony_ci ARM_SAVE(ARM_IDLECT3); 2748c2ecf20Sopenharmony_ci ARM_SAVE(ARM_EWUPCT); 2758c2ecf20Sopenharmony_ci ARM_SAVE(ARM_RSTCT1); 2768c2ecf20Sopenharmony_ci ARM_SAVE(ARM_RSTCT2); 2778c2ecf20Sopenharmony_ci ARM_SAVE(ARM_SYSST); 2788c2ecf20Sopenharmony_ci ULPD_SAVE(ULPD_CLOCK_CTRL); 2798c2ecf20Sopenharmony_ci ULPD_SAVE(ULPD_STATUS_REQ); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* (Step 3 removed - we now allow deep sleep by default) */ 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* 2848c2ecf20Sopenharmony_ci * Step 4: OMAP DSP Shutdown 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* stop DSP */ 2888c2ecf20Sopenharmony_ci omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* shut down dsp_ck */ 2918c2ecf20Sopenharmony_ci if (!cpu_is_omap7xx()) 2928c2ecf20Sopenharmony_ci omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* temporarily enabling api_ck to access DSP registers */ 2958c2ecf20Sopenharmony_ci omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* save DSP registers */ 2988c2ecf20Sopenharmony_ci DSP_SAVE(DSP_IDLECT2); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Stop all DSP domain clocks */ 3018c2ecf20Sopenharmony_ci __raw_writew(0, DSP_IDLECT2); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * Step 5: Wakeup Event Setup 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci omap_pm_wakeup_setup(); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* 3108c2ecf20Sopenharmony_ci * Step 6: ARM and Traffic controller shutdown 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* disable ARM watchdog */ 3148c2ecf20Sopenharmony_ci omap_writel(0x00F5, OMAP_WDT_TIMER_MODE); 3158c2ecf20Sopenharmony_ci omap_writel(0x00A0, OMAP_WDT_TIMER_MODE); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* 3188c2ecf20Sopenharmony_ci * Step 6b: ARM and Traffic controller shutdown 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * Step 6 continues here. Prepare jump to power management 3218c2ecf20Sopenharmony_ci * assembly code in internal SRAM. 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * Since the omap_cpu_suspend routine has been copied to 3248c2ecf20Sopenharmony_ci * SRAM, we'll do an indirect procedure call to it and pass the 3258c2ecf20Sopenharmony_ci * contents of arm_idlect1 and arm_idlect2 so it can restore 3268c2ecf20Sopenharmony_ci * them when it wakes up and it will return. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1]; 3308c2ecf20Sopenharmony_ci arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2]; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * Step 6c: ARM and Traffic controller shutdown 3348c2ecf20Sopenharmony_ci * 3358c2ecf20Sopenharmony_ci * Jump to assembly code. The processor will stay there 3368c2ecf20Sopenharmony_ci * until wake up. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci omap_sram_suspend(arg0, arg1); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* 3418c2ecf20Sopenharmony_ci * If we are here, processor is woken up! 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* 3458c2ecf20Sopenharmony_ci * Restore DSP clocks 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* again temporarily enabling api_ck to access DSP registers */ 3498c2ecf20Sopenharmony_ci omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* Restore DSP domain clocks */ 3528c2ecf20Sopenharmony_ci DSP_RESTORE(DSP_IDLECT2); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (!(cpu_is_omap15xx())) 3598c2ecf20Sopenharmony_ci ARM_RESTORE(ARM_IDLECT3); 3608c2ecf20Sopenharmony_ci ARM_RESTORE(ARM_CKCTL); 3618c2ecf20Sopenharmony_ci ARM_RESTORE(ARM_EWUPCT); 3628c2ecf20Sopenharmony_ci ARM_RESTORE(ARM_RSTCT1); 3638c2ecf20Sopenharmony_ci ARM_RESTORE(ARM_RSTCT2); 3648c2ecf20Sopenharmony_ci ARM_RESTORE(ARM_SYSST); 3658c2ecf20Sopenharmony_ci ULPD_RESTORE(ULPD_CLOCK_CTRL); 3668c2ecf20Sopenharmony_ci ULPD_RESTORE(ULPD_STATUS_REQ); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (cpu_is_omap7xx()) { 3698c2ecf20Sopenharmony_ci MPUI7XX_RESTORE(EMIFS_CONFIG); 3708c2ecf20Sopenharmony_ci MPUI7XX_RESTORE(EMIFF_SDRAM_CONFIG); 3718c2ecf20Sopenharmony_ci MPUI7XX_RESTORE(OMAP_IH1_MIR); 3728c2ecf20Sopenharmony_ci MPUI7XX_RESTORE(OMAP_IH2_0_MIR); 3738c2ecf20Sopenharmony_ci MPUI7XX_RESTORE(OMAP_IH2_1_MIR); 3748c2ecf20Sopenharmony_ci } else if (cpu_is_omap15xx()) { 3758c2ecf20Sopenharmony_ci MPUI1510_RESTORE(MPUI_CTRL); 3768c2ecf20Sopenharmony_ci MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG); 3778c2ecf20Sopenharmony_ci MPUI1510_RESTORE(MPUI_DSP_API_CONFIG); 3788c2ecf20Sopenharmony_ci MPUI1510_RESTORE(EMIFS_CONFIG); 3798c2ecf20Sopenharmony_ci MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG); 3808c2ecf20Sopenharmony_ci MPUI1510_RESTORE(OMAP_IH1_MIR); 3818c2ecf20Sopenharmony_ci MPUI1510_RESTORE(OMAP_IH2_MIR); 3828c2ecf20Sopenharmony_ci } else if (cpu_is_omap16xx()) { 3838c2ecf20Sopenharmony_ci MPUI1610_RESTORE(MPUI_CTRL); 3848c2ecf20Sopenharmony_ci MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG); 3858c2ecf20Sopenharmony_ci MPUI1610_RESTORE(MPUI_DSP_API_CONFIG); 3868c2ecf20Sopenharmony_ci MPUI1610_RESTORE(EMIFS_CONFIG); 3878c2ecf20Sopenharmony_ci MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci MPUI1610_RESTORE(OMAP_IH1_MIR); 3908c2ecf20Sopenharmony_ci MPUI1610_RESTORE(OMAP_IH2_0_MIR); 3918c2ecf20Sopenharmony_ci MPUI1610_RESTORE(OMAP_IH2_1_MIR); 3928c2ecf20Sopenharmony_ci MPUI1610_RESTORE(OMAP_IH2_2_MIR); 3938c2ecf20Sopenharmony_ci MPUI1610_RESTORE(OMAP_IH2_3_MIR); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (!cpu_is_omap15xx()) 3978c2ecf20Sopenharmony_ci omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* 4008c2ecf20Sopenharmony_ci * Re-enable interrupts 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci local_irq_enable(); 4048c2ecf20Sopenharmony_ci local_fiq_enable(); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci omap_serial_wake_trigger(0); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci printk(KERN_INFO "PM: OMAP%x is re-starting from deep sleep...\n", 4098c2ecf20Sopenharmony_ci omap_rev()); 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 4138c2ecf20Sopenharmony_ci/* 4148c2ecf20Sopenharmony_ci * Read system PM registers for debugging 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_cistatic int omap_pm_debug_show(struct seq_file *m, void *v) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci ARM_SAVE(ARM_CKCTL); 4198c2ecf20Sopenharmony_ci ARM_SAVE(ARM_IDLECT1); 4208c2ecf20Sopenharmony_ci ARM_SAVE(ARM_IDLECT2); 4218c2ecf20Sopenharmony_ci if (!(cpu_is_omap15xx())) 4228c2ecf20Sopenharmony_ci ARM_SAVE(ARM_IDLECT3); 4238c2ecf20Sopenharmony_ci ARM_SAVE(ARM_EWUPCT); 4248c2ecf20Sopenharmony_ci ARM_SAVE(ARM_RSTCT1); 4258c2ecf20Sopenharmony_ci ARM_SAVE(ARM_RSTCT2); 4268c2ecf20Sopenharmony_ci ARM_SAVE(ARM_SYSST); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci ULPD_SAVE(ULPD_IT_STATUS); 4298c2ecf20Sopenharmony_ci ULPD_SAVE(ULPD_CLOCK_CTRL); 4308c2ecf20Sopenharmony_ci ULPD_SAVE(ULPD_SOFT_REQ); 4318c2ecf20Sopenharmony_ci ULPD_SAVE(ULPD_STATUS_REQ); 4328c2ecf20Sopenharmony_ci ULPD_SAVE(ULPD_DPLL_CTRL); 4338c2ecf20Sopenharmony_ci ULPD_SAVE(ULPD_POWER_CTRL); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (cpu_is_omap7xx()) { 4368c2ecf20Sopenharmony_ci MPUI7XX_SAVE(MPUI_CTRL); 4378c2ecf20Sopenharmony_ci MPUI7XX_SAVE(MPUI_DSP_STATUS); 4388c2ecf20Sopenharmony_ci MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG); 4398c2ecf20Sopenharmony_ci MPUI7XX_SAVE(MPUI_DSP_API_CONFIG); 4408c2ecf20Sopenharmony_ci MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG); 4418c2ecf20Sopenharmony_ci MPUI7XX_SAVE(EMIFS_CONFIG); 4428c2ecf20Sopenharmony_ci } else if (cpu_is_omap15xx()) { 4438c2ecf20Sopenharmony_ci MPUI1510_SAVE(MPUI_CTRL); 4448c2ecf20Sopenharmony_ci MPUI1510_SAVE(MPUI_DSP_STATUS); 4458c2ecf20Sopenharmony_ci MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); 4468c2ecf20Sopenharmony_ci MPUI1510_SAVE(MPUI_DSP_API_CONFIG); 4478c2ecf20Sopenharmony_ci MPUI1510_SAVE(EMIFF_SDRAM_CONFIG); 4488c2ecf20Sopenharmony_ci MPUI1510_SAVE(EMIFS_CONFIG); 4498c2ecf20Sopenharmony_ci } else if (cpu_is_omap16xx()) { 4508c2ecf20Sopenharmony_ci MPUI1610_SAVE(MPUI_CTRL); 4518c2ecf20Sopenharmony_ci MPUI1610_SAVE(MPUI_DSP_STATUS); 4528c2ecf20Sopenharmony_ci MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG); 4538c2ecf20Sopenharmony_ci MPUI1610_SAVE(MPUI_DSP_API_CONFIG); 4548c2ecf20Sopenharmony_ci MPUI1610_SAVE(EMIFF_SDRAM_CONFIG); 4558c2ecf20Sopenharmony_ci MPUI1610_SAVE(EMIFS_CONFIG); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci seq_printf(m, 4598c2ecf20Sopenharmony_ci "ARM_CKCTL_REG: 0x%-8x \n" 4608c2ecf20Sopenharmony_ci "ARM_IDLECT1_REG: 0x%-8x \n" 4618c2ecf20Sopenharmony_ci "ARM_IDLECT2_REG: 0x%-8x \n" 4628c2ecf20Sopenharmony_ci "ARM_IDLECT3_REG: 0x%-8x \n" 4638c2ecf20Sopenharmony_ci "ARM_EWUPCT_REG: 0x%-8x \n" 4648c2ecf20Sopenharmony_ci "ARM_RSTCT1_REG: 0x%-8x \n" 4658c2ecf20Sopenharmony_ci "ARM_RSTCT2_REG: 0x%-8x \n" 4668c2ecf20Sopenharmony_ci "ARM_SYSST_REG: 0x%-8x \n" 4678c2ecf20Sopenharmony_ci "ULPD_IT_STATUS_REG: 0x%-4x \n" 4688c2ecf20Sopenharmony_ci "ULPD_CLOCK_CTRL_REG: 0x%-4x \n" 4698c2ecf20Sopenharmony_ci "ULPD_SOFT_REQ_REG: 0x%-4x \n" 4708c2ecf20Sopenharmony_ci "ULPD_DPLL_CTRL_REG: 0x%-4x \n" 4718c2ecf20Sopenharmony_ci "ULPD_STATUS_REQ_REG: 0x%-4x \n" 4728c2ecf20Sopenharmony_ci "ULPD_POWER_CTRL_REG: 0x%-4x \n", 4738c2ecf20Sopenharmony_ci ARM_SHOW(ARM_CKCTL), 4748c2ecf20Sopenharmony_ci ARM_SHOW(ARM_IDLECT1), 4758c2ecf20Sopenharmony_ci ARM_SHOW(ARM_IDLECT2), 4768c2ecf20Sopenharmony_ci ARM_SHOW(ARM_IDLECT3), 4778c2ecf20Sopenharmony_ci ARM_SHOW(ARM_EWUPCT), 4788c2ecf20Sopenharmony_ci ARM_SHOW(ARM_RSTCT1), 4798c2ecf20Sopenharmony_ci ARM_SHOW(ARM_RSTCT2), 4808c2ecf20Sopenharmony_ci ARM_SHOW(ARM_SYSST), 4818c2ecf20Sopenharmony_ci ULPD_SHOW(ULPD_IT_STATUS), 4828c2ecf20Sopenharmony_ci ULPD_SHOW(ULPD_CLOCK_CTRL), 4838c2ecf20Sopenharmony_ci ULPD_SHOW(ULPD_SOFT_REQ), 4848c2ecf20Sopenharmony_ci ULPD_SHOW(ULPD_DPLL_CTRL), 4858c2ecf20Sopenharmony_ci ULPD_SHOW(ULPD_STATUS_REQ), 4868c2ecf20Sopenharmony_ci ULPD_SHOW(ULPD_POWER_CTRL)); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (cpu_is_omap7xx()) { 4898c2ecf20Sopenharmony_ci seq_printf(m, 4908c2ecf20Sopenharmony_ci "MPUI7XX_CTRL_REG 0x%-8x \n" 4918c2ecf20Sopenharmony_ci "MPUI7XX_DSP_STATUS_REG: 0x%-8x \n" 4928c2ecf20Sopenharmony_ci "MPUI7XX_DSP_BOOT_CONFIG_REG: 0x%-8x \n" 4938c2ecf20Sopenharmony_ci "MPUI7XX_DSP_API_CONFIG_REG: 0x%-8x \n" 4948c2ecf20Sopenharmony_ci "MPUI7XX_SDRAM_CONFIG_REG: 0x%-8x \n" 4958c2ecf20Sopenharmony_ci "MPUI7XX_EMIFS_CONFIG_REG: 0x%-8x \n", 4968c2ecf20Sopenharmony_ci MPUI7XX_SHOW(MPUI_CTRL), 4978c2ecf20Sopenharmony_ci MPUI7XX_SHOW(MPUI_DSP_STATUS), 4988c2ecf20Sopenharmony_ci MPUI7XX_SHOW(MPUI_DSP_BOOT_CONFIG), 4998c2ecf20Sopenharmony_ci MPUI7XX_SHOW(MPUI_DSP_API_CONFIG), 5008c2ecf20Sopenharmony_ci MPUI7XX_SHOW(EMIFF_SDRAM_CONFIG), 5018c2ecf20Sopenharmony_ci MPUI7XX_SHOW(EMIFS_CONFIG)); 5028c2ecf20Sopenharmony_ci } else if (cpu_is_omap15xx()) { 5038c2ecf20Sopenharmony_ci seq_printf(m, 5048c2ecf20Sopenharmony_ci "MPUI1510_CTRL_REG 0x%-8x \n" 5058c2ecf20Sopenharmony_ci "MPUI1510_DSP_STATUS_REG: 0x%-8x \n" 5068c2ecf20Sopenharmony_ci "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n" 5078c2ecf20Sopenharmony_ci "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n" 5088c2ecf20Sopenharmony_ci "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n" 5098c2ecf20Sopenharmony_ci "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n", 5108c2ecf20Sopenharmony_ci MPUI1510_SHOW(MPUI_CTRL), 5118c2ecf20Sopenharmony_ci MPUI1510_SHOW(MPUI_DSP_STATUS), 5128c2ecf20Sopenharmony_ci MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG), 5138c2ecf20Sopenharmony_ci MPUI1510_SHOW(MPUI_DSP_API_CONFIG), 5148c2ecf20Sopenharmony_ci MPUI1510_SHOW(EMIFF_SDRAM_CONFIG), 5158c2ecf20Sopenharmony_ci MPUI1510_SHOW(EMIFS_CONFIG)); 5168c2ecf20Sopenharmony_ci } else if (cpu_is_omap16xx()) { 5178c2ecf20Sopenharmony_ci seq_printf(m, 5188c2ecf20Sopenharmony_ci "MPUI1610_CTRL_REG 0x%-8x \n" 5198c2ecf20Sopenharmony_ci "MPUI1610_DSP_STATUS_REG: 0x%-8x \n" 5208c2ecf20Sopenharmony_ci "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n" 5218c2ecf20Sopenharmony_ci "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n" 5228c2ecf20Sopenharmony_ci "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n" 5238c2ecf20Sopenharmony_ci "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n", 5248c2ecf20Sopenharmony_ci MPUI1610_SHOW(MPUI_CTRL), 5258c2ecf20Sopenharmony_ci MPUI1610_SHOW(MPUI_DSP_STATUS), 5268c2ecf20Sopenharmony_ci MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG), 5278c2ecf20Sopenharmony_ci MPUI1610_SHOW(MPUI_DSP_API_CONFIG), 5288c2ecf20Sopenharmony_ci MPUI1610_SHOW(EMIFF_SDRAM_CONFIG), 5298c2ecf20Sopenharmony_ci MPUI1610_SHOW(EMIFS_CONFIG)); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return 0; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(omap_pm_debug); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void omap_pm_init_debugfs(void) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct dentry *d; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci d = debugfs_create_dir("pm_debug", NULL); 5428c2ecf20Sopenharmony_ci debugfs_create_file("omap_pm", S_IWUSR | S_IRUGO, d, NULL, 5438c2ecf20Sopenharmony_ci &omap_pm_debug_fops); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/* 5498c2ecf20Sopenharmony_ci * omap_pm_prepare - Do preliminary suspend work. 5508c2ecf20Sopenharmony_ci * 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_cistatic int omap_pm_prepare(void) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci /* We cannot sleep in idle until we have resumed */ 5558c2ecf20Sopenharmony_ci cpu_idle_poll_ctrl(true); 5568c2ecf20Sopenharmony_ci return 0; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci/* 5618c2ecf20Sopenharmony_ci * omap_pm_enter - Actually enter a sleep state. 5628c2ecf20Sopenharmony_ci * @state: State we're entering. 5638c2ecf20Sopenharmony_ci * 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int omap_pm_enter(suspend_state_t state) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci switch (state) 5698c2ecf20Sopenharmony_ci { 5708c2ecf20Sopenharmony_ci case PM_SUSPEND_MEM: 5718c2ecf20Sopenharmony_ci omap1_pm_suspend(); 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci default: 5748c2ecf20Sopenharmony_ci return -EINVAL; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return 0; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci/** 5828c2ecf20Sopenharmony_ci * omap_pm_finish - Finish up suspend sequence. 5838c2ecf20Sopenharmony_ci * 5848c2ecf20Sopenharmony_ci * This is called after we wake back up (or if entering the sleep state 5858c2ecf20Sopenharmony_ci * failed). 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic void omap_pm_finish(void) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci cpu_idle_poll_ctrl(false); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic irqreturn_t omap_wakeup_interrupt(int irq, void *dev) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic const struct platform_suspend_ops omap_pm_ops = { 6028c2ecf20Sopenharmony_ci .prepare = omap_pm_prepare, 6038c2ecf20Sopenharmony_ci .enter = omap_pm_enter, 6048c2ecf20Sopenharmony_ci .finish = omap_pm_finish, 6058c2ecf20Sopenharmony_ci .valid = suspend_valid_only_mem, 6068c2ecf20Sopenharmony_ci}; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic int __init omap_pm_init(void) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci int error = 0; 6118c2ecf20Sopenharmony_ci int irq; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (!cpu_class_is_omap1()) 6148c2ecf20Sopenharmony_ci return -ENODEV; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci pr_info("Power Management for TI OMAP.\n"); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_OMAP_32K_TIMER)) 6198c2ecf20Sopenharmony_ci pr_info("OMAP1 PM: sleep states in idle disabled due to no 32KiHz timer\n"); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_OMAP_DM_TIMER)) 6228c2ecf20Sopenharmony_ci pr_info("OMAP1 PM: sleep states in idle disabled due to no DMTIMER support\n"); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_OMAP_32K_TIMER) && 6258c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_OMAP_DM_TIMER)) { 6268c2ecf20Sopenharmony_ci /* OMAP16xx only */ 6278c2ecf20Sopenharmony_ci pr_info("OMAP1 PM: sleep states in idle enabled\n"); 6288c2ecf20Sopenharmony_ci enable_dyn_sleep = 1; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* 6328c2ecf20Sopenharmony_ci * We copy the assembler sleep/wakeup routines to SRAM. 6338c2ecf20Sopenharmony_ci * These routines need to be in SRAM as that's the only 6348c2ecf20Sopenharmony_ci * memory the MPU can see when it wakes up. 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci if (cpu_is_omap7xx()) { 6378c2ecf20Sopenharmony_ci omap_sram_suspend = omap_sram_push(omap7xx_cpu_suspend, 6388c2ecf20Sopenharmony_ci omap7xx_cpu_suspend_sz); 6398c2ecf20Sopenharmony_ci } else if (cpu_is_omap15xx()) { 6408c2ecf20Sopenharmony_ci omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend, 6418c2ecf20Sopenharmony_ci omap1510_cpu_suspend_sz); 6428c2ecf20Sopenharmony_ci } else if (cpu_is_omap16xx()) { 6438c2ecf20Sopenharmony_ci omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend, 6448c2ecf20Sopenharmony_ci omap1610_cpu_suspend_sz); 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (omap_sram_suspend == NULL) { 6488c2ecf20Sopenharmony_ci printk(KERN_ERR "PM not initialized: Missing SRAM support\n"); 6498c2ecf20Sopenharmony_ci return -ENODEV; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci arm_pm_idle = omap1_pm_idle; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (cpu_is_omap7xx()) 6558c2ecf20Sopenharmony_ci irq = INT_7XX_WAKE_UP_REQ; 6568c2ecf20Sopenharmony_ci else if (cpu_is_omap16xx()) 6578c2ecf20Sopenharmony_ci irq = INT_1610_WAKE_UP_REQ; 6588c2ecf20Sopenharmony_ci else 6598c2ecf20Sopenharmony_ci irq = -1; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (irq >= 0) { 6628c2ecf20Sopenharmony_ci if (request_irq(irq, omap_wakeup_interrupt, 0, "peripheral wakeup", NULL)) 6638c2ecf20Sopenharmony_ci pr_err("Failed to request irq %d (peripheral wakeup)\n", irq); 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* Program new power ramp-up time 6678c2ecf20Sopenharmony_ci * (0 for most boards since we don't lower voltage when in deep sleep) 6688c2ecf20Sopenharmony_ci */ 6698c2ecf20Sopenharmony_ci omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */ 6728c2ecf20Sopenharmony_ci omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* Configure IDLECT3 */ 6758c2ecf20Sopenharmony_ci if (cpu_is_omap7xx()) 6768c2ecf20Sopenharmony_ci omap_writel(OMAP7XX_IDLECT3_VAL, OMAP7XX_IDLECT3); 6778c2ecf20Sopenharmony_ci else if (cpu_is_omap16xx()) 6788c2ecf20Sopenharmony_ci omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci suspend_set_ops(&omap_pm_ops); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 6838c2ecf20Sopenharmony_ci omap_pm_init_debugfs(); 6848c2ecf20Sopenharmony_ci#endif 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr); 6878c2ecf20Sopenharmony_ci if (error) 6888c2ecf20Sopenharmony_ci printk(KERN_ERR "sysfs_create_file failed: %d\n", error); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (cpu_is_omap16xx()) { 6918c2ecf20Sopenharmony_ci /* configure LOW_PWR pin */ 6928c2ecf20Sopenharmony_ci omap_cfg_reg(T20_1610_LOW_PWR); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return error; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci__initcall(omap_pm_init); 698