aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s5pv210/cpuidle.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s5pv210/cpuidle.c')
-rw-r--r--arch/arm/mach-s5pv210/cpuidle.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/arch/arm/mach-s5pv210/cpuidle.c b/arch/arm/mach-s5pv210/cpuidle.c
new file mode 100644
index 0000000..d7d532a
--- /dev/null
+++ b/arch/arm/mach-s5pv210/cpuidle.c
@@ -0,0 +1,100 @@
+/*
+ * arch/arm/mach-s5pv210/cpuidle.c
+ *
+ * Copyright (c) Samsung Electronics Co. Ltd
+ *
+ * CPU idle driver for S5PV210
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+#include <asm/proc-fns.h>
+#include <asm/cacheflush.h>
+
+#include <mach/map.h>
+#include <mach/regs-irq.h>
+#include <mach/regs-clock.h>
+#include <plat/pm.h>
+#include <plat/devs.h>
+
+#include <mach/dma.h>
+#include <mach/regs-gpio.h>
+
+#define S5PC110_MAX_STATES 1
+
+static void s5p_enter_idle(void)
+{
+ unsigned long tmp;
+
+ tmp = __raw_readl(S5P_IDLE_CFG);
+ tmp &= ~((3<<30)|(3<<28)|(1<<0));
+ tmp |= ((2<<30)|(2<<28));
+ __raw_writel(tmp, S5P_IDLE_CFG);
+
+ tmp = __raw_readl(S5P_PWR_CFG);
+ tmp &= S5P_CFG_WFI_CLEAN;
+ __raw_writel(tmp, S5P_PWR_CFG);
+
+ cpu_do_idle();
+}
+
+/* Actual code that puts the SoC in different idle states */
+static int s5p_enter_idle_normal(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ struct timeval before, after;
+ int idle_time;
+
+ local_irq_disable();
+ do_gettimeofday(&before);
+
+ s5p_enter_idle();
+
+ do_gettimeofday(&after);
+ local_irq_enable();
+ idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+ (after.tv_usec - before.tv_usec);
+ return idle_time;
+}
+
+static DEFINE_PER_CPU(struct cpuidle_device, s5p_cpuidle_device);
+
+static struct cpuidle_driver s5p_idle_driver = {
+ .name = "s5p_idle",
+ .owner = THIS_MODULE,
+};
+
+/* Initialize CPU idle by registering the idle states */
+static int s5p_init_cpuidle(void)
+{
+ struct cpuidle_device *device;
+
+ cpuidle_register_driver(&s5p_idle_driver);
+
+ device = &per_cpu(s5p_cpuidle_device, smp_processor_id());
+ device->state_count = 1;
+
+ /* Wait for interrupt state */
+ device->states[0].enter = s5p_enter_idle_normal;
+ device->states[0].exit_latency = 1; /* uS */
+ device->states[0].target_residency = 10000;
+ device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+ strcpy(device->states[0].name, "IDLE");
+ strcpy(device->states[0].desc, "ARM clock gating - WFI");
+
+ if (cpuidle_register_device(device)) {
+ printk(KERN_ERR "s5p_init_cpuidle: Failed registering\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+device_initcall(s5p_init_cpuidle);