diff options
| author | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2024-05-28 22:21:34 +0200 | 
|---|---|---|
| committer | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2024-05-28 22:21:34 +0200 | 
| commit | f73a058be5d70dd81a43f16b2bbff4b1576a7af8 (patch) | |
| tree | b7959c01cf7a5d95c7c4d5b61929ff9123370322 /drivers/pwm/pwm-stm32.c | |
| parent | 6cb05d89fd62a76a9b74bd16211fb0930e89fea8 (diff) | |
| parent | 3e049b6b8f32f25c6967f4cffd8eac6e1e5316f6 (diff) | |
Merge remote-tracking branch 'drm/drm-fixes' into drm-misc-fixes
v6.10-rc1 is released, forward from v6.9
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Diffstat (limited to 'drivers/pwm/pwm-stm32.c')
| -rw-r--r-- | drivers/pwm/pwm-stm32.c | 60 | 
1 files changed, 40 insertions, 20 deletions
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 0c028d17c075..a2f231d13a9f 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -309,29 +309,35 @@ unlock:  }  static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch, -			    int duty_ns, int period_ns) +			    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; -	/* Period and prescaler values depends on clock rate */ -	div = (unsigned long long)clk_get_rate(priv->clk) * period_ns; - -	do_div(div, NSEC_PER_SEC); -	prd = div; - -	while (div > priv->max_arr) { -		prescaler++; -		div = prd; -		do_div(div, prescaler + 1); -	} +	/* +	 * .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so +	 * 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. +	 */ -	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 @@ -351,8 +357,8 @@ static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,  	regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE);  	/* Calculate the duty cycles */ -	dty = prd * duty_ns; -	do_div(dty, period_ns); +	dty = mul_u64_u64_div_u64(duty_ns, clk_get_rate(priv->clk), +				  (u64)NSEC_PER_SEC * (prescaler + 1));  	regmap_write(priv->regmap, TIM_CCR1 + 4 * ch, dty); @@ -648,14 +654,27 @@ static int stm32_pwm_probe(struct platform_device *pdev)  	priv->max_arr = ddata->max_arr;  	if (!priv->regmap || !priv->clk) -		return -EINVAL; +		return dev_err_probe(dev, -EINVAL, "Failed to get %s\n", +				     priv->regmap ? "clk" : "regmap");  	ret = stm32_pwm_probe_breakinputs(priv, np);  	if (ret) -		return ret; +		return dev_err_probe(dev, ret, +				     "Failed to configure breakinputs\n");  	stm32_pwm_detect_complementary(priv); +	ret = devm_clk_rate_exclusive_get(dev, priv->clk); +	if (ret) +		return dev_err_probe(dev, ret, "Failed to lock clock\n"); + +	/* +	 * With the clk running with not more than 1 GHz the calculations in +	 * .apply() won't overflow. +	 */ +	if (clk_get_rate(priv->clk) > 1000000000) +		return dev_err_probe(dev, -EINVAL, "Failed to lock clock\n"); +  	chip->ops = &stm32pwm_ops;  	/* Initialize clock refcount to number of enabled PWM channels. */ @@ -664,7 +683,8 @@ static int stm32_pwm_probe(struct platform_device *pdev)  	ret = devm_pwmchip_add(dev, chip);  	if (ret < 0) -		return ret; +		return dev_err_probe(dev, ret, +				     "Failed to register pwmchip\n");  	platform_set_drvdata(pdev, chip);  | 
