diff mbox series

[clk-fixes,v1,2/2] clk: composite: Use rate_ops.determine_rate when also a mux is available

Message ID 20211016105022.303413-3-martin.blumenstingl@googlemail.com (mailing list archive)
State Accepted, archived
Headers show
Series Fix clk-composite to support .determine_rate | expand

Commit Message

Martin Blumenstingl Oct. 16, 2021, 10:50 a.m. UTC
Update clk_composite_determine_rate() to use rate_ops.determine_rate
when available in combination with a mux. So far clk_divider_ops provide
both, .round_rate and .determine_rate. Removing the former would make
clk-composite fail silently for example on Rockchip platforms (which
heavily use composite clocks).
Add support for using rate_ops.determine_rate when either
rate_ops.round_rate is not available or both (.round_rate and
.determine_rate) are provided.

Suggested-by: Alex Bee <knaerzche@gmail.com>
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 drivers/clk/clk-composite.c | 68 ++++++++++++++++++++++++++-----------
 1 file changed, 48 insertions(+), 20 deletions(-)

Comments

Stephen Boyd Oct. 18, 2021, 8:01 p.m. UTC | #1
Quoting Martin Blumenstingl (2021-10-16 03:50:22)
> Update clk_composite_determine_rate() to use rate_ops.determine_rate
> when available in combination with a mux. So far clk_divider_ops provide
> both, .round_rate and .determine_rate. Removing the former would make
> clk-composite fail silently for example on Rockchip platforms (which
> heavily use composite clocks).
> Add support for using rate_ops.determine_rate when either
> rate_ops.round_rate is not available or both (.round_rate and
> .determine_rate) are provided.
> 
> Suggested-by: Alex Bee <knaerzche@gmail.com>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---

Applied to clk-next
diff mbox series

Patch

diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index ba8d4d8cf8dd..c04ae0e7e4b4 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -42,6 +42,29 @@  static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
 	return rate_ops->recalc_rate(rate_hw, parent_rate);
 }
 
+static int clk_composite_determine_rate_for_parent(struct clk_hw *rate_hw,
+						   struct clk_rate_request *req,
+						   struct clk_hw *parent_hw,
+						   const struct clk_ops *rate_ops)
+{
+	long rate;
+
+	req->best_parent_hw = parent_hw;
+	req->best_parent_rate = clk_hw_get_rate(parent_hw);
+
+	if (rate_ops->determine_rate)
+		return rate_ops->determine_rate(rate_hw, req);
+
+	rate = rate_ops->round_rate(rate_hw, req->rate,
+				    &req->best_parent_rate);
+	if (rate < 0)
+		return rate;
+
+	req->rate = rate;
+
+	return 0;
+}
+
 static int clk_composite_determine_rate(struct clk_hw *hw,
 					struct clk_rate_request *req)
 {
@@ -51,51 +74,56 @@  static int clk_composite_determine_rate(struct clk_hw *hw,
 	struct clk_hw *rate_hw = composite->rate_hw;
 	struct clk_hw *mux_hw = composite->mux_hw;
 	struct clk_hw *parent;
-	unsigned long parent_rate;
-	long tmp_rate, best_rate = 0;
 	unsigned long rate_diff;
 	unsigned long best_rate_diff = ULONG_MAX;
-	long rate;
-	int i;
+	unsigned long best_rate = 0;
+	int i, ret;
 
-	if (rate_hw && rate_ops && rate_ops->round_rate &&
+	if (rate_hw && rate_ops &&
+	    (rate_ops->determine_rate || rate_ops->round_rate) &&
 	    mux_hw && mux_ops && mux_ops->set_parent) {
 		req->best_parent_hw = NULL;
 
 		if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
+			struct clk_rate_request tmp_req = *req;
+
 			parent = clk_hw_get_parent(mux_hw);
-			req->best_parent_hw = parent;
-			req->best_parent_rate = clk_hw_get_rate(parent);
 
-			rate = rate_ops->round_rate(rate_hw, req->rate,
-						    &req->best_parent_rate);
-			if (rate < 0)
-				return rate;
+			ret = clk_composite_determine_rate_for_parent(rate_hw,
+								      &tmp_req,
+								      parent,
+								      rate_ops);
+			if (ret)
+				return ret;
+
+			req->rate = tmp_req.rate;
+			req->best_parent_rate = tmp_req.best_parent_rate;
 
-			req->rate = rate;
 			return 0;
 		}
 
 		for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) {
+			struct clk_rate_request tmp_req = *req;
+
 			parent = clk_hw_get_parent_by_index(mux_hw, i);
 			if (!parent)
 				continue;
 
-			parent_rate = clk_hw_get_rate(parent);
-
-			tmp_rate = rate_ops->round_rate(rate_hw, req->rate,
-							&parent_rate);
-			if (tmp_rate < 0)
+			ret = clk_composite_determine_rate_for_parent(rate_hw,
+								      &tmp_req,
+								      parent,
+								      rate_ops);
+			if (ret)
 				continue;
 
-			rate_diff = abs(req->rate - tmp_rate);
+			rate_diff = abs(req->rate - tmp_req.rate);
 
 			if (!rate_diff || !req->best_parent_hw
 				       || best_rate_diff > rate_diff) {
 				req->best_parent_hw = parent;
-				req->best_parent_rate = parent_rate;
+				req->best_parent_rate = tmp_req.best_parent_rate;
 				best_rate_diff = rate_diff;
-				best_rate = tmp_rate;
+				best_rate = tmp_req.rate;
 			}
 
 			if (!rate_diff)