[PATCH v3 3/3] pwm: ehrpwm: ensure clock and runtime PM are enabled if hardware is active

From: Rafael V. Volkmer
Date: Fri Feb 07 2025 - 16:38:13 EST


During probe, if the hardware is already active, it is not guaranteed
that the clock is enabled. To address this, ehrpwm_pwm_probe() now
checks whether the PWM is enabled and ensures that the necessary
resources are initialized.

Changes:
- Call ehrpwm_get_state() during probe to check if the PWM is active.
- If the PWM is enabled, call clk_prepare_enable() to ensure the clock
is active.
- If the clock is successfully enabled, call pm_runtime_get_sync() to
manage power state.
- Handle failure cases by properly disabling and unpreparing the clock.

This ensures that the driver correctly handles cases where the hardware
is already in use at the time of initialization, preventing potential
failures due to uninitialized resources.

Signed-off-by: Rafael V. Volkmer <rafael.v.volkmer@xxxxxxxxx>
---
drivers/pwm/pwm-tiehrpwm.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 52527136c507..30beaf7d1721 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -633,8 +633,10 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct ehrpwm_pwm_chip *pc;
+ struct pwm_state state;
struct pwm_chip *chip;
struct clk *clk;
+ bool tbclk_enabled;
int ret;

chip = devm_pwmchip_alloc(&pdev->dev, NUM_PWM_CHANNEL, sizeof(*pc));
@@ -676,6 +678,18 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
return ret;
}

+ ehrpwm_get_state(chip, &chip->pwms[0], &state);
+
+ if (state.enabled == true) {
+ ret = clk_prepare_enable(pc->tbclk);
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret, "clk_prepare_enable() failed");
+ goto err_pwmchip_remove;
+ }
+
+ tbclk_enabled = true;
+ }
+
ret = pwmchip_add(chip);
if (ret < 0) {
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
@@ -685,10 +699,22 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, chip);
pm_runtime_enable(&pdev->dev);

+ if (state.enabled == true) {
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err_probe(&pdev->dev, ret, "pm_runtime_get_sync() failed");
+ clk_disable_unprepare(pc->tbclk);
+ goto err_pwmchip_remove;
+ }
+ }
+
return 0;

+err_pwmchip_remove:
+ pwmchip_remove(chip);
err_clk_unprepare:
- clk_unprepare(pc->tbclk);
+ if (tbclk_enabled)
+ clk_unprepare(pc->tbclk);

return ret;
}
--
2.25.1