diff options
| author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-12-24 11:38:27 +0900 | 
|---|---|---|
| committer | Kukjin Kim <kgene.kim@samsung.com> | 2012-01-20 09:39:52 +0900 | 
| commit | 2abf13c9ffdcde537fc54b83f1bcd50cc758beca (patch) | |
| tree | d74405613d53e34d95a5ee3c812d84580bfac9df | |
| parent | dcd6c92267155e70a94b3927bce681ce74b80d1f (diff) | |
ARM: S3C64XX: Add basic cpuidle driver
Add a very basic cpuidle driver for S3C64xx which merely drives the CPU
into IDLE mode. We could do this with pm_idle but the more modern idiom
is to use cpuidle and the intention is to go further and support STOP
and DEEP-STOP states in conjunction with the pm_domain framework.
The actual state entry code was lifted from Tomasz Figa's work on spica.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
| -rw-r--r-- | arch/arm/mach-s3c64xx/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/mach-s3c64xx/cpuidle.c | 91 | 
2 files changed, 92 insertions, 0 deletions
| diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index 1822ac2eba31..610fe2807ed7 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_CPU_S3C6410)	+= s3c6410.o  # PM  obj-$(CONFIG_PM)		+= pm.o irq-pm.o sleep.o +obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o  # DMA support diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c new file mode 100644 index 000000000000..625d2c7b4540 --- /dev/null +++ b/arch/arm/mach-s3c64xx/cpuidle.c @@ -0,0 +1,91 @@ +/* linux/arch/arm/mach-s3c64xx/cpuidle.c + * + * Copyright (c) 2011 Wolfson Microelectronics, plc + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/cpuidle.h> +#include <linux/io.h> +#include <linux/export.h> +#include <linux/time.h> + +#include <asm/proc-fns.h> + +#include <mach/map.h> + +#include <mach/regs-sys.h> +#include <mach/regs-syscon-power.h> + +static int s3c64xx_enter_idle(struct cpuidle_device *dev, +			      struct cpuidle_driver *drv, +			      int index) +{ +	struct timeval before, after; +	unsigned long tmp; +	int idle_time; + +	local_irq_disable(); +	do_gettimeofday(&before); + +	/* Setup PWRCFG to enter idle mode */ +	tmp = __raw_readl(S3C64XX_PWR_CFG); +	tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK; +	tmp |= S3C64XX_PWRCFG_CFG_WFI_IDLE; +	__raw_writel(tmp, S3C64XX_PWR_CFG); + +	cpu_do_idle(); + +	do_gettimeofday(&after); +	local_irq_enable(); +	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + +		    (after.tv_usec - before.tv_usec); + +	dev->last_residency = idle_time; +	return index; +} + +static struct cpuidle_state s3c64xx_cpuidle_set[] = { +	[0] = { +		.enter			= s3c64xx_enter_idle, +		.exit_latency		= 1, +		.target_residency	= 100000, +		.flags			= CPUIDLE_FLAG_TIME_VALID, +		.name			= "IDLE", +		.desc			= "System active, ARM gated", +	}, +}; + +static struct cpuidle_driver s3c64xx_cpuidle_driver = { +	.name		= "s3c64xx_cpuidle", +	.owner		= THIS_MODULE, +	.state_count	= ARRAY_SIZE(s3c64xx_cpuidle_set), +}; + +static struct cpuidle_device s3c64xx_cpuidle_device = { +	.state_count	= ARRAY_SIZE(s3c64xx_cpuidle_set), +}; + +static int __init s3c64xx_init_cpuidle(void) +{ +	int ret; + +	memcpy(s3c64xx_cpuidle_driver.states, s3c64xx_cpuidle_set, +	       sizeof(s3c64xx_cpuidle_set)); +	cpuidle_register_driver(&s3c64xx_cpuidle_driver); + +	ret = cpuidle_register_device(&s3c64xx_cpuidle_device); +	if (ret) { +		pr_err("Failed to register cpuidle device: %d\n", ret); +		return ret; +	} + +	return 0; +} +device_initcall(s3c64xx_init_cpuidle); | 
