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,
 | 
			
		||||
			    u64 duty_ns, u64 period_ns)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long long prd, div, dty;
 | 
			
		||||
	unsigned int prescaler = 0;
 | 
			
		||||
	unsigned long long prd, dty;
 | 
			
		||||
	unsigned long long prescaler;
 | 
			
		||||
	u32 ccmr, mask, shift;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * .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++;
 | 
			
		||||
		div = prd;
 | 
			
		||||
		do_div(div, prescaler + 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	prd = div;
 | 
			
		||||
	prescaler = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
 | 
			
		||||
					(u64)NSEC_PER_SEC * priv->max_arr);
 | 
			
		||||
	if (prescaler > 0)
 | 
			
		||||
		prescaler -= 1;
 | 
			
		||||
 | 
			
		||||
	if (prescaler > MAX_TIM_PSC)
 | 
			
		||||
		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
 | 
			
		||||
	 * channels are active at the same time we can't change them
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue