From patchwork Fri Oct 29 12:42:16 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 290192 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o9TCg8L2022997 for ; Fri, 29 Oct 2010 12:42:08 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1761461Ab0J2MmH (ORCPT ); Fri, 29 Oct 2010 08:42:07 -0400 Received: from mailout-de.gmx.net ([213.165.64.23]:49085 "HELO mail.gmx.net" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with SMTP id S1756141Ab0J2MmG (ORCPT ); Fri, 29 Oct 2010 08:42:06 -0400 Received: (qmail invoked by alias); 29 Oct 2010 12:42:03 -0000 Received: from p508989BA.dip0.t-ipconnect.de (EHLO axis700.grange) [80.137.137.186] by mail.gmx.net (mp009) with SMTP; 29 Oct 2010 14:42:03 +0200 X-Authenticated: #20450766 X-Provags-ID: V01U2FsdGVkX19dFsFw9oNdokQuawepuTy+UvVFNgXQij7ZBZPVTN fVwi2AukrQEfPJ Received: from lyakh (helo=localhost) by axis700.grange with local-esmtp (Exim 4.63) (envelope-from ) id 1PBoHg-0006PE-BI; Fri, 29 Oct 2010 14:42:16 +0200 Date: Fri, 29 Oct 2010 14:42:16 +0200 (CEST) From: Guennadi Liakhovetski To: Paul Mundt cc: linux-sh@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH/RFC 3/3 v2] ARM: mach-shmobile: implement parent clock optimization In-Reply-To: <20101028065304.GB16806@linux-sh.org> Message-ID: References: <20101028002802.GA10365@linux-sh.org> <20101028065304.GB16806@linux-sh.org> MIME-Version: 1.0 X-Y-GMX-Trusted: 0 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 (demeter1.kernel.org [140.211.167.41]); Fri, 29 Oct 2010 12:42:08 +0000 (UTC) diff --git a/drivers/sh/clk.c b/drivers/sh/clk.c index 5d84ada..412620b 100644 --- a/drivers/sh/clk.c +++ b/drivers/sh/clk.c @@ -390,6 +390,79 @@ long clk_round_rate(struct clk *clk, unsigned long rate) } EXPORT_SYMBOL_GPL(clk_round_rate); +long clk_round_parent(struct clk *clk, unsigned long target, + unsigned long *best_freq, unsigned long *parent_freq, + unsigned int div_min, unsigned int div_max) +{ + struct cpufreq_frequency_table *freq, *best = NULL; + unsigned long error = ULONG_MAX, freq_high, freq_low, div; + struct clk *parent = clk_get_parent(clk); + + if (!parent) { + *parent_freq = 0; + *best_freq = clk_round_rate(clk, target); + return abs(target - *best_freq); + } + + for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END; + freq++) { + if (freq->frequency == CPUFREQ_ENTRY_INVALID) + continue; + + if (unlikely(freq->frequency <= target * div_min)) { + unsigned long freq_max = (freq->frequency + div_min / 2) / div_min; + if (error > target - freq_max) { + error = target - freq_max; + best = freq; + if (best_freq) + *best_freq = freq_max; + } + if (!error) + break; + continue; + } + + if (unlikely(freq->frequency >= target * div_max)) { + unsigned long freq_min = (freq->frequency + div_max / 2) / div_max; + if (error > target - freq_min) { + error = freq_min - target; + best = freq; + if (best_freq) + *best_freq = freq_min; + } + if (!error) + break; + continue; + } + + + div = freq->frequency / target; + freq_high = freq->frequency / div; + freq_low = freq->frequency / (div + 1); + if (freq_high - target < error) { + error = freq_high - target; + best = freq; + if (best_freq) + *best_freq = freq_high; + } + if (target - freq_low < error) { + error = target - freq_low; + best = freq; + if (best_freq) + *best_freq = freq_low; + } + pr_debug("%u / %lu = %lu, / %lu = %lu, best %lu, parent %u\n", + freq->frequency, div, freq_high, div + 1, freq_low, + *best_freq, best->frequency); + if (!error) + break; + } + if (parent_freq) + *parent_freq = best->frequency; + return error; +} +EXPORT_SYMBOL_GPL(clk_round_parent); + #ifdef CONFIG_PM static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) { diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index 875ce50..d370057 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h @@ -111,6 +111,10 @@ int clk_rate_table_find(struct clk *clk, struct cpufreq_frequency_table *freq_table, unsigned long rate); +long clk_round_parent(struct clk *clk, unsigned long target, + unsigned long *best_freq, unsigned long *parent_freq, + unsigned int div_min, unsigned int div_max); + #define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags) \ { \ .parent = _parent, \