You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
120 lines
4.3 KiB
120 lines
4.3 KiB
From 15a02c1f6dd7c2bb150c61d00ffb33f584ff2288 Mon Sep 17 00:00:00 2001
|
|
From: Stephen Boyd <sboyd@codeaurora.org>
|
|
Date: Mon, 19 Jan 2015 18:05:28 -0800
|
|
Subject: [PATCH] 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: Stephen Boyd <sboyd@codeaurora.org>
|
|
Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
|
|
Signed-off-by: Michael Turquette <mturquette@linaro.org>
|
|
---
|
|
drivers/clk/clk.c | 47 +++++++++++++++++++++++++++++++++++---------
|
|
include/linux/clk-provider.h | 8 +++++++-
|
|
2 files changed, 45 insertions(+), 10 deletions(-)
|
|
|
|
--- a/drivers/clk/clk.c
|
|
+++ b/drivers/clk/clk.c
|
|
@@ -695,14 +695,20 @@ struct clk *__clk_lookup(const char *nam
|
|
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)
|
|
+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 **best_parent_p,
|
|
+ unsigned long flags)
|
|
{
|
|
struct clk *clk = hw->clk, *parent, *best_parent = NULL;
|
|
int i, num_parents;
|
|
@@ -730,7 +736,7 @@ long __clk_mux_determine_rate(struct clk
|
|
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;
|
|
}
|
|
@@ -743,8 +749,31 @@ out:
|
|
|
|
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 **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 **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)
|
|
--- a/include/linux/clk-provider.h
|
|
+++ b/include/linux/clk-provider.h
|
|
@@ -382,6 +382,8 @@ struct clk *clk_register_divider_table(s
|
|
* 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;
|
|
@@ -396,7 +398,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;
|
|
@@ -554,6 +557,9 @@ struct clk *__clk_lookup(const char *nam
|
|
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|
unsigned long *best_parent_rate,
|
|
struct clk **best_parent_p);
|
|
+long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
|
|
+ unsigned long *best_parent_rate,
|
|
+ struct clk **best_parent_p);
|
|
|
|
/*
|
|
* FIXME clock api without lock protection
|
|
|