0001
0002
0003
0004
0005
0006 #include <linux/context_tracking.h>
0007 #include <linux/cpuidle.h>
0008 #include <linux/module.h>
0009 #include <asm/cpuidle.h>
0010
0011 #include <soc/imx/cpuidle.h>
0012
0013 #include "common.h"
0014 #include "cpuidle.h"
0015 #include "hardware.h"
0016
0017 static int num_idle_cpus = 0;
0018 static DEFINE_RAW_SPINLOCK(cpuidle_lock);
0019
0020 static int imx6q_enter_wait(struct cpuidle_device *dev,
0021 struct cpuidle_driver *drv, int index)
0022 {
0023 raw_spin_lock(&cpuidle_lock);
0024 if (++num_idle_cpus == num_online_cpus())
0025 imx6_set_lpm(WAIT_UNCLOCKED);
0026 raw_spin_unlock(&cpuidle_lock);
0027
0028 ct_idle_enter();
0029 cpu_do_idle();
0030 ct_idle_exit();
0031
0032 raw_spin_lock(&cpuidle_lock);
0033 if (num_idle_cpus-- == num_online_cpus())
0034 imx6_set_lpm(WAIT_CLOCKED);
0035 raw_spin_unlock(&cpuidle_lock);
0036
0037 return index;
0038 }
0039
0040 static struct cpuidle_driver imx6q_cpuidle_driver = {
0041 .name = "imx6q_cpuidle",
0042 .owner = THIS_MODULE,
0043 .states = {
0044
0045 ARM_CPUIDLE_WFI_STATE,
0046
0047 {
0048 .exit_latency = 50,
0049 .target_residency = 75,
0050 .flags = CPUIDLE_FLAG_TIMER_STOP | CPUIDLE_FLAG_RCU_IDLE,
0051 .enter = imx6q_enter_wait,
0052 .name = "WAIT",
0053 .desc = "Clock off",
0054 },
0055 },
0056 .state_count = 2,
0057 .safe_state_index = 0,
0058 };
0059
0060
0061
0062
0063
0064
0065
0066 void imx6q_cpuidle_fec_irqs_used(void)
0067 {
0068 cpuidle_driver_state_disabled(&imx6q_cpuidle_driver, 1, true);
0069 }
0070 EXPORT_SYMBOL_GPL(imx6q_cpuidle_fec_irqs_used);
0071
0072 void imx6q_cpuidle_fec_irqs_unused(void)
0073 {
0074 cpuidle_driver_state_disabled(&imx6q_cpuidle_driver, 1, false);
0075 }
0076 EXPORT_SYMBOL_GPL(imx6q_cpuidle_fec_irqs_unused);
0077
0078 int __init imx6q_cpuidle_init(void)
0079 {
0080
0081 imx6_set_int_mem_clk_lpm(true);
0082
0083 return cpuidle_register(&imx6q_cpuidle_driver, NULL);
0084 }