clk: clk-mux: implement remuxing on set_rate
Implement clk-mux remuxing if the CLK_SET_RATE_NO_REPARENT flag isn't set. This implements determine_rate for clk-mux to propagate to each parent and to choose the best one (like clk-divider this chooses the parent which provides the fastest rate <= the requested rate). The determine_rate op is implemented as a core helper function so that it can be easily used by more complex clocks which incorporate muxes. Signed-off-by: James Hogan <james.hogan@imgtec.com> Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Cc: Mike Turquette <mturquette@linaro.org> Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Mike Turquette <mturquette@linaro.org>
This commit is contained in:
parent
819c1de344
commit
e366fdd725
@ -104,6 +104,7 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
const struct clk_ops clk_mux_ops = {
|
||||
.get_parent = clk_mux_get_parent,
|
||||
.set_parent = clk_mux_set_parent,
|
||||
.determine_rate = __clk_mux_determine_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_mux_ops);
|
||||
|
||||
|
@ -692,6 +692,55 @@ struct clk *__clk_lookup(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper for finding best parent to provide a given frequency. This can be used
|
||||
* directly as a determine_rate callback (e.g. for a mux), or from a more
|
||||
* complex clock that may combine a mux with other operations.
|
||||
*/
|
||||
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk **best_parent_p)
|
||||
{
|
||||
struct clk *clk = hw->clk, *parent, *best_parent = NULL;
|
||||
int i, num_parents;
|
||||
unsigned long parent_rate, best = 0;
|
||||
|
||||
/* if NO_REPARENT flag set, pass through to current parent */
|
||||
if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
|
||||
parent = clk->parent;
|
||||
if (clk->flags & CLK_SET_RATE_PARENT)
|
||||
best = __clk_round_rate(parent, rate);
|
||||
else if (parent)
|
||||
best = __clk_get_rate(parent);
|
||||
else
|
||||
best = __clk_get_rate(clk);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* find the parent that can provide the fastest rate <= rate */
|
||||
num_parents = clk->num_parents;
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
parent = clk_get_parent_by_index(clk, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
if (clk->flags & CLK_SET_RATE_PARENT)
|
||||
parent_rate = __clk_round_rate(parent, rate);
|
||||
else
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
if (parent_rate <= rate && parent_rate > best) {
|
||||
best_parent = parent;
|
||||
best = parent_rate;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (best_parent)
|
||||
*best_parent_p = best_parent;
|
||||
*best_parent_rate = best;
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/*** clk api ***/
|
||||
|
||||
void __clk_unprepare(struct clk *clk)
|
||||
|
@ -436,6 +436,9 @@ unsigned long __clk_get_flags(struct clk *clk);
|
||||
bool __clk_is_prepared(struct clk *clk);
|
||||
bool __clk_is_enabled(struct clk *clk);
|
||||
struct clk *__clk_lookup(const char *name);
|
||||
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk **best_parent_p);
|
||||
|
||||
/*
|
||||
* FIXME clock api without lock protection
|
||||
|
Loading…
Reference in New Issue
Block a user