lkml.org 
[lkml]   [2022]   [Aug]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 154/545] pwm: sifive: Ensure the clk is enabled exactly once per running PWM
    Date
    From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

    [ Upstream commit ace41d7564e655c39f709a78c035188a460c7cbd ]

    .apply() assumes the clk to be for a given PWM iff the PWM is enabled.
    So make sure this is the case when .probe() completes. And in .remove()
    disable the according number of times.

    This fixes a clk enable/disable imbalance, if some PWMs are already running
    at probe time.

    Fixes: 9e37a53eb051 (pwm: sifive: Add a driver for SiFive SoC PWM)
    Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    Tested-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
    Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/pwm/pwm-sifive.c | 46 ++++++++++++++++++++++++++++++++--------
    1 file changed, 37 insertions(+), 9 deletions(-)

    diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
    index cc32f7ce09a6..1def1bc59240 100644
    --- a/drivers/pwm/pwm-sifive.c
    +++ b/drivers/pwm/pwm-sifive.c
    @@ -230,6 +230,8 @@ static int pwm_sifive_probe(struct platform_device *pdev)
    struct pwm_chip *chip;
    struct resource *res;
    int ret;
    + u32 val;
    + unsigned int enabled_pwms = 0, enabled_clks = 1;

    ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
    if (!ddata)
    @@ -260,6 +262,33 @@ static int pwm_sifive_probe(struct platform_device *pdev)
    return ret;
    }

    + val = readl(ddata->regs + PWM_SIFIVE_PWMCFG);
    + if (val & PWM_SIFIVE_PWMCFG_EN_ALWAYS) {
    + unsigned int i;
    +
    + for (i = 0; i < chip->npwm; ++i) {
    + val = readl(ddata->regs + PWM_SIFIVE_PWMCMP(i));
    + if (val > 0)
    + ++enabled_pwms;
    + }
    + }
    +
    + /* The clk should be on once for each running PWM. */
    + if (enabled_pwms) {
    + while (enabled_clks < enabled_pwms) {
    + /* This is not expected to fail as the clk is already on */
    + ret = clk_enable(ddata->clk);
    + if (unlikely(ret)) {
    + dev_err_probe(dev, ret, "Failed to enable clk\n");
    + goto disable_clk;
    + }
    + ++enabled_clks;
    + }
    + } else {
    + clk_disable(ddata->clk);
    + enabled_clks = 0;
    + }
    +
    /* Watch for changes to underlying clock frequency */
    ddata->notifier.notifier_call = pwm_sifive_clock_notifier;
    ret = clk_notifier_register(ddata->clk, &ddata->notifier);
    @@ -282,7 +311,11 @@ static int pwm_sifive_probe(struct platform_device *pdev)
    unregister_clk:
    clk_notifier_unregister(ddata->clk, &ddata->notifier);
    disable_clk:
    - clk_disable_unprepare(ddata->clk);
    + while (enabled_clks) {
    + clk_disable(ddata->clk);
    + --enabled_clks;
    + }
    + clk_unprepare(ddata->clk);

    return ret;
    }
    @@ -290,21 +323,16 @@ static int pwm_sifive_probe(struct platform_device *pdev)
    static int pwm_sifive_remove(struct platform_device *dev)
    {
    struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev);
    - bool is_enabled = false;
    struct pwm_device *pwm;
    int ch;

    for (ch = 0; ch < ddata->chip.npwm; ch++) {
    pwm = &ddata->chip.pwms[ch];
    - if (pwm->state.enabled) {
    - is_enabled = true;
    - break;
    - }
    + if (pwm->state.enabled)
    + clk_disable(ddata->clk);
    }
    - if (is_enabled)
    - clk_disable(ddata->clk);

    - clk_disable_unprepare(ddata->clk);
    + clk_unprepare(ddata->clk);
    pwmchip_remove(&ddata->chip);
    clk_notifier_unregister(ddata->clk, &ddata->notifier);

    --
    2.35.1


    \
     
     \ /
      Last update: 2022-08-19 18:08    [W:3.871 / U:0.176 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site