forked from mirrors/linux
		
	pwm: stm32: Calculate prescaler with a division instead of a loop
Instead of looping over increasing values for the prescaler and testing if it's big enough, calculate the value using a single division. Link: https://lore.kernel.org/r/498a44b313a6c0a84ccddd03cd67aadaaaf7daf2.1710711976.git.u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
This commit is contained in:
		
							parent
							
								
									d44d635635
								
							
						
					
					
						commit
						8002fbeef1
					
				
					 1 changed files with 17 additions and 13 deletions
				
			
		| 
						 | 
					@ -311,29 +311,33 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
 | 
				
			||||||
static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
 | 
					static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
 | 
				
			||||||
			    u64 duty_ns, u64 period_ns)
 | 
								    u64 duty_ns, u64 period_ns)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long long prd, div, dty;
 | 
						unsigned long long prd, dty;
 | 
				
			||||||
	unsigned int prescaler = 0;
 | 
						unsigned long long prescaler;
 | 
				
			||||||
	u32 ccmr, mask, shift;
 | 
						u32 ccmr, mask, shift;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so
 | 
						 * .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so
 | 
				
			||||||
	 * this won't overflow.
 | 
						 * the calculations here won't overflow.
 | 
				
			||||||
 | 
						 * First we need to find the minimal value for prescaler such that
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *        period_ns * clkrate
 | 
				
			||||||
 | 
						 *   ------------------------------
 | 
				
			||||||
 | 
						 *   NSEC_PER_SEC * (prescaler + 1)
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * isn't bigger than max_arr.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	div = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
 | 
					 | 
				
			||||||
				  NSEC_PER_SEC);
 | 
					 | 
				
			||||||
	prd = div;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (div > priv->max_arr) {
 | 
						prescaler = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
 | 
				
			||||||
		prescaler++;
 | 
										(u64)NSEC_PER_SEC * priv->max_arr);
 | 
				
			||||||
		div = prd;
 | 
						if (prescaler > 0)
 | 
				
			||||||
		do_div(div, prescaler + 1);
 | 
							prescaler -= 1;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	prd = div;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (prescaler > MAX_TIM_PSC)
 | 
						if (prescaler > MAX_TIM_PSC)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prd = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
 | 
				
			||||||
 | 
									  (u64)NSEC_PER_SEC * (prescaler + 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * All channels share the same prescaler and counter so when two
 | 
						 * All channels share the same prescaler and counter so when two
 | 
				
			||||||
	 * channels are active at the same time we can't change them
 | 
						 * channels are active at the same time we can't change them
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue