summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorPrashant Gaikwad <pgaikwad@nvidia.com>2011-04-28 15:48:44 +0530
committerNiket Sirsi <nsirsi@nvidia.com>2011-05-06 20:24:32 -0700
commit6610bc77e97d29d84c1cf55d4090ed57bb320b25 (patch)
treefd783b9e25d151b967664c4c16d01322af9ef87a /arch/arm/mach-tegra
parente6afc94c9bb6ee865a9dc2d546e792cc87ec407f (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 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 <vwadekar@nvidia.com> Tested-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/clock.h7
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c35
2 files changed, 41 insertions, 1 deletions
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
@@ -132,6 +132,13 @@ struct clk {
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;
unsigned long rate;
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 = {