Commit 15a02c1f authored by Stephen Boyd's avatar Stephen Boyd Committed by Michael Turquette

clk: Add __clk_mux_determine_rate_closest

Some clock drivers want to find the closest rate on the input of
a mux instead of a rate that's less than or equal to the desired
rate. Add a generic mux function to support this.
Signed-off-by: default avatarStephen Boyd <sboyd@codeaurora.org>
Tested-by: default avatarKenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: default avatarMichael Turquette <mturquette@linaro.org>
parent 52bba980
...@@ -690,14 +690,20 @@ struct clk *__clk_lookup(const char *name) ...@@ -690,14 +690,20 @@ struct clk *__clk_lookup(const char *name)
return NULL; return NULL;
} }
/* static bool mux_is_better_rate(unsigned long rate, unsigned long now,
* Helper for finding best parent to provide a given frequency. This can be used unsigned long best, unsigned long flags)
* 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. if (flags & CLK_MUX_ROUND_CLOSEST)
*/ return abs(now - rate) < abs(best - rate);
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
return now <= rate && now > best;
}
static long
clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p) struct clk_hw **best_parent_p,
unsigned long flags)
{ {
struct clk *clk = hw->clk, *parent, *best_parent = NULL; struct clk *clk = hw->clk, *parent, *best_parent = NULL;
int i, num_parents; int i, num_parents;
...@@ -725,7 +731,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, ...@@ -725,7 +731,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
parent_rate = __clk_round_rate(parent, rate); parent_rate = __clk_round_rate(parent, rate);
else else
parent_rate = __clk_get_rate(parent); parent_rate = __clk_get_rate(parent);
if (parent_rate <= rate && parent_rate > best) { if (mux_is_better_rate(rate, parent_rate, best, flags)) {
best_parent = parent; best_parent = parent;
best = parent_rate; best = parent_rate;
} }
...@@ -738,8 +744,31 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, ...@@ -738,8 +744,31 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
return best; return best;
} }
/*
* 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_hw **best_parent_p)
{
return clk_mux_determine_rate_flags(hw, rate, best_parent_rate,
best_parent_p, 0);
}
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate); EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
return clk_mux_determine_rate_flags(hw, rate, best_parent_rate,
best_parent_p,
CLK_MUX_ROUND_CLOSEST);
}
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
/*** clk api ***/ /*** clk api ***/
void __clk_unprepare(struct clk *clk) void __clk_unprepare(struct clk *clk)
......
...@@ -384,6 +384,8 @@ void clk_unregister_divider(struct clk *clk); ...@@ -384,6 +384,8 @@ void clk_unregister_divider(struct clk *clk);
* register, and mask of mux bits are in higher 16-bit of this register. * register, and mask of mux bits are in higher 16-bit of this register.
* While setting the mux bits, higher 16-bit should also be updated to * While setting the mux bits, higher 16-bit should also be updated to
* indicate changing mux bits. * indicate changing mux bits.
* CLK_MUX_ROUND_CLOSEST - Use the parent rate that is closest to the desired
* frequency.
*/ */
struct clk_mux { struct clk_mux {
struct clk_hw hw; struct clk_hw hw;
...@@ -398,7 +400,8 @@ struct clk_mux { ...@@ -398,7 +400,8 @@ struct clk_mux {
#define CLK_MUX_INDEX_ONE BIT(0) #define CLK_MUX_INDEX_ONE BIT(0)
#define CLK_MUX_INDEX_BIT BIT(1) #define CLK_MUX_INDEX_BIT BIT(1)
#define CLK_MUX_HIWORD_MASK BIT(2) #define CLK_MUX_HIWORD_MASK BIT(2)
#define CLK_MUX_READ_ONLY BIT(3) /* mux setting cannot be changed */ #define CLK_MUX_READ_ONLY BIT(3) /* mux can't be changed */
#define CLK_MUX_ROUND_CLOSEST BIT(4)
extern const struct clk_ops clk_mux_ops; extern const struct clk_ops clk_mux_ops;
extern const struct clk_ops clk_mux_ro_ops; extern const struct clk_ops clk_mux_ro_ops;
...@@ -556,6 +559,9 @@ struct clk *__clk_lookup(const char *name); ...@@ -556,6 +559,9 @@ struct clk *__clk_lookup(const char *name);
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p); struct clk_hw **best_parent_p);
long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p);
/* /*
* FIXME clock api without lock protection * FIXME clock api without lock protection
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment