From patchwork Tue Jul 27 08:14:35 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Magnus Damm X-Patchwork-Id: 114470 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o6R8BPjq012780 for ; Tue, 27 Jul 2010 08:13:38 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753952Ab0G0INi (ORCPT ); Tue, 27 Jul 2010 04:13:38 -0400 Received: from mail-pw0-f46.google.com ([209.85.160.46]:53595 "EHLO mail-pw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751222Ab0G0INg (ORCPT ); Tue, 27 Jul 2010 04:13:36 -0400 Received: by pwi5 with SMTP id 5so346761pwi.19 for ; Tue, 27 Jul 2010 01:13:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:date:message-id :subject; bh=7BiWCopNV3B4y4Ywp3hmFsaDPQZOVIM1R7xYYHauykY=; b=YHcPx69C6zAr99duv/7aXjSyD4+TnRyQsA7idc+jxnePtOAyELJ4vmWJoPA/UCpf5I 1py2nPvDF6GEUBdSNVjoYzA6+w6+PlAsjwQ1s37PuNbX81LUyFVhvTpJXPdmT52HhI24 lGL7lwfbFn3iChkfU5ck/w+sdmmE3UUtJYRD4= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:date:message-id:subject; b=SpW5aVKN9QpVA//yQ3bH3kEFEQdJPTpqkloukrC8+OJ17aY6Aef1ysRcNrSYHPgK8O vuT40/c6maHE65ghRjFTcgJKSLvOUw5T+/Wii2OFfe+LnVQfRuKs1AZNS/RV2UHut7x5 bvNaUSKGLV06lWJoZSf0midk9qyIxD45rzGoA= Received: by 10.114.39.7 with SMTP id m7mr12803769wam.92.1280218415854; Tue, 27 Jul 2010 01:13:35 -0700 (PDT) Received: from [127.0.0.1] (49.14.32.202.bf.2iij.net [202.32.14.49]) by mx.google.com with ESMTPS id s5sm8343512wak.12.2010.07.27.01.13.34 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 27 Jul 2010 01:13:35 -0700 (PDT) From: Magnus Damm To: linux-sh@vger.kernel.org Cc: Magnus Damm , lethal@linux-sh.org Date: Tue, 27 Jul 2010 17:14:35 +0900 Message-Id: <20100727081435.24558.96566.sendpatchset@t400s> Subject: [PATCH] ARM: mach-shmobile: Runtime PM V3 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 27 Jul 2010 08:13:38 +0000 (UTC) --- 0001/arch/arm/mach-shmobile/Makefile +++ work/arch/arm/mach-shmobile/Makefile 2010-07-27 16:15:37.000000000 +0900 @@ -3,7 +3,7 @@ # # Common objects -obj-y := timer.o console.o clock.o +obj-y := timer.o console.o clock.o pm_runtime.o # CPU objects obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o --- 0001/arch/arm/mach-shmobile/clock-sh7372.c +++ work/arch/arm/mach-shmobile/clock-sh7372.c 2010-07-27 16:15:37.000000000 +0900 @@ -274,7 +274,7 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ - [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, CLK_ENABLE_ON_INIT), /* FSIA */ + [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSIA */ [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */ [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */ --- /dev/null +++ work/arch/arm/mach-shmobile/pm_runtime.c 2010-07-27 16:50:22.000000000 +0900 @@ -0,0 +1,169 @@ +/* + * arch/arm/mach-shmobile/pm_runtime.c + * + * Runtime PM support code for SuperH Mobile ARM + * + * Copyright (C) 2009-2010 Magnus Damm + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM_RUNTIME +#define BIT_ONCE 0 +#define BIT_ACTIVE 1 +#define BIT_CLK_ENABLED 2 + +struct pm_runtime_data { + unsigned long flags; + struct clk *clk; +}; + +static void __devres_release(struct device *dev, void *res) +{ + struct pm_runtime_data *prd = res; + + dev_dbg(dev, "__devres_release()\n"); + + if (test_bit(BIT_CLK_ENABLED, &prd->flags)) + clk_disable(prd->clk); + + if (test_bit(BIT_ACTIVE, &prd->flags)) + clk_put(prd->clk); +} + +static struct pm_runtime_data *__to_prd(struct device *dev) +{ + return devres_find(dev, __devres_release, NULL, NULL); +} + +static void platform_pm_runtime_init(struct device *dev, + struct pm_runtime_data *prd) +{ + if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) { + prd->clk = clk_get(dev, NULL); + if (!IS_ERR(prd->clk)) { + set_bit(BIT_ACTIVE, &prd->flags); + dev_info(dev, "clocks managed by runtime pm\n"); + } + } +} + +static void platform_pm_runtime_bug(struct device *dev, + struct pm_runtime_data *prd) +{ + if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) + dev_err(dev, "runtime pm suspend before resume\n"); +} + +int platform_pm_runtime_suspend(struct device *dev) +{ + struct pm_runtime_data *prd = __to_prd(dev); + + dev_dbg(dev, "platform_pm_runtime_suspend()\n"); + + platform_pm_runtime_bug(dev, prd); + + if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { + clk_disable(prd->clk); + clear_bit(BIT_CLK_ENABLED, &prd->flags); + } + + return 0; +} + +int platform_pm_runtime_resume(struct device *dev) +{ + struct pm_runtime_data *prd = __to_prd(dev); + + dev_dbg(dev, "platform_pm_runtime_resume()\n"); + + platform_pm_runtime_init(dev, prd); + + if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { + clk_enable(prd->clk); + set_bit(BIT_CLK_ENABLED, &prd->flags); + } + + return 0; +} + +int platform_pm_runtime_idle(struct device *dev) +{ + /* suspend synchronously to disable clocks immediately */ + return pm_runtime_suspend(dev); +} + +static int platform_bus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct pm_runtime_data *prd; + + dev_dbg(dev, "platform_bus_notify() %ld !\n", action); + + if (action == BUS_NOTIFY_BIND_DRIVER) { + prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL); + if (prd) + devres_add(dev, prd); + else + dev_err(dev, "unable to alloc memory for runtime pm\n"); + } + + return 0; +} + +#else /* CONFIG_PM_RUNTIME */ + +static int platform_bus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct clk *clk; + + dev_dbg(dev, "platform_bus_notify() %ld !\n", action); + + switch (action) { + case BUS_NOTIFY_BIND_DRIVER: + clk = clk_get(dev, NULL); + if (!IS_ERR(clk)) { + clk_enable(clk); + clk_put(clk); + dev_info(dev, "runtime pm disabled, clock forced on\n"); + } + break; + case BUS_NOTIFY_UNBOUND_DRIVER: + clk = clk_get(dev, NULL); + if (!IS_ERR(clk)) { + clk_disable(clk); + clk_put(clk); + dev_info(dev, "runtime pm disabled, clock forced off\n"); + } + break; + } + + return 0; +} + +#endif /* CONFIG_PM_RUNTIME */ + +static struct notifier_block platform_bus_notifier = { + .notifier_call = platform_bus_notify +}; + +static int __init sh_pm_runtime_init(void) +{ + bus_register_notifier(&platform_bus_type, &platform_bus_notifier); + return 0; +} +core_initcall(sh_pm_runtime_init);