From patchwork Fri Jan 31 18:12:45 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Felipe Balbi X-Patchwork-Id: 23986 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qa0-f70.google.com (mail-qa0-f70.google.com [209.85.216.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 59709202B2 for ; Fri, 31 Jan 2014 18:15:00 +0000 (UTC) Received: by mail-qa0-f70.google.com with SMTP id ii20sf10345680qab.1 for ; Fri, 31 Jan 2014 10:14:59 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:subject:date:message-id :mime-version:cc:precedence:list-id:list-unsubscribe:list-archive :list-post:list-help:list-subscribe:sender:errors-to :x-original-sender:x-original-authentication-results:mailing-list :content-type:content-transfer-encoding; bh=l5pT43BLTKogo8PYq84K/rX4JFT21xDmc/9jJE5vF2A=; b=arpmw/7NRXzO9dnX2tkFqoo7bKkNuPkKU9dreNNtAXlFlUIlRevfqC+Zm1Ln4xdILM Rf7M81Xe918vOxqGMT4BtRnB8VPRw6nfBVCjRZVaTpBAhdhxFGcW6fJ8ABQEGTMoU3iX nKRRP38IVzn4b9aTWRBiKifi4ybTN7CbNIOk/mIN94p+gKY65bbRUapIfEPXCnfw15Kc yMHDwGCabkFt3qTS1uvp+aZm30zTm7dCRtYBWd+9xZPYP+iBYkUtlRMcfOEZbPbx5qvI NcpjxLNVoLcn3ttXPiddUR+i96737Leg5AeaAoazbGHzF29aIyCKZ//qpnKf5JQN7j0m i7Gw== X-Gm-Message-State: ALoCoQkMVlx8htQCd7kGCoZtaNt4iP0bNZ+lw/tTHLVOsNP3ssS9Bt9imnlEMXFLzNzJ8mPyfShL X-Received: by 10.52.121.68 with SMTP id li4mr1157238vdb.6.1391192099574; Fri, 31 Jan 2014 10:14:59 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.89.38 with SMTP id u35ls1097596qgd.60.gmail; Fri, 31 Jan 2014 10:14:59 -0800 (PST) X-Received: by 10.52.37.103 with SMTP id x7mr21708vdj.75.1391192099444; Fri, 31 Jan 2014 10:14:59 -0800 (PST) Received: from mail-vb0-f42.google.com (mail-vb0-f42.google.com [209.85.212.42]) by mx.google.com with ESMTPS id t4si3789410vcz.58.2014.01.31.10.14.59 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 31 Jan 2014 10:14:59 -0800 (PST) Received-SPF: neutral (google.com: 209.85.212.42 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.42; Received: by mail-vb0-f42.google.com with SMTP id i3so3233684vbh.1 for ; Fri, 31 Jan 2014 10:14:59 -0800 (PST) X-Received: by 10.52.106.166 with SMTP id gv6mr16330vdb.86.1391192099347; Fri, 31 Jan 2014 10:14:59 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.174.196 with SMTP id u4csp115976vcz; Fri, 31 Jan 2014 10:14:58 -0800 (PST) X-Received: by 10.180.105.41 with SMTP id gj9mr28407013wib.28.1391192098329; Fri, 31 Jan 2014 10:14:58 -0800 (PST) Received: from casper.infradead.org (casper.infradead.org. [2001:770:15f::2]) by mx.google.com with ESMTPS id hd8si14872959wib.36.2014.01.31.10.14.57 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 31 Jan 2014 10:14:58 -0800 (PST) Received-SPF: pass (google.com: domain of linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org designates 2001:770:15f::2 as permitted sender) client-ip=2001:770:15f::2; Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W9Ibz-0000EY-LR; Fri, 31 Jan 2014 18:14:43 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1W9Ibx-0000iW-BV; Fri, 31 Jan 2014 18:14:41 +0000 Received: from bear.ext.ti.com ([192.94.94.41]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W9Ibt-0000hy-Ug for linux-arm-kernel@lists.infradead.org; Fri, 31 Jan 2014 18:14:38 +0000 Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id s0VIE8PT010198; Fri, 31 Jan 2014 12:14:08 -0600 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id s0VIE8sx020027; Fri, 31 Jan 2014 12:14:08 -0600 Received: from dlep33.itg.ti.com (157.170.170.75) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.2.342.3; Fri, 31 Jan 2014 12:14:08 -0600 Received: from localhost (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep33.itg.ti.com (8.14.3/8.13.8) with ESMTP id s0VIE7jA021847; Fri, 31 Jan 2014 12:14:07 -0600 From: Felipe Balbi To: Greg KH Subject: [RFC/PATCH] base: platform: add generic clock handling for platform-bus Date: Fri, 31 Jan 2014 12:12:45 -0600 Message-ID: <1391191965-31102-1-git-send-email-balbi@ti.com> X-Mailer: git-send-email 1.8.5.2 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140131_131438_105055_30FDD687 X-CRM114-Status: GOOD ( 21.46 ) X-Spam-Score: -7.5 (-------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-7.5 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [192.94.94.41 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.6 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Kevin Hilman , Russell King , linux-pm@vger.kernel.org, Tony Lindgren , Linux Kernel Mailing List , Felipe Balbi , Tero Kristo , Linux OMAP Mailing List , Linux ARM Kernel Mailing List X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: balbi@ti.com X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.42 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 Still TODO a commit log. Not for merging!!!!! NYET-Signed-off-by: Felipe Balbi --- This patch is an idea I've had recently in order to combine several different PM implementations into the platform-bus. This patch is bare minimum for platforms which need to handle functional and interface clocks but the whole thing is made optional. Note that this patch makes sure that by the time a platform_driver's probe is called, we already have clocks enabled and pm_runtime_set_active() has been called, thus making sure that a device driver's pm_runtime_get_sync() will solely increase the pm usage counter. I have *NOT* tested this anywhere *YET*, but I suppose it shouldn't cause any issues since the clock API has ref counting too. Would really like to get some review from several folks involved with ARM SoC PM so that's the reason for the wide audience. If I have missed anybody, please add them to Cc. As mentioned above, this is *NOT* meant for merging, but serves as a starting point for discussing some convergence of several PM domain implementations on different arch/arm/mach-* directories. For OMAP, this has the added benefit of removing clock handling from omap_device/omap_hwmod and, thus, dropping the need for so many DT_CLK() tables under drivers/clk/ti/ drivers/base/platform.c | 169 ++++++++++++++++++++++++++++++++++++++-- include/linux/platform_device.h | 9 +++ 2 files changed, 173 insertions(+), 5 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 3a94b79..86aeb5b 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -484,6 +484,21 @@ static int platform_drv_probe(struct device *_dev) if (ACPI_HANDLE(_dev)) acpi_dev_pm_attach(_dev, true); + dev->fck = devm_clk_get(_dev, "fck"); + dev->ick = devm_clk_get(_dev, "ick"); + + if (!IS_ERR(dev->fck)) + clk_prepare_enable(dev->fck); + else + dev->fck = NULL; + + if (!IS_ERR(dev->ick)) + clk_prepare_enable(dev->ick); + else + dev->ick = NULL; + + pm_runtime_set_active(_dev); + ret = drv->probe(dev); if (ret && ACPI_HANDLE(_dev)) acpi_dev_pm_detach(_dev, true); @@ -507,6 +522,14 @@ static int platform_drv_remove(struct device *_dev) struct platform_device *dev = to_platform_device(_dev); int ret; + if (!IS_ERR(dev->ick)) + clk_disable_unprepare(dev->ick); + + if (!IS_ERR(dev->fck)) + clk_disable_unprepare(dev->fck); + + pm_runtime_set_suspended(_dev); + ret = drv->remove(dev); if (ACPI_HANDLE(_dev)) acpi_dev_pm_detach(_dev, true); @@ -780,6 +803,59 @@ static int platform_legacy_resume(struct device *dev) #endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM_RUNTIME +int platform_pm_runtime_suspend(struct device *dev) +{ + struct device_driver *drv = dev->driver; + struct platform_driver *pdrv = to_platform_driver(drv); + struct platform_device *pdev = to_platform_device(dev); + int ret; + + ret = pm_generic_runtime_suspend(dev); + if (ret) + return ret; + + if (!test_bit(PLATFORM_PM_RUNTIME_KEEP_ICK, &pdrv->flags)) + clk_disable(pdev->ick); + + if (!test_bit(PLATFORM_PM_RUNTIME_KEEP_FCK, &pdrv->flags)) + clk_disable(pdev->fck); + + return ret; +} + +int platform_pm_runtime_resume(struct device *dev) +{ + struct device_driver *drv = dev->driver; + struct platform_driver *pdrv = to_platform_driver(drv); + struct platform_device *pdev = to_platform_device(dev); + int ret; + + if (!test_bit(PLATFORM_PM_RUNTIME_KEEP_ICK, &pdrv->flags)) { + ret = clk_enable(pdev->ick); + if (ret) + return ret; + } + + if (!test_bit(PLATFORM_PM_RUNTIME_KEEP_FCK, &pdrv->flags)) { + ret = clk_enable(pdev->fck); + if (ret) { + clk_disable(pdev->ick); + return ret; + } + } + + ret = pm_generic_runtime_suspend(dev); + if (ret) { + clk_disable(pdev->ick); + clk_disable(pdev->fck); + return ret; + } + + return ret; +} +#endif + #ifdef CONFIG_SUSPEND int platform_pm_suspend(struct device *dev) @@ -790,6 +866,9 @@ int platform_pm_suspend(struct device *dev) if (!drv) return 0; + if (pm_runtime_suspended(dev)) + return 0; + if (drv->pm) { if (drv->pm->suspend) ret = drv->pm->suspend(dev); @@ -802,12 +881,27 @@ int platform_pm_suspend(struct device *dev) int platform_pm_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct device_driver *drv = dev->driver; int ret = 0; if (!drv) return 0; + ret = clk_enable(pdev->ick); + if (ret) + return ret; + + ret = clk_enable(pdev->fck); + if (ret) { + clk_disable(pdev->ick); + return ret; + } + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + if (drv->pm) { if (drv->pm->resume) ret = drv->pm->resume(dev); @@ -815,7 +909,17 @@ int platform_pm_resume(struct device *dev) ret = platform_legacy_resume(dev); } - return ret; + if (ret) { + clk_disable(pdev->ick); + clk_disable(pdev->fck); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + + return ret; + } + + return 0; } #endif /* CONFIG_SUSPEND */ @@ -830,6 +934,9 @@ int platform_pm_freeze(struct device *dev) if (!drv) return 0; + if (pm_runtime_suspended(dev)) + return 0; + if (drv->pm) { if (drv->pm->freeze) ret = drv->pm->freeze(dev); @@ -848,6 +955,20 @@ int platform_pm_thaw(struct device *dev) if (!drv) return 0; + ret = clk_enable(pdev->ick); + if (ret) + return ret; + + ret = clk_enable(pdev->fck); + if (ret) { + clk_disable(pdev->ick); + return ret; + } + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + if (drv->pm) { if (drv->pm->thaw) ret = drv->pm->thaw(dev); @@ -855,7 +976,17 @@ int platform_pm_thaw(struct device *dev) ret = platform_legacy_resume(dev); } - return ret; + if (ret) { + clk_disable(pdev->ick); + clk_disable(pdev->fck); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + + return ret; + } + + return 0; } int platform_pm_poweroff(struct device *dev) @@ -866,6 +997,9 @@ int platform_pm_poweroff(struct device *dev) if (!drv) return 0; + if (pm_runtime_suspended(dev)) + return 0; + if (drv->pm) { if (drv->pm->poweroff) ret = drv->pm->poweroff(dev); @@ -884,6 +1018,20 @@ int platform_pm_restore(struct device *dev) if (!drv) return 0; + ret = clk_enable(pdev->ick); + if (ret) + return ret; + + ret = clk_enable(pdev->fck); + if (ret) { + clk_disable(pdev->ick); + return ret; + } + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + if (drv->pm) { if (drv->pm->restore) ret = drv->pm->restore(dev); @@ -891,14 +1039,25 @@ int platform_pm_restore(struct device *dev) ret = platform_legacy_resume(dev); } - return ret; + if (ret) { + clk_disable(pdev->ick); + clk_disable(pdev->fck); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + + return ret; + } + + return 0; } #endif /* CONFIG_HIBERNATE_CALLBACKS */ static const struct dev_pm_ops platform_dev_pm_ops = { - .runtime_suspend = pm_generic_runtime_suspend, - .runtime_resume = pm_generic_runtime_resume, + SET_RUNTIME_PM_OPS(platform_pm_runtime_suspend, + platform_pm_runtime_resume, + NULL) USE_PLATFORM_PM_SLEEP_OPS }; diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 16f6654..91133f5 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -12,6 +12,7 @@ #define _PLATFORM_DEVICE_H_ #include +#include #include #define PLATFORM_DEVID_NONE (-1) @@ -21,6 +22,10 @@ struct mfd_cell; struct platform_device { const char *name; + + struct clk *fck; + struct clk *ick; + int id; bool id_auto; struct device dev; @@ -179,8 +184,12 @@ struct platform_driver { struct device_driver driver; const struct platform_device_id *id_table; bool prevent_deferred_probe; + unsigned long flags; }; +#define PLATFORM_PM_RUNTIME_KEEP_ICK BIT(0) +#define PLATFORM_PM_RUNTIME_KEEP_FCK BIT(1) + #define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ driver))