From patchwork Fri Aug 26 02:33:14 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Lee X-Patchwork-Id: 1099962 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p7Q2XkPp032121 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Fri, 26 Aug 2011 02:34:07 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QwmEa-0003us-OB; Fri, 26 Aug 2011 02:33:28 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QwmEa-0004jS-9Z; Fri, 26 Aug 2011 02:33:28 +0000 Received: from mail-yw0-f49.google.com ([209.85.213.49]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QwmEU-0004ir-UX for linux-arm-kernel@lists.infradead.org; Fri, 26 Aug 2011 02:33:25 +0000 Received: by ywp17 with SMTP id 17so2724408ywp.36 for ; Thu, 25 Aug 2011 19:33:20 -0700 (PDT) Received: by 10.91.146.7 with SMTP id y7mr533709agn.38.1314325998374; Thu, 25 Aug 2011 19:33:18 -0700 (PDT) Received: from b18647-20 ([64.31.34.40]) by mx.google.com with ESMTPS id c5sm1097809anh.1.2011.08.25.19.33.16 (version=SSLv3 cipher=OTHER); Thu, 25 Aug 2011 19:33:17 -0700 (PDT) From: Robert Lee To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 1/2] Adding platform level cpuidle driver for i.MX SoCs. Date: Thu, 25 Aug 2011 21:33:14 -0500 Message-Id: <1314325995-29118-1-git-send-email-rob.lee@linaro.org> X-Mailer: git-send-email 1.7.1 X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110825_223323_127880_0F0D5A24 X-CRM114-Status: GOOD ( 19.48 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.213.49 listed in list.dnswl.org] Cc: rob.lee@linaro.org, s.hauer@pengutronix.de, amit.kucheria@linaro.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 26 Aug 2011 02:34:07 +0000 (UTC) Signed-off-by: Robert Lee --- arch/arm/plat-mxc/Kconfig | 10 ++++ arch/arm/plat-mxc/Makefile | 2 + arch/arm/plat-mxc/cpuidle.c | 112 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 0 deletions(-) create mode 100644 arch/arm/plat-mxc/cpuidle.c diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index a5353fc..84672b3 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -122,4 +122,14 @@ config IRAM_ALLOC bool select GENERIC_ALLOCATOR +config ARCH_HAS_CPUIDLE + bool + +config MXC_CPUIDLE + bool + depends on ARCH_HAS_CPUIDLE && CPU_IDLE + default y + help + Internal node to signify that the ARCH has CPUIDLE support. + endif diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index d53c35f..59f20ac 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -19,6 +19,8 @@ obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o +obj-$(CONFIG_MXC_CPUIDLE) += cpuidle.o + ifdef CONFIG_SND_IMX_SOC obj-y += ssi-fiq.o obj-y += ssi-fiq-ksym.o diff --git a/arch/arm/plat-mxc/cpuidle.c b/arch/arm/plat-mxc/cpuidle.c new file mode 100644 index 0000000..cd637e1 --- /dev/null +++ b/arch/arm/plat-mxc/cpuidle.c @@ -0,0 +1,112 @@ +/* + * 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 +#include +#include +#include +#include +#include + + +#ifndef MXC_OVERRIDE_DEFAULT_CPUIDLE_PARAMS + +#define MXC_X_MACRO(a, b, c) {c} +static struct imx_cpuidle_params default_cpuidle_params[] = \ + MXC_CPUIDLE_TABLE; +#undef MXC_X_MACRO + +static struct imx_cpuidle_params *imx_cpuidle_params = default_cpuidle_params; + +#else + +static struct imx_cpuidle_params *imx_cpuidle_params; + +#endif + + + +/* in case you want to override the mach level params at the board level */ +void imx_cpuidle_board_params(struct imx_cpuidle_params *cpuidle_params) +{ + imx_cpuidle_params = cpuidle_params; +} + +static int imx_enter_idle(struct cpuidle_device *dev, + struct cpuidle_state *state) +{ + struct timeval before, after; + int idle_time, i; + + /* We only need to pass an index to the mach level so here we + * find the index of the name contained in the cpuidle_state + * to pass. */ + for (i = 0; i < MXC_NUM_CPUIDLE_STATES && i < CPUIDLE_STATE_MAX; i++) + if (state == &dev->states[i]) + break; + + local_irq_disable(); + local_fiq_disable(); + + do_gettimeofday(&before); + + imx_cpu_do_idle(i); + + do_gettimeofday(&after); + + local_fiq_enable(); + local_irq_enable(); + + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + + (after.tv_usec - before.tv_usec); + + return idle_time; +} + +static struct cpuidle_driver imx_cpuidle_driver = { + .name = "imx_idle", + .owner = THIS_MODULE, +}; + +static DEFINE_PER_CPU(struct cpuidle_device, imx_cpuidle_device); + +static int __init imx_cpuidle_init(void) +{ + struct cpuidle_device *device; + int i; + + #define MXC_X_MACRO(a, b, c) #a + char *mxc_cpuidle_state_name[] = MXC_CPUIDLE_TABLE; + #undef MXC_X_MACRO + + #define MXC_X_MACRO(a, b, c) b + char *mxc_cpuidle_state_desc[] = MXC_CPUIDLE_TABLE; + #undef MXC_X_MACRO + + if (imx_cpuidle_params == NULL) + return -ENODEV; + + cpuidle_register_driver(&imx_cpuidle_driver); + + device = &per_cpu(imx_cpuidle_device, smp_processor_id()); + device->state_count = MXC_NUM_CPUIDLE_STATES; + + for (i = 0; i < MXC_NUM_CPUIDLE_STATES && i < CPUIDLE_STATE_MAX; i++) { + device->states[i].enter = imx_enter_idle; + device->states[i].exit_latency = imx_cpuidle_params[i].latency; + device->states[i].flags = CPUIDLE_FLAG_TIME_VALID; + strcpy(device->states[i].name, mxc_cpuidle_state_name[i]); + strcpy(device->states[i].desc, mxc_cpuidle_state_desc[i]); + } + + if (cpuidle_register_device(device)) { + printk(KERN_ERR "imx_cpuidle_init: Failed registering\n"); + return -ENODEV; + } + return 0; +} + +late_initcall(imx_cpuidle_init);