From e25ac87d3f831fed002c34aadddaf4ebb4ea45ec Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 26 Jan 2024 13:04:33 +0100 Subject: pwm: atmel-hlcdc: Fix clock imbalance related to suspend support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The suspend callback disables the periph clock when the PWM is enabled and resume reenables this clock if the PWM was disabled before. Judging from the code comment it's suspend that is wrong here. Fix accordingly. Fixes: f9bb9da7c09d ("pwm: atmel-hlcdc: Implement the suspend/resume hooks") Reviewed-by: Claudiu Beznea Link: https://lore.kernel.org/r/b51ea92b0a45eff3dc83b08adefd43d930df996c.1706269232.git.u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/pwm/pwm-atmel-hlcdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pwm/pwm-atmel-hlcdc.c') diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 3f2c5031a3ba..1f6fc9a9fcf3 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -185,7 +185,7 @@ static int atmel_hlcdc_pwm_suspend(struct device *dev) struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev); /* Keep the periph clock enabled if the PWM is still running. */ - if (pwm_is_enabled(&atmel->chip.pwms[0])) + if (!pwm_is_enabled(&atmel->chip.pwms[0])) clk_disable_unprepare(atmel->hlcdc->periph_clk); return 0; -- cgit v1.2.3 From c6c3f7e73dabd8c5aee0f7aad9720d8f5e3f5ca7 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 26 Jan 2024 13:04:34 +0100 Subject: pwm: atmel-hlcdc: Don't use pwm consumer API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lowlevel driver callbacks are not supposed to use the consumer API functions. Currently this works, but with the upcoming locking changes this probably results in dead locks. Reviewed-by: Claudiu Beznea Link: https://lore.kernel.org/r/6e34607828b290cd64ca9f82df40872853069f07.1706269232.git.u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/pwm/pwm-atmel-hlcdc.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/pwm/pwm-atmel-hlcdc.c') diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 1f6fc9a9fcf3..2d64af045fc5 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -183,9 +183,10 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = { static int atmel_hlcdc_pwm_suspend(struct device *dev) { struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev); + struct pwm_device *pwm = &atmel->chip.pwms[0]; /* Keep the periph clock enabled if the PWM is still running. */ - if (!pwm_is_enabled(&atmel->chip.pwms[0])) + if (!pwm->state.enabled) clk_disable_unprepare(atmel->hlcdc->periph_clk); return 0; @@ -194,20 +195,17 @@ static int atmel_hlcdc_pwm_suspend(struct device *dev) static int atmel_hlcdc_pwm_resume(struct device *dev) { struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev); - struct pwm_state state; + struct pwm_device *pwm = &atmel->chip.pwms[0]; int ret; - pwm_get_state(&atmel->chip.pwms[0], &state); - /* Re-enable the periph clock it was stopped during suspend. */ - if (!state.enabled) { + if (!pwm->state.enabled) { ret = clk_prepare_enable(atmel->hlcdc->periph_clk); if (ret) return ret; } - return atmel_hlcdc_pwm_apply(&atmel->chip, &atmel->chip.pwms[0], - &state); + return atmel_hlcdc_pwm_apply(&atmel->chip, pwm, &pwm->state); } static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops, -- cgit v1.2.3 From 0ba76822eb65a92c0762d0b0fa79b45ad909d892 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 14 Feb 2024 10:30:58 +0100 Subject: pwm: atmel-hlcdc: Prepare removing pwm_chip from driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prepares the driver for further changes that will drop struct pwm_chip chip from struct atmel_hlcdc_pwm. Use the pwm_chip as driver data instead of the atmel_hlcdc_pwm to get access to the pwm_chip in the .suspend() and .resume() callbacks and atmel_hlcdc_pwm_remove() without using atmel->chip. Link: https://lore.kernel.org/r/0e97342f15540c7330d405eaaf3e68baa8e1e488.1707900770.git.u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/pwm/pwm-atmel-hlcdc.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers/pwm/pwm-atmel-hlcdc.c') diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 2d64af045fc5..718f1b1cce0b 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -182,8 +182,9 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = { static int atmel_hlcdc_pwm_suspend(struct device *dev) { - struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev); - struct pwm_device *pwm = &atmel->chip.pwms[0]; + struct pwm_chip *chip = dev_get_drvdata(dev); + struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip); + struct pwm_device *pwm = &chip->pwms[0]; /* Keep the periph clock enabled if the PWM is still running. */ if (!pwm->state.enabled) @@ -194,8 +195,9 @@ static int atmel_hlcdc_pwm_suspend(struct device *dev) static int atmel_hlcdc_pwm_resume(struct device *dev) { - struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev); - struct pwm_device *pwm = &atmel->chip.pwms[0]; + struct pwm_chip *chip = dev_get_drvdata(dev); + struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip); + struct pwm_device *pwm = &chip->pwms[0]; int ret; /* Re-enable the periph clock it was stopped during suspend. */ @@ -205,7 +207,7 @@ static int atmel_hlcdc_pwm_resume(struct device *dev) return ret; } - return atmel_hlcdc_pwm_apply(&atmel->chip, pwm, &pwm->state); + return atmel_hlcdc_pwm_apply(chip, pwm, &pwm->state); } static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops, @@ -241,6 +243,7 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) { const struct of_device_id *match; struct device *dev = &pdev->dev; + struct pwm_chip *chip; struct atmel_hlcdc_pwm *atmel; struct atmel_hlcdc *hlcdc; int ret; @@ -260,26 +263,28 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) atmel->errata = match->data; atmel->hlcdc = hlcdc; - atmel->chip.ops = &atmel_hlcdc_pwm_ops; - atmel->chip.dev = dev; - atmel->chip.npwm = 1; + chip = &atmel->chip; + chip->ops = &atmel_hlcdc_pwm_ops; + chip->dev = dev; + chip->npwm = 1; - ret = pwmchip_add(&atmel->chip); + ret = pwmchip_add(chip); if (ret) { clk_disable_unprepare(hlcdc->periph_clk); return ret; } - platform_set_drvdata(pdev, atmel); + platform_set_drvdata(pdev, chip); return 0; } static void atmel_hlcdc_pwm_remove(struct platform_device *pdev) { - struct atmel_hlcdc_pwm *atmel = platform_get_drvdata(pdev); + struct pwm_chip *chip = platform_get_drvdata(pdev); + struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip); - pwmchip_remove(&atmel->chip); + pwmchip_remove(chip); clk_disable_unprepare(atmel->hlcdc->periph_clk); } -- cgit v1.2.3 From 93dcf8e00e16d76a5f0d689ebad13761a1213c33 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 14 Feb 2024 10:30:59 +0100 Subject: pwm: atmel-hlcdc: Make use of devm_pwmchip_alloc() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prepares the pwm-atmel-hlcdc driver to further changes of the pwm core outlined in the commit introducing devm_pwmchip_alloc(). There is no intended semantical change and the driver should behave as before. Link: https://lore.kernel.org/r/4724c6a0f052160ac80ba5a3065c9470778b7457.1707900770.git.u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/pwm/pwm-atmel-hlcdc.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/pwm/pwm-atmel-hlcdc.c') diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 718f1b1cce0b..2afb302be02c 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -28,7 +28,6 @@ struct atmel_hlcdc_pwm_errata { }; struct atmel_hlcdc_pwm { - struct pwm_chip chip; struct atmel_hlcdc *hlcdc; struct clk *cur_clk; const struct atmel_hlcdc_pwm_errata *errata; @@ -36,7 +35,7 @@ struct atmel_hlcdc_pwm { static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip) { - return container_of(chip, struct atmel_hlcdc_pwm, chip); + return pwmchip_get_drvdata(chip); } static int atmel_hlcdc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, @@ -250,9 +249,10 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) hlcdc = dev_get_drvdata(dev->parent); - atmel = devm_kzalloc(dev, sizeof(*atmel), GFP_KERNEL); - if (!atmel) - return -ENOMEM; + chip = devm_pwmchip_alloc(dev, 1, sizeof(*atmel)); + if (IS_ERR(chip)) + return PTR_ERR(chip); + atmel = to_atmel_hlcdc_pwm(chip); ret = clk_prepare_enable(hlcdc->periph_clk); if (ret) @@ -263,10 +263,7 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) atmel->errata = match->data; atmel->hlcdc = hlcdc; - chip = &atmel->chip; chip->ops = &atmel_hlcdc_pwm_ops; - chip->dev = dev; - chip->npwm = 1; ret = pwmchip_add(chip); if (ret) { -- cgit v1.2.3