diff options
Diffstat (limited to 'arch/arm/mach-s5pv210/cpuidle.c')
-rw-r--r-- | arch/arm/mach-s5pv210/cpuidle.c | 100 |
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); |