diff options
author | Prashant Gaikwad <pgaikwad@nvidia.com> | 2011-04-28 15:48:44 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2012-03-22 23:25:29 -0700 |
commit | 7b1b50bf2c73b1baf59ad7413a71d3aad537a66b (patch) | |
tree | f742fb7760b9a9dd655c4c8885b61bdb3d071ad5 /arch/arm/mach-tegra/tegra2_clocks.c | |
parent | 9c3608fe693a5ae3ab9344fff3b74955d199cebd (diff) |
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
Original-Change-Id: Id6d4f9321fe3d49922ace9b50cb6e5114f63b9b5
Reviewed-on: http://git-master/r/29643
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Rebase-Id: Rb722438f9370900d4536ef9e09a6bcad29521ce0
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_clocks.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_clocks.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 32cc91c56b87..aaaf2dd1ce1b 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -231,6 +231,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) { @@ -454,7 +459,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 = { @@ -2065,6 +2095,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 = { |