mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	clk: composite: Use rate_ops.determine_rate when also a mux is available
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> Link: https://lore.kernel.org/r/20211016105022.303413-3-martin.blumenstingl@googlemail.com Tested-by: Alex Bee <knaerzche@gmail.com> Tested-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
		
							parent
							
								
									675c496d0f
								
							
						
					
					
						commit
						6594988fd6
					
				
					 1 changed files with 48 additions and 20 deletions
				
			
		| 
						 | 
					@ -42,6 +42,29 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
 | 
				
			||||||
	return rate_ops->recalc_rate(rate_hw, parent_rate);
 | 
						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,
 | 
					static int clk_composite_determine_rate(struct clk_hw *hw,
 | 
				
			||||||
					struct clk_rate_request *req)
 | 
										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 *rate_hw = composite->rate_hw;
 | 
				
			||||||
	struct clk_hw *mux_hw = composite->mux_hw;
 | 
						struct clk_hw *mux_hw = composite->mux_hw;
 | 
				
			||||||
	struct clk_hw *parent;
 | 
						struct clk_hw *parent;
 | 
				
			||||||
	unsigned long parent_rate;
 | 
					 | 
				
			||||||
	long tmp_rate, best_rate = 0;
 | 
					 | 
				
			||||||
	unsigned long rate_diff;
 | 
						unsigned long rate_diff;
 | 
				
			||||||
	unsigned long best_rate_diff = ULONG_MAX;
 | 
						unsigned long best_rate_diff = ULONG_MAX;
 | 
				
			||||||
	long rate;
 | 
						unsigned long best_rate = 0;
 | 
				
			||||||
	int i;
 | 
						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) {
 | 
						    mux_hw && mux_ops && mux_ops->set_parent) {
 | 
				
			||||||
		req->best_parent_hw = NULL;
 | 
							req->best_parent_hw = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
 | 
							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);
 | 
								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,
 | 
								ret = clk_composite_determine_rate_for_parent(rate_hw,
 | 
				
			||||||
						    &req->best_parent_rate);
 | 
													      &tmp_req,
 | 
				
			||||||
			if (rate < 0)
 | 
													      parent,
 | 
				
			||||||
				return rate;
 | 
													      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;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) {
 | 
							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);
 | 
								parent = clk_hw_get_parent_by_index(mux_hw, i);
 | 
				
			||||||
			if (!parent)
 | 
								if (!parent)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			parent_rate = clk_hw_get_rate(parent);
 | 
								ret = clk_composite_determine_rate_for_parent(rate_hw,
 | 
				
			||||||
 | 
													      &tmp_req,
 | 
				
			||||||
			tmp_rate = rate_ops->round_rate(rate_hw, req->rate,
 | 
													      parent,
 | 
				
			||||||
							&parent_rate);
 | 
													      rate_ops);
 | 
				
			||||||
			if (tmp_rate < 0)
 | 
								if (ret)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			rate_diff = abs(req->rate - tmp_rate);
 | 
								rate_diff = abs(req->rate - tmp_req.rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!rate_diff || !req->best_parent_hw
 | 
								if (!rate_diff || !req->best_parent_hw
 | 
				
			||||||
				       || best_rate_diff > rate_diff) {
 | 
									       || best_rate_diff > rate_diff) {
 | 
				
			||||||
				req->best_parent_hw = parent;
 | 
									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_diff = rate_diff;
 | 
				
			||||||
				best_rate = tmp_rate;
 | 
									best_rate = tmp_req.rate;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!rate_diff)
 | 
								if (!rate_diff)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue