提交 421186e7 编写于 作者: C Colin Cross

ARM: tegra: clock: Round rate before setting rate

Call the clock's round_rate op, if it exists, before calling
the set_rate op.  This will help later when dvfs is added,
dvfs needs to know what the final rate will be before the
frequency changes.

Also requires fixes to the round rate functions to ensure
calling round rate and then set rate will not cause the
frequency to be rounded down twice.  When picking clock
divider values, the clock framework picks the closest
frequency that is lower than the requested frequency.  If
the new frequency calculated from the divider value is
rounded down, and then passed to set_rate, it will get
rounded down again, possibly resulting in a frequency two
steps lower than the original requested frequency.

Fix the problem by rounding up when calculating the frequency
coming out of a clock divider, so if that frequency is
requested again, the same divider value will be picked.
Signed-off-by: NColin Cross <ccross@android.com>
Acked-by: NOlof Johansson <olof@lixom.net>
上级 78f379b5
...@@ -86,6 +86,7 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p) ...@@ -86,6 +86,7 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
if (c->mul != 0 && c->div != 0) { if (c->mul != 0 && c->div != 0) {
rate *= c->mul; rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div); do_div(rate, c->div);
} }
...@@ -240,12 +241,23 @@ EXPORT_SYMBOL(clk_get_parent); ...@@ -240,12 +241,23 @@ EXPORT_SYMBOL(clk_get_parent);
int clk_set_rate_locked(struct clk *c, unsigned long rate) int clk_set_rate_locked(struct clk *c, unsigned long rate)
{ {
long new_rate;
if (!c->ops || !c->ops->set_rate) if (!c->ops || !c->ops->set_rate)
return -ENOSYS; return -ENOSYS;
if (rate > c->max_rate) if (rate > c->max_rate)
rate = c->max_rate; rate = c->max_rate;
if (c->ops && c->ops->round_rate) {
new_rate = c->ops->round_rate(c, rate);
if (new_rate < 0)
return new_rate;
rate = new_rate;
}
return c->ops->set_rate(c, rate); return c->ops->set_rate(c, rate);
} }
......
...@@ -898,9 +898,9 @@ static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate) ...@@ -898,9 +898,9 @@ static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
divider = clk_div71_get_divider(parent_rate, rate); divider = clk_div71_get_divider(parent_rate, rate);
if (divider < 0) if (divider < 0)
return divider; return divider;
return parent_rate * 2 / (divider + 2); return DIV_ROUND_UP(parent_rate * 2, divider + 2);
} else if (c->flags & DIV_2) { } else if (c->flags & DIV_2) {
return parent_rate / 2; return DIV_ROUND_UP(parent_rate, 2);
} }
return -EINVAL; return -EINVAL;
} }
...@@ -1092,12 +1092,12 @@ static long tegra2_periph_clk_round_rate(struct clk *c, ...@@ -1092,12 +1092,12 @@ static long tegra2_periph_clk_round_rate(struct clk *c,
if (divider < 0) if (divider < 0)
return divider; return divider;
return parent_rate * 2 / (divider + 2); return DIV_ROUND_UP(parent_rate * 2, divider + 2);
} else if (c->flags & DIV_U16) { } else if (c->flags & DIV_U16) {
divider = clk_div16_get_divider(parent_rate, rate); divider = clk_div16_get_divider(parent_rate, rate);
if (divider < 0) if (divider < 0)
return divider; return divider;
return parent_rate / (divider + 1); return DIV_ROUND_UP(parent_rate, divider + 1);
} }
return -EINVAL; return -EINVAL;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册