Skip to content

Commit

Permalink
ARM: OMAP2+: clock: allow omap2_dpll_round_rate() to round to next-lo…
Browse files Browse the repository at this point in the history
…west rate

Change the behavior of omap2_dpll_round_rate() to round to either the
exact rate requested, or the next lowest rate that the clock is able to
provide.

This is not an ideal fix, but is intended to provide a relatively safe
way for drivers to set PLL rates, until a better solution can be
implemented.

For the time being, omap3_noncore_dpll_set_rate() is still allowed to
set its rate to something other than what the caller requested; but will
warn when this occurs.

Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
  • Loading branch information
Paul Walmsley committed Jul 25, 2014
1 parent a497c3b commit 0a26344
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 9 deletions.
28 changes: 21 additions & 7 deletions arch/arm/mach-omap2/clkt_dpll.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,13 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
int m, n, r, scaled_max_m;
int min_delta_m = INT_MAX, min_delta_n = INT_MAX;
unsigned long scaled_rt_rp;
unsigned long new_rate = 0;
struct dpll_data *dd;
unsigned long ref_rate;
long delta;
long prev_min_delta = LONG_MAX;
const char *clk_name;

if (!clk || !clk->dpll_data)
Expand Down Expand Up @@ -342,23 +345,34 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
if (r == DPLL_MULT_UNDERFLOW)
continue;

/* skip rates above our target rate */
delta = target_rate - new_rate;
if (delta < 0)
continue;

if (delta < prev_min_delta) {
prev_min_delta = delta;
min_delta_m = m;
min_delta_n = n;
}

pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n",
clk_name, m, n, new_rate);

if (target_rate == new_rate) {
dd->last_rounded_m = m;
dd->last_rounded_n = n;
dd->last_rounded_rate = target_rate;
if (delta == 0)
break;
}
}

if (target_rate != new_rate) {
if (prev_min_delta == LONG_MAX) {
pr_debug("clock: %s: cannot round to rate %lu\n",
clk_name, target_rate);
return ~0;
}

return target_rate;
dd->last_rounded_m = min_delta_m;
dd->last_rounded_n = min_delta_n;
dd->last_rounded_rate = target_rate - prev_min_delta;

return dd->last_rounded_rate;
}

13 changes: 11 additions & 2 deletions arch/arm/mach-omap2/dpll3xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
struct clk *new_parent = NULL;
unsigned long rrate;
u16 freqsel = 0;
struct dpll_data *dd;
int ret;
Expand Down Expand Up @@ -505,8 +506,16 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
__clk_prepare(dd->clk_ref);
clk_enable(dd->clk_ref);

if (dd->last_rounded_rate != rate)
rate = __clk_round_rate(hw->clk, rate);
/* XXX this check is probably pointless in the CCF context */
if (dd->last_rounded_rate != rate) {
rrate = __clk_round_rate(hw->clk, rate);
if (rrate != rate) {
pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
__func__, __clk_get_name(hw->clk),
rrate, rate);
rate = rrate;
}
}

if (dd->last_rounded_rate == 0)
return -EINVAL;
Expand Down

0 comments on commit 0a26344

Please sign in to comment.