Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

pwm: mediatek: Lock and cache clock rate

This simplifies error handling and reduces the amount of clk_get_rate()
calls.

While touching the clk handling also allocate the clock array as part of
driver data and lock the clock rate to ensure that the output doesn't
change unexpectedly.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Link: https://lore.kernel.org/r/20250725154506.2610172-17-u.kleine-koenig@baylibre.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>

authored by

Uwe Kleine-König and committed by
Uwe Kleine-König
ed5902a2 849b064c

+35 -28
+35 -28
drivers/pwm/pwm-mediatek.c
··· 49 49 * @regs: base address of PWM chip 50 50 * @clk_top: the top clock generator 51 51 * @clk_main: the clock used by PWM core 52 - * @clk_pwms: the clock used by each PWM channel 53 52 * @soc: pointer to chip's platform data 53 + * @clk_pwms: the clock and clkrate used by each PWM channel 54 54 */ 55 55 struct pwm_mediatek_chip { 56 56 void __iomem *regs; 57 57 struct clk *clk_top; 58 58 struct clk *clk_main; 59 - struct clk **clk_pwms; 60 59 const struct pwm_mediatek_of_data *soc; 60 + struct { 61 + struct clk *clk; 62 + unsigned long rate; 63 + } clk_pwms[]; 61 64 }; 62 65 63 66 static inline struct pwm_mediatek_chip * ··· 82 79 if (ret < 0) 83 80 goto disable_clk_top; 84 81 85 - ret = clk_prepare_enable(pc->clk_pwms[hwpwm]); 82 + ret = clk_prepare_enable(pc->clk_pwms[hwpwm].clk); 86 83 if (ret < 0) 87 84 goto disable_clk_main; 88 85 86 + if (!pc->clk_pwms[hwpwm].rate) { 87 + pc->clk_pwms[hwpwm].rate = clk_get_rate(pc->clk_pwms[hwpwm].clk); 88 + 89 + /* 90 + * With the clk running with not more than 1 GHz the 91 + * calculations in .apply() won't overflow. 92 + */ 93 + if (!pc->clk_pwms[hwpwm].rate || 94 + pc->clk_pwms[hwpwm].rate > 1000000000) { 95 + ret = -EINVAL; 96 + goto disable_clk_hwpwm; 97 + } 98 + } 99 + 89 100 return 0; 90 101 102 + disable_clk_hwpwm: 103 + clk_disable_unprepare(pc->clk_pwms[hwpwm].clk); 91 104 disable_clk_main: 92 105 clk_disable_unprepare(pc->clk_main); 93 106 disable_clk_top: ··· 115 96 static void pwm_mediatek_clk_disable(struct pwm_mediatek_chip *pc, 116 97 unsigned int hwpwm) 117 98 { 118 - clk_disable_unprepare(pc->clk_pwms[hwpwm]); 99 + clk_disable_unprepare(pc->clk_pwms[hwpwm].clk); 119 100 clk_disable_unprepare(pc->clk_main); 120 101 clk_disable_unprepare(pc->clk_top); 121 102 } ··· 169 150 if (ret < 0) 170 151 return ret; 171 152 172 - clk_rate = clk_get_rate(pc->clk_pwms[pwm->hwpwm]); 173 - /* 174 - * With the clk running with not more than 1 GHz the calculations below 175 - * won't overflow 176 - */ 177 - if (!clk_rate || clk_rate > 1000000000) { 178 - ret = -EINVAL; 179 - goto out; 180 - } 153 + clk_rate = pc->clk_pwms[pwm->hwpwm].rate; 181 154 182 155 /* Make sure we use the bus clock and not the 26MHz clock */ 183 156 if (pc->soc->pwm_ck_26m_sel_reg) ··· 288 277 u32 clkdiv, cnt_period, cnt_duty; 289 278 unsigned long clk_rate; 290 279 291 - clk_rate = clk_get_rate(pc->clk_pwms[pwm->hwpwm]); 292 - if (!clk_rate) { 293 - ret = -EINVAL; 294 - goto out; 295 - } 280 + clk_rate = pc->clk_pwms[pwm->hwpwm].rate; 296 281 297 282 state->enabled = true; 298 283 state->polarity = PWM_POLARITY_NORMAL; ··· 313 306 state->enabled = false; 314 307 } 315 308 316 - out: 317 309 pwm_mediatek_clk_disable(pc, pwm->hwpwm); 318 310 319 311 return ret; ··· 376 370 377 371 soc = of_device_get_match_data(&pdev->dev); 378 372 379 - chip = devm_pwmchip_alloc(&pdev->dev, soc->num_pwms, sizeof(*pc)); 373 + chip = devm_pwmchip_alloc(&pdev->dev, soc->num_pwms, 374 + sizeof(*pc) + soc->num_pwms * sizeof(*pc->clk_pwms)); 380 375 if (IS_ERR(chip)) 381 376 return PTR_ERR(chip); 382 377 pc = to_pwm_mediatek_chip(chip); ··· 387 380 pc->regs = devm_platform_ioremap_resource(pdev, 0); 388 381 if (IS_ERR(pc->regs)) 389 382 return PTR_ERR(pc->regs); 390 - 391 - pc->clk_pwms = devm_kmalloc_array(&pdev->dev, soc->num_pwms, 392 - sizeof(*pc->clk_pwms), GFP_KERNEL); 393 - if (!pc->clk_pwms) 394 - return -ENOMEM; 395 383 396 384 pc->clk_top = devm_clk_get(&pdev->dev, "top"); 397 385 if (IS_ERR(pc->clk_top)) ··· 403 401 404 402 snprintf(name, sizeof(name), "pwm%d", i + 1); 405 403 406 - pc->clk_pwms[i] = devm_clk_get(&pdev->dev, name); 407 - if (IS_ERR(pc->clk_pwms[i])) 408 - return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_pwms[i]), 404 + pc->clk_pwms[i].clk = devm_clk_get(&pdev->dev, name); 405 + if (IS_ERR(pc->clk_pwms[i].clk)) 406 + return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_pwms[i].clk), 409 407 "Failed to get %s clock\n", name); 408 + 409 + ret = devm_clk_rate_exclusive_get(&pdev->dev, pc->clk_pwms[i].clk); 410 + if (ret) 411 + return dev_err_probe(&pdev->dev, ret, 412 + "Failed to lock clock rate for %s\n", name); 410 413 } 411 414 412 415 ret = pwm_mediatek_init_used_clks(pc);