1 /* 2 * Copyright (C) 2014 Freescale Semiconductor, Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/cpuidle.h> 10 #include <linux/cpu_pm.h> 11 #include <linux/module.h> 12 #include <asm/cpuidle.h> 13 #include <asm/suspend.h> 14 15 #include "common.h" 16 #include "cpuidle.h" 17 18 static int imx6sx_idle_finish(unsigned long val) 19 { 20 cpu_do_idle(); 21 22 return 0; 23 } 24 25 static int imx6sx_enter_wait(struct cpuidle_device *dev, 26 struct cpuidle_driver *drv, int index) 27 { 28 imx6q_set_lpm(WAIT_UNCLOCKED); 29 30 switch (index) { 31 case 1: 32 cpu_do_idle(); 33 break; 34 case 2: 35 imx6_enable_rbc(true); 36 imx_gpc_set_arm_power_in_lpm(true); 37 imx_set_cpu_jump(0, v7_cpu_resume); 38 /* Need to notify there is a cpu pm operation. */ 39 cpu_pm_enter(); 40 cpu_cluster_pm_enter(); 41 42 cpu_suspend(0, imx6sx_idle_finish); 43 44 cpu_cluster_pm_exit(); 45 cpu_pm_exit(); 46 imx_gpc_set_arm_power_in_lpm(false); 47 imx6_enable_rbc(false); 48 break; 49 default: 50 break; 51 } 52 53 imx6q_set_lpm(WAIT_CLOCKED); 54 55 return index; 56 } 57 58 static struct cpuidle_driver imx6sx_cpuidle_driver = { 59 .name = "imx6sx_cpuidle", 60 .owner = THIS_MODULE, 61 .states = { 62 /* WFI */ 63 ARM_CPUIDLE_WFI_STATE, 64 /* WAIT */ 65 { 66 .exit_latency = 50, 67 .target_residency = 75, 68 .flags = CPUIDLE_FLAG_TIMER_STOP, 69 .enter = imx6sx_enter_wait, 70 .name = "WAIT", 71 .desc = "Clock off", 72 }, 73 /* WAIT + ARM power off */ 74 { 75 /* 76 * ARM gating 31us * 5 + RBC clear 65us 77 * and some margin for SW execution, here set it 78 * to 300us. 79 */ 80 .exit_latency = 300, 81 .target_residency = 500, 82 .enter = imx6sx_enter_wait, 83 .name = "LOW-POWER-IDLE", 84 .desc = "ARM power off", 85 }, 86 }, 87 .state_count = 3, 88 .safe_state_index = 0, 89 }; 90 91 int __init imx6sx_cpuidle_init(void) 92 { 93 imx6_enable_rbc(false); 94 /* 95 * set ARM power up/down timing to the fastest, 96 * sw2iso and sw can be set to one 32K cycle = 31us 97 * except for power up sw2iso which need to be 98 * larger than LDO ramp up time. 99 */ 100 imx_gpc_set_arm_power_up_timing(2, 1); 101 imx_gpc_set_arm_power_down_timing(1, 1); 102 103 return cpuidle_register(&imx6sx_cpuidle_driver, NULL); 104 } 105