From 6610bc77e97d29d84c1cf55d4090ed57bb320b25 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Thu, 28 Apr 2011 15:48:44 +0530 Subject: ARM: tegra: clocks: make pclk div dynamic dynamic changing of pclk divider to follow APB clock minimum frequency requirements with respect to sclk frequency. Bug 819796 Reviewed-on: http://git-master/r/29643 (cherry picked from commit c5ed952608ff2e3ffdcba99295f8892dac1506c0) Change-Id: Iec403b137fa001ff401fd14990040889ec679eca Reviewed-on: http://git-master/r/30315 Reviewed-by: Varun Wadekar Tested-by: Varun Wadekar Reviewed-by: Bharat Nihalani --- arch/arm/mach-tegra/clock.h | 7 +++++++ arch/arm/mach-tegra/tegra2_clocks.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index 9337f6afc4c9..6a1c5ba96a8a 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h @@ -131,6 +131,13 @@ struct clk { struct clk *main; struct clk *backup; } cpu; + struct { + struct clk *pclk; + struct clk *hclk; + struct clk *sclk_low; + struct clk *sclk_high; + unsigned long threshold; + } system; struct { struct list_head node; bool enabled; diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 16df52cd861d..bc3e56bc8f33 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -221,6 +221,11 @@ static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate) return divider_u16 - 1; } +static inline int clk_set_div(struct clk *c, int n) +{ + return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n); +} + /* clk_m functions */ static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c) { @@ -456,7 +461,32 @@ static long tegra2_vsclk_round_rate(struct clk *c, unsigned long rate) static int tegra2_vsclk_set_rate(struct clk *c, unsigned long rate) { - return clk_set_rate(c->parent, rate); + int ret; + + if (rate >= c->u.system.pclk->min_rate * 2) { + ret = clk_set_div(c->u.system.pclk, 2); + if (ret) { + pr_err("Failed to set 1 : 2 pclk divider\n"); + return ret; + } + } + + ret = clk_set_rate(c->parent, rate); + if (ret) { + pr_err("Failed to set sclk source %s to %lu\n", + c->parent->name, rate); + return ret; + } + + if (rate < c->u.system.pclk->min_rate * 2) { + ret = clk_set_div(c->u.system.pclk, 1); + if (ret) { + pr_err("Failed to set 1 : 1 pclk divider\n"); + return ret; + } + } + + return 0; } static struct clk_ops tegra_vsclk_ops = { @@ -1885,6 +1915,9 @@ static struct clk tegra_clk_virtual_sclk = { .name = "vsclk", .parent = &tegra_clk_sclk, .ops = &tegra_vsclk_ops, + .u.system = { + .pclk = &tegra_clk_pclk, + }, }; static struct clk tegra_clk_blink = { -- cgit v1.2.3