From patchwork Sat Jul 14 00:16:41 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Turquette X-Patchwork-Id: 1197291 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id D8F74DFFFD for ; Sat, 14 Jul 2012 00:21:16 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Spq3k-0004G9-E0; Sat, 14 Jul 2012 00:18:08 +0000 Received: from comal.ext.ti.com ([198.47.26.152]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1Spq2n-0004EJ-4q for linux-arm-kernel@lists.infradead.org; Sat, 14 Jul 2012 00:17:12 +0000 Received: from dlelxv30.itg.ti.com ([172.17.2.17]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id q6E0GsCI006304; Fri, 13 Jul 2012 19:16:54 -0500 Received: from DLEE74.ent.ti.com (dlee74.ent.ti.com [157.170.170.8]) by dlelxv30.itg.ti.com (8.13.8/8.13.8) with ESMTP id q6E0GsEh024096; Fri, 13 Jul 2012 19:16:54 -0500 Received: from dlelxv22.itg.ti.com (172.17.1.197) by DLEE74.ent.ti.com (157.170.170.8) with Microsoft SMTP Server id 14.1.323.3; Fri, 13 Jul 2012 19:16:53 -0500 Received: from nucleus.nsc.com (nucleus.nsc.com [10.188.36.112]) by dlelxv22.itg.ti.com (8.13.8/8.13.8) with ESMTP id q6E0Goto005544; Fri, 13 Jul 2012 19:16:52 -0500 From: Mike Turquette To: Subject: [PATCH 2/2] [RFC] cpufreq: omap: scale regulator from clk notifier Date: Fri, 13 Jul 2012 17:16:41 -0700 Message-ID: <1342225001-22962-3-git-send-email-mturquette@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1342225001-22962-1-git-send-email-mturquette@linaro.org> References: <1342225001-22962-1-git-send-email-mturquette@linaro.org> MIME-Version: 1.0 X-Spam-Note: CRM114 invocation failed X-Spam-Score: -6.9 (------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-6.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [198.47.26.152 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: paul@pwsan.com, pgaikwad@nvidia.com, Mike Turquette , viresh.kumar@linaro.org, linus.walleij@linaro.org, rnayak@ti.com, rob.herring@calxeda.com, ccross@android.com, broonie@opensource.wolfsonmicro.com, tglx@linutronix.de, shawn.guo@linaro.org, pdeschrijver@nvidia.com, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This patch moves direct control of the MPU voltage regulator out of the cpufreq driver .target callback and instead puts that logic into a clock rate change notifier callback. The same frequency/voltage lookup via the OPP library is present, except that the calls to regulator_set_voltage are done from the clock framework instead of cpufreq. Ideally it would be nice to reduce the .target callback for OMAP's cpufreq driver to a simple call to clk_set_rate. For now there is still some other stuff needed there (jiffies per loop, rounding the rate, etc etc). Not-signed-off-by: Mike Turquette --- drivers/cpufreq/omap-cpufreq.c | 154 +++++++++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 58 deletions(-) diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 17fa04d..bf15c49 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -80,10 +80,9 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int relation) { unsigned int i; - int r, ret = 0; + int ret = 0; struct cpufreq_freqs freqs; - struct opp *opp; - unsigned long freq, volt = 0, volt_old = 0, tol = 0; + unsigned long freq; if (!freq_table) { dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, @@ -119,47 +118,11 @@ static int omap_target(struct cpufreq_policy *policy, freq = freqs.new * 1000; - if (mpu_reg) { - opp = opp_find_freq_ceil(mpu_dev, &freq); - if (IS_ERR(opp)) { - dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", - __func__, freqs.new); - return -EINVAL; - } - volt = opp_get_voltage(opp); - tol = volt * OPP_TOLERANCE / 100; - volt_old = regulator_get_voltage(mpu_reg); - } - - dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", - freqs.old / 1000, volt_old ? volt_old / 1000 : -1, - freqs.new / 1000, volt ? volt / 1000 : -1); - - /* scaling up? scale voltage before frequency */ - if (mpu_reg && (freqs.new > freqs.old)) { - r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); - if (r < 0) { - dev_warn(mpu_dev, "%s: unable to scale voltage up.\n", - __func__); - freqs.new = freqs.old; - goto done; - } - } + dev_dbg(mpu_dev, "cpufreq-omap: %u MHz --> %u MHz\n", + freqs.old / 1000, freqs.new / 1000); ret = clk_set_rate(mpu_clk, freqs.new * 1000); - /* scaling down? scale voltage after frequency */ - if (mpu_reg && (freqs.new < freqs.old)) { - r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); - if (r < 0) { - dev_warn(mpu_dev, "%s: unable to scale voltage down.\n", - __func__); - ret = clk_set_rate(mpu_clk, freqs.old * 1000); - freqs.new = freqs.old; - goto done; - } - } - freqs.new = omap_getspeed(policy->cpu); #ifdef CONFIG_SMP /* @@ -187,7 +150,6 @@ static int omap_target(struct cpufreq_policy *policy, freqs.new); #endif -done: /* notifiers */ for_each_cpu(i, policy->cpus) { freqs.cpu = i; @@ -207,10 +169,6 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) { int result = 0; - mpu_clk = clk_get(NULL, mpu_clk_name); - if (IS_ERR(mpu_clk)) - return PTR_ERR(mpu_clk); - if (policy->cpu >= NR_CPUS) { result = -EINVAL; goto fail_ck; @@ -284,32 +242,74 @@ static struct cpufreq_driver omap_driver = { .attr = omap_cpufreq_attr, }; -static int __init omap_cpufreq_init(void) +static int mpu_clk_volt_scale_handler(struct notifier_block *nb, + unsigned long flags, void *data) { - if (cpu_is_omap24xx()) - mpu_clk_name = "virt_prcm_set"; - else if (cpu_is_omap34xx()) - mpu_clk_name = "dpll1_ck"; - else if (cpu_is_omap44xx()) - mpu_clk_name = "dpll_mpu_ck"; + struct clk_notifier_data *cnd = data; + unsigned long tol; + int ret, volt_new, volt_old; + struct opp *opp; - if (!mpu_clk_name) { - pr_err("%s: unsupported Silicon?\n", __func__); - return -EINVAL; + volt_old = regulator_get_voltage(mpu_reg); + opp = opp_find_freq_exact(mpu_dev, cnd->new_rate, true); + volt_new = opp_get_voltage(opp); + + tol = volt_new * OPP_TOLERANCE / 100; + + /* scaling up? scale voltage before frequency */ + if (cnd->new_rate > cnd->old_rate) { + dev_dbg(mpu_dev, "cpufreq-omap: %d mV --> %d mV\n", + volt_old, volt_new); + + ret = regulator_set_voltage(mpu_reg, volt_new - tol, volt_new + tol); + + if (ret < 0) { + dev_warn(mpu_dev, "%s: unable to scale voltage up.\n", + __func__); + return NOTIFY_BAD; + } + } + + /* scaling down? scale voltage after frequency */ + if (cnd->new_rate < cnd->old_rate) { + dev_dbg(mpu_dev, "cpufreq-omap: %d mV --> %d mV\n", + volt_old, volt_new); + + ret = regulator_set_voltage(mpu_reg, volt_new - tol, volt_new + tol); + + if (ret< 0) { + dev_warn(mpu_dev, "%s: unable to scale voltage down.\n", + __func__); + return NOTIFY_BAD; + } } + return NOTIFY_OK; +} + +static struct notifier_block mpu_clk_volt_scale_nb = { + .notifier_call = mpu_clk_volt_scale_handler, +}; + +static int __init omap_regulator_init(void) +{ + int ret = 0; + mpu_dev = omap_device_get_by_hwmod_name("mpu"); if (!mpu_dev) { pr_warning("%s: unable to get the mpu device\n", __func__); - return -EINVAL; + ret = -EINVAL; + goto out; } mpu_reg = regulator_get(mpu_dev, "vcc"); if (IS_ERR(mpu_reg)) { pr_warning("%s: unable to get MPU regulator\n", __func__); mpu_reg = NULL; + ret = -ENODEV; + goto out; } else { - /* + /* * Ensure physical regulator is present. * (e.g. could be dummy regulator.) */ @@ -318,9 +318,47 @@ static int __init omap_cpufreq_init(void) __func__); regulator_put(mpu_reg); mpu_reg = NULL; + ret = -ENODEV; + goto out; } } +out: + return ret; +} + +static int __init omap_cpufreq_init(void) +{ + int ret; + + if (cpu_is_omap24xx()) + mpu_clk_name = "virt_prcm_set"; + else if (cpu_is_omap34xx()) + mpu_clk_name = "dpll1_ck"; + else if (cpu_is_omap44xx()) + mpu_clk_name = "dpll_mpu_ck"; + + if (!mpu_clk_name) { + pr_err("%s: unsupported Silicon?\n", __func__); + return -EINVAL; + } + + mpu_clk = clk_get(NULL, mpu_clk_name); + if (IS_ERR(mpu_clk)) + return PTR_ERR(mpu_clk); + + ret = omap_regulator_init(); + if (ret) { + pr_err("%s: failed to get mpu regulator\n", __func__); + pr_err("%s: skipping clk notifier registration\n", __func__); + goto out; + } + + ret = clk_notifier_register(mpu_clk, &mpu_clk_volt_scale_nb); + if (ret) + pr_err("%s: failed to register clk notifier\n", __func__); + +out: return cpufreq_register_driver(&omap_driver); }