From patchwork Thu Sep 1 13:45:47 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 75218 Delivered-To: patch@linaro.org Received: by 10.140.29.8 with SMTP id a8csp309024qga; Thu, 1 Sep 2016 06:48:32 -0700 (PDT) X-Received: by 10.98.39.193 with SMTP id n184mr16351292pfn.164.1472737712286; Thu, 01 Sep 2016 06:48:32 -0700 (PDT) Return-Path: Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id 68si5842007pfr.68.2016.09.01.06.48.32 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 01 Sep 2016 06:48:32 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org designates 2001:1868:205::9 as permitted sender) client-ip=2001:1868:205::9; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org designates 2001:1868:205::9 as permitted sender) smtp.mailfrom=linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bfSKy-00083b-4F; Thu, 01 Sep 2016 13:47:24 +0000 Received: from mailout2.w1.samsung.com ([210.118.77.12]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bfSKD-0007bu-SV for linux-arm-kernel@lists.infradead.org; Thu, 01 Sep 2016 13:46:40 +0000 Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout2.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0OCT00FLBVKXXIC0@mailout2.w1.samsung.com> for linux-arm-kernel@lists.infradead.org; Thu, 01 Sep 2016 14:46:09 +0100 (BST) X-AuditID: cbfec7f5-f792e6d0000013f5-12-57c83120fa48 Received: from eusync2.samsung.com ( [203.254.199.212]) by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id B4.D6.05109.02138C75; Thu, 1 Sep 2016 14:46:08 +0100 (BST) Received: from AMDC2765.digital.local ([106.116.147.25]) by eusync2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OCT00993VKRF730@eusync2.samsung.com>; Thu, 01 Sep 2016 14:46:08 +0100 (BST) From: Marek Szyprowski To: linux-clk@vger.kernel.org, linux-pm@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH 1/5] clk: add support for runtime pm Date: Thu, 01 Sep 2016 15:45:47 +0200 Message-id: <1472737551-15272-2-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1472737551-15272-1-git-send-email-m.szyprowski@samsung.com> References: <1472737551-15272-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrMLMWRmVeSWpSXmKPExsVy+t/xK7oKhifCDW4vt7HYOGM9q8X1L89Z LSbdn8Bi8fqFocWmx9dYLT723GO1+Nx7hNFixvl9TBZrj9xlt7h4ytXi8Jt2VosfZ7pZLI6v DXfg9Xh/o5Xd43JfL5PHnWt72Dw2L6n36NuyitHj8ya5ALYoLpuU1JzMstQifbsErowZyxUK thhXdBz+xdjA+FOji5GDQ0LARKJ/CncXIyeQKSZx4d56ti5GLg4hgaWMEm+3L2CHcJqYJPrf z2UHqWITMJToetsFViUi0MQo8aRvGlgVs0Afs0TrtOlgVcJAY49NO8MCYrMIqEocPDmTDcTm FfCQuPpkISvEPjmJk8cmg9mcAp4SnevWgvUKAdWs2DGXcQIj7wJGhlWMoqmlyQXFSem5RnrF ibnFpXnpesn5uZsYIUH5dQfj0mNWhxgFOBiVeHg36J8IF2JNLCuuzD3EKMHBrCTCK2QAFOJN SaysSi3Kjy8qzUktPsQozcGiJM47c9f7ECGB9MSS1OzU1ILUIpgsEwenVAOjpVRL//PemEd2 3aU2FvtLbkzvD7tzRoQ3b8YHoc5FoTvPG33mkNaMceD+q6ty/tyWNPX7hgIak2RLZBrVd8wI tTnEnxdeJ7Ri3w8RkweW7Nf+O3b1rGCdv7Na86HIvu8Bonbb1ZJ3S853ZJiZ82thkCP3HNN/ y68Fz3n88HLzlR+b/9xdnH5ciaU4I9FQi7moOBEAi1g3D0YCAAA= X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160901_064638_234663_EABE8787 X-CRM114-Status: GOOD ( 27.43 ) X-Spam-Score: -8.3 (--------) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-8.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [210.118.77.12 listed in wl.mailspike.net] -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [210.118.77.12 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -1.4 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] -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Ulf Hansson , Bartlomiej Zolnierkiewicz , Michael Turquette , Stephen Boyd , Krzysztof Kozlowski , Inki Dae , Chanwoo Choi , Sylwester Nawrocki , Marek Szyprowski MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org Registers for some clocks might be located in the SOC area, which are under the power domain. To enable access to those registers respective domain has to be turned on. Additionally, registers for such clocks will usually loose its contents when power domain is turned off, so additional saving and restoring of them might be needed in the clock controller driver. This patch adds basic infrastructure in the clocks core to allow implementing driver for such clocks under power domains. Clock provider can supply a struct device pointer, which is the used by clock core for tracking and managing clock's controller runtime pm state. Each clk_prepare() operation will first call pm_runtime_get_sync() on the supplied device, while clk_unprepare() will do pm_runtime_put() at the end. Additional calls to pm_runtime_get/put functions are required to ensure that any register access (like calculating/chaning clock rates) will be done with clock controller in active runtime state. Special handling of the case when runtime pm is disabled for clock controller's device is needed to let this feature work properly also during system sleep suspend/resume operations (runtime pm is first disabled before entering sleep state's, but controller is usually still operational until its suspend pm callback is called). Signed-off-by: Marek Szyprowski --- drivers/clk/clk.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 8 deletions(-) -- 1.9.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 820a939fb6bb..a1934e9b4e95 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,7 @@ struct clk_core { const struct clk_ops *ops; struct clk_hw *hw; struct module *owner; + struct device *dev; struct clk_core *parent; const char **parent_names; struct clk_core **parents; @@ -87,6 +89,42 @@ struct clk { struct hlist_node clks_node; }; +/*** runtime pm ***/ +static int clk_pm_runtime_get(struct clk_core *core) +{ + int ret = 0; + + if (!core->dev) + return 0; + + if (pm_runtime_enabled(core->dev)) { + ret = pm_runtime_get_sync(core->dev); + } else { + if (!pm_runtime_status_suspended(core->dev)) + pm_runtime_get_noresume(core->dev); + } + return ret < 0 ? ret : 0; +} + +static void clk_pm_runtime_put(struct clk_core *core) +{ + if (!core->dev) + return; + + if (pm_runtime_enabled(core->dev)) + pm_runtime_put(core->dev); + else + pm_runtime_put_noidle(core->dev); +} + +static bool clk_pm_runtime_suspended(struct clk_core *core) +{ + if (!core->dev) + return 0; + + return pm_runtime_suspended(core->dev); +} + /*** locking ***/ static void clk_prepare_lock(void) { @@ -150,6 +188,9 @@ static void clk_enable_unlock(unsigned long flags) static bool clk_core_is_prepared(struct clk_core *core) { + if (clk_pm_runtime_suspended(core)) + return false; + /* * .is_prepared is optional for clocks that can prepare * fall back to software usage counter if it is missing @@ -162,6 +203,9 @@ static bool clk_core_is_prepared(struct clk_core *core) static bool clk_core_is_enabled(struct clk_core *core) { + if (clk_pm_runtime_suspended(core)) + return false; + /* * .is_enabled is only mandatory for clocks that gate * fall back to software usage counter if .is_enabled is missing @@ -489,6 +533,8 @@ static void clk_core_unprepare(struct clk_core *core) if (core->ops->unprepare) core->ops->unprepare(core->hw); + clk_pm_runtime_put(core); + trace_clk_unprepare_complete(core); clk_core_unprepare(core->parent); } @@ -530,10 +576,14 @@ static int clk_core_prepare(struct clk_core *core) return 0; if (core->prepare_count == 0) { - ret = clk_core_prepare(core->parent); + ret = clk_pm_runtime_get(core); if (ret) return ret; + ret = clk_core_prepare(core->parent); + if (ret) + goto runtime_put; + trace_clk_prepare(core); if (core->ops->prepare) @@ -541,15 +591,18 @@ static int clk_core_prepare(struct clk_core *core) trace_clk_prepare_complete(core); - if (ret) { - clk_core_unprepare(core->parent); - return ret; - } + if (ret) + goto unprepare; } core->prepare_count++; return 0; +unprepare: + clk_core_unprepare(core->parent); +runtime_put: + clk_pm_runtime_put(core); + return ret; } static int clk_core_prepare_lock(struct clk_core *core) @@ -1563,6 +1616,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core, { struct clk_core *top, *fail_clk; unsigned long rate = req_rate; + int ret = 0; if (!core) return 0; @@ -1579,21 +1633,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core, if (!top) return -EINVAL; + ret = clk_pm_runtime_get(core); + if (ret) + return ret; + /* notify that we are about to change rates */ fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE); if (fail_clk) { pr_debug("%s: failed to set %s rate\n", __func__, fail_clk->name); clk_propagate_rate_change(top, ABORT_RATE_CHANGE); - return -EBUSY; + ret = -EBUSY; + goto err; } /* change the rates */ clk_change_rate(top); core->req_rate = req_rate; +err: + clk_pm_runtime_put(core); - return 0; + return ret; } /** @@ -1824,12 +1885,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent) p_rate = parent->rate; } + ret = clk_pm_runtime_get(core); + if (ret) + goto out; + /* propagate PRE_RATE_CHANGE notifications */ ret = __clk_speculate_rates(core, p_rate); /* abort if a driver objects */ if (ret & NOTIFY_STOP_MASK) - goto out; + goto runtime_put; /* do the re-parent */ ret = __clk_set_parent(core, parent, p_index); @@ -1842,6 +1907,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent) __clk_recalc_accuracies(core); } +runtime_put: + clk_pm_runtime_put(core); out: clk_prepare_unlock(); @@ -2546,6 +2613,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) goto fail_name; } core->ops = hw->init->ops; + core->dev = dev; if (dev && dev->driver) core->owner = dev->driver->owner; core->hw = hw;