Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+38 −9
Original line number Diff line number Diff line
@@ -690,14 +690,20 @@ 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,
static bool mux_is_better_rate(unsigned long rate, unsigned long now,
			   unsigned long best, unsigned long flags)
{
	if (flags & CLK_MUX_ROUND_CLOSEST)
		return abs(now - rate) < abs(best - 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,
			      struct clk_hw **best_parent_p)
			     struct clk_hw **best_parent_p,
			     unsigned long flags)
{
	struct clk *clk = hw->clk, *parent, *best_parent = NULL;
	int i, num_parents;
@@ -725,7 +731,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
			parent_rate = __clk_round_rate(parent, rate);
		else
			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_rate;
		}
@@ -738,8 +744,31 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,

	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);

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        ***/

void __clk_unprepare(struct clk *clk)
+7 −1
Original line number Diff line number Diff line
@@ -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.
 *	While setting the mux bits, higher 16-bit should also be updated to
 *	indicate changing mux bits.
 * CLK_MUX_ROUND_CLOSEST - Use the parent rate that is closest to the desired
 *	frequency.
 */
struct clk_mux {
	struct clk_hw	hw;
@@ -398,7 +400,8 @@ struct clk_mux {
#define CLK_MUX_INDEX_ONE		BIT(0)
#define CLK_MUX_INDEX_BIT		BIT(1)
#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_ro_ops;
@@ -556,6 +559,9 @@ 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_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