clk: divider: Make divider_round_rate take the parent clock

So far, divider_round_rate only considers the parent clock returned by
clk_hw_get_parent.

This works fine on clocks that have a single parents, this doesn't work on
muxes, since we will only consider the first parent, while other parents
may totally be able to provide a better combination.

Clocks in that case cannot use divider_round_rate, so would have to come up
with a very similar logic to work around it. Instead of having to do
something like this, and duplicate that logic everywhere, create a
divider_round_rate parent to allow caller to give an additional parameter
for the parent clock to consider.

Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
This commit is contained in:
Maxime Ripard 2017-05-17 09:40:30 +02:00
parent b042e42fee
commit 22833a9165
2 changed files with 23 additions and 12 deletions

View File

@ -275,7 +275,8 @@ static int _next_div(const struct clk_div_table *table, int div,
return div; return div;
} }
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, static int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent,
unsigned long rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
const struct clk_div_table *table, u8 width, const struct clk_div_table *table, u8 width,
unsigned long flags) unsigned long flags)
@ -314,8 +315,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
*best_parent_rate = parent_rate_saved; *best_parent_rate = parent_rate_saved;
return i; return i;
} }
parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), parent_rate = clk_hw_round_rate(parent, rate * i);
rate * i);
now = DIV_ROUND_UP_ULL((u64)parent_rate, i); now = DIV_ROUND_UP_ULL((u64)parent_rate, i);
if (_is_best_div(rate, now, best, flags)) { if (_is_best_div(rate, now, best, flags)) {
bestdiv = i; bestdiv = i;
@ -326,23 +326,24 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (!bestdiv) { if (!bestdiv) {
bestdiv = _get_maxdiv(table, width, flags); bestdiv = _get_maxdiv(table, width, flags);
*best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1); *best_parent_rate = clk_hw_round_rate(parent, 1);
} }
return bestdiv; return bestdiv;
} }
long divider_round_rate(struct clk_hw *hw, unsigned long rate, long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
unsigned long *prate, const struct clk_div_table *table, unsigned long rate, unsigned long *prate,
u8 width, unsigned long flags) const struct clk_div_table *table,
u8 width, unsigned long flags)
{ {
int div; int div;
div = clk_divider_bestdiv(hw, rate, prate, table, width, flags); div = clk_divider_bestdiv(hw, parent, rate, prate, table, width, flags);
return DIV_ROUND_UP_ULL((u64)*prate, div); return DIV_ROUND_UP_ULL((u64)*prate, div);
} }
EXPORT_SYMBOL_GPL(divider_round_rate); EXPORT_SYMBOL_GPL(divider_round_rate_parent);
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate) unsigned long *prate)

View File

@ -412,9 +412,10 @@ extern const struct clk_ops clk_divider_ro_ops;
unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
unsigned int val, const struct clk_div_table *table, unsigned int val, const struct clk_div_table *table,
unsigned long flags); unsigned long flags);
long divider_round_rate(struct clk_hw *hw, unsigned long rate, long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
unsigned long *prate, const struct clk_div_table *table, unsigned long rate, unsigned long *prate,
u8 width, unsigned long flags); const struct clk_div_table *table,
u8 width, unsigned long flags);
int divider_get_val(unsigned long rate, unsigned long parent_rate, int divider_get_val(unsigned long rate, unsigned long parent_rate,
const struct clk_div_table *table, u8 width, const struct clk_div_table *table, u8 width,
unsigned long flags); unsigned long flags);
@ -757,6 +758,15 @@ static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src)
dst->core = src->core; dst->core = src->core;
} }
static inline long divider_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate,
const struct clk_div_table *table,
u8 width, unsigned long flags)
{
return divider_round_rate_parent(hw, clk_hw_get_parent(hw),
rate, prate, table, width, flags);
}
/* /*
* FIXME clock api without lock protection * FIXME clock api without lock protection
*/ */