[PATCH 7/8] pwm: mediatek: Lock and cache clock rate
Uwe Kleine-König
u.kleine-koenig at baylibre.com
Tue Jul 8 10:18:37 PDT 2025
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 at baylibre.com>
---
drivers/pwm/pwm-mediatek.c | 64 +++++++++++++++++++++-----------------
1 file changed, 35 insertions(+), 29 deletions(-)
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index d7801e6df6ba..c48d46124059 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -49,15 +49,18 @@ struct pwm_mediatek_of_data {
* @regs: base address of PWM chip
* @clk_top: the top clock generator
* @clk_main: the clock used by PWM core
- * @clk_pwms: the clock used by each PWM channel
* @soc: pointer to chip's platform data
+ * @clk_pwms: the clock and clkrate used by each PWM channel
*/
struct pwm_mediatek_chip {
void __iomem *regs;
struct clk *clk_top;
struct clk *clk_main;
- struct clk **clk_pwms;
const struct pwm_mediatek_of_data *soc;
+ struct {
+ struct clk *clk;
+ unsigned long rate;
+ } clk_pwms[];
};
static inline struct pwm_mediatek_chip *
@@ -79,12 +82,28 @@ static int pwm_mediatek_clk_enable(struct pwm_mediatek_chip *pc,
if (ret < 0)
goto disable_clk_top;
- ret = clk_prepare_enable(pc->clk_pwms[hwpwm]);
+ ret = clk_prepare_enable(pc->clk_pwms[hwpwm].clk);
if (ret < 0)
goto disable_clk_main;
+ if (!pc->clk_pwms[hwpwm].rate) {
+ pc->clk_pwms[hwpwm].rate = clk_get_rate(pc->clk_pwms[hwpwm].clk);
+
+ /*
+ * With the clk running with not more than 1 GHz the
+ * calculations in .apply() won't overflow.
+ */
+ if (!pc->clk_pwms[hwpwm].rate ||
+ pc->clk_pwms[hwpwm].rate > 1000000000) {
+ ret = -EINVAL;
+ goto disable_clk_hwpwm;
+ }
+ }
+
return 0;
+disable_clk_hwpwm:
+ clk_disable_unprepare(pc->clk_pwms[hwpwm].clk);
disable_clk_main:
clk_disable_unprepare(pc->clk_main);
disable_clk_top:
@@ -96,7 +115,7 @@ static int pwm_mediatek_clk_enable(struct pwm_mediatek_chip *pc,
static void pwm_mediatek_clk_disable(struct pwm_mediatek_chip *pc,
unsigned int hwpwm)
{
- clk_disable_unprepare(pc->clk_pwms[hwpwm]);
+ clk_disable_unprepare(pc->clk_pwms[hwpwm].clk);
clk_disable_unprepare(pc->clk_main);
clk_disable_unprepare(pc->clk_top);
}
@@ -130,15 +149,7 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
if (ret < 0)
return ret;
- clk_rate = clk_get_rate(pc->clk_pwms[pwm->hwpwm]);
- /*
- * With the clk running with not more than 1 GHz the calculations below
- * won't overflow
- */
- if (!clk_rate || clk_rate > 1000000000) {
- ret = -EINVAL;
- goto out;
- }
+ clk_rate = pc->clk_pwms[pwm->hwpwm].rate;
/* Make sure we use the bus clock and not the 26MHz clock */
if (pc->soc->pwm_ck_26m_sel_reg)
@@ -180,7 +191,6 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
pwm_mediatek_writel(pc, pwm->hwpwm, reg_width, cnt_period);
pwm_mediatek_writel(pc, pwm->hwpwm, reg_thres, cnt_duty);
-out:
pwm_mediatek_clk_disable(pc, pwm->hwpwm);
return ret;
@@ -266,11 +276,7 @@ static int pwm_mediatek_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
u32 clkdiv, cnt_period, cnt_duty;
unsigned long clk_rate;
- clk_rate = clk_get_rate(pc->clk_pwms[pwm->hwpwm]);
- if (!clk_rate) {
- ret = -EINVAL;
- goto out;
- }
+ clk_rate = pc->clk_pwms[pwm->hwpwm].rate;
state->enabled = true;
state->polarity = PWM_POLARITY_NORMAL;
@@ -295,7 +301,6 @@ static int pwm_mediatek_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
state->enabled = false;
}
-out:
pwm_mediatek_clk_disable(pc, pwm->hwpwm);
return ret;
@@ -359,7 +364,8 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
soc = of_device_get_match_data(&pdev->dev);
- chip = devm_pwmchip_alloc(&pdev->dev, soc->num_pwms, sizeof(*pc));
+ chip = devm_pwmchip_alloc(&pdev->dev, soc->num_pwms,
+ sizeof(*pc) + soc->num_pwms * sizeof(*pc->clk_pwms));
if (IS_ERR(chip))
return PTR_ERR(chip);
pc = to_pwm_mediatek_chip(chip);
@@ -370,11 +376,6 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
if (IS_ERR(pc->regs))
return PTR_ERR(pc->regs);
- pc->clk_pwms = devm_kmalloc_array(&pdev->dev, soc->num_pwms,
- sizeof(*pc->clk_pwms), GFP_KERNEL);
- if (!pc->clk_pwms)
- return -ENOMEM;
-
pc->clk_top = devm_clk_get(&pdev->dev, "top");
if (IS_ERR(pc->clk_top))
return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_top),
@@ -390,10 +391,15 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
snprintf(name, sizeof(name), "pwm%d", i + 1);
- pc->clk_pwms[i] = devm_clk_get(&pdev->dev, name);
- if (IS_ERR(pc->clk_pwms[i]))
- return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_pwms[i]),
+ pc->clk_pwms[i].clk = devm_clk_get(&pdev->dev, name);
+ if (IS_ERR(pc->clk_pwms[i].clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_pwms[i].clk),
"Failed to get %s clock\n", name);
+
+ ret = devm_clk_rate_exclusive_get(&pdev->dev, pc->clk_pwms[i].clk);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to lock clock rate for %s\n", name);
}
ret = pwm_mediatek_init_used_clks(pc);
--
2.49.0
More information about the Linux-mediatek
mailing list