diff options
author | Alex Frid <afrid@nvidia.com> | 2011-01-24 22:12:28 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:42:16 -0800 |
commit | ad6e170a82799cdfd7bdf5240f612b36dc151dc0 (patch) | |
tree | c34eec4e2937f1c3cb4b2aaf1a3fd41e81e18ff1 /arch/arm/mach-tegra/clock.c | |
parent | 6ea8f8522a40a988c4926fde70ed1fd159981d8f (diff) |
ARM: tegra: clock: Prevent parent over-clocking
Pre-set clock rate when changing parent to avoid parent over-clocking
during clock initialization from common/board specific tables. Drivers
however, may still hit over-clocking error.
Original-Change-Id: Ib101d85e90ab4c1194ac98680c930eebd8c56b76
Reviewed-on: http://git-master/r/16877
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Original-Change-Id: I307e7eb507d885c381087812d262d56338aab861
Rebase-Id: R1c5fae8b3b048b31b2ed775a602ea33afb5c732e
Diffstat (limited to 'arch/arm/mach-tegra/clock.c')
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 326010e65325..dec8937821bf 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -440,6 +440,28 @@ out: } EXPORT_SYMBOL(clk_round_rate); +static int tegra_clk_clip_rate_for_parent(struct clk *c, struct clk *p) +{ + unsigned long flags, max_rate, old_rate, new_rate; + + clk_lock_save(c, flags); + + max_rate = clk_get_max_rate(c); + new_rate = clk_predict_rate_from_parent(c, p); + old_rate = clk_get_rate_locked(c); + + clk_unlock_restore(c, flags); + + if (new_rate > max_rate) { + u64 rate = max_rate; + rate *= old_rate; + do_div(rate, new_rate); + + return clk_set_rate(c, (unsigned long)rate); + } + return 0; +} + static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table) { struct clk *c; @@ -464,6 +486,14 @@ static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table) } if (c->parent != p) { + ret = tegra_clk_clip_rate_for_parent(c, p); + if (ret) { + pr_warning("Unable to clip rate for parent %s" + " of clock %s: %d\n", + table->parent, table->name, ret); + return -EINVAL; + } + ret = clk_set_parent(c, p); if (ret) { pr_warning("Unable to set parent %s of clock %s: %d\n", |