mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Rafael V. Volkmer" <rafael.v.volkmer@gmail.com>
To: rafael.v.volkmer@gmail.com
Cc: linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org,
	ukleinek@kernel.org
Subject: [PATCH v6 5/6] pwm: tiehrpwm: handle already-running channels at probe
Date: Sun, 23 Nov 2025 20:33:49 -0300	[thread overview]
Message-ID: <20251123233349.2122-1-rafael.v.volkmer@gmail.com> (raw)
In-Reply-To: <20251123233151.2103-1-rafael.v.volkmer@gmail.com>

Detect active A/B outputs from AQCTL(A/B) when they are not
software-forced in AQCSFRC, take one pm_runtime_get_sync() per active
channel, and enable tbclk only if at least one channel is active. This
keeps runtime PM usage counts and tbclk state consistent with the
actual hardware configuration.

Before, an eHRPWM instance left running by firmware or the bootloader
could have no runtime PM reference and no tbclk enable, leaving the
driver out of sync with hardware. After this change, PM and clock
state match the active channels observed at probe.

Signed-off-by: Rafael V. Volkmer <rafael.v.volkmer@gmail.com>
---
 drivers/pwm/pwm-tiehrpwm.c | 64 +++++++++++++++++++++++++++++++++-----
 1 file changed, 57 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index cc525626b2f9..1a9be36fc7b2 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -554,13 +554,35 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
 	struct ehrpwm_pwm_chip *pc;
 	struct pwm_chip *chip;
 	struct clk *clk;
-	int ret;
+	int ret, ch_idx, ch_disable;
+	u16 aqcsfrc_reg, aqctla_reg, aqctlb_reg;
+	bool enabled_ch[NUM_PWM_CHANNEL] = { false, false };
 
 	chip = devm_pwmchip_alloc(&pdev->dev, NUM_PWM_CHANNEL, sizeof(*pc));
 	if (IS_ERR(chip))
 		return PTR_ERR(chip);
 	pc = to_ehrpwm_pwm_chip(chip);
 
+	pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pc->mmio_base))
+		return PTR_ERR(pc->mmio_base);
+
+	/*
+	 * Best-effort snapshot of AQCSFRC/AQCTLx before touching clocks or
+	 * runtime PM. If the eHRPWM block is power-gated or its clock is
+	 * disabled these registers are expected to read as 0, which we
+	 * interpret as "channel not configured / disabled".
+	 */
+	aqcsfrc_reg = readw(pc->mmio_base + AQCSFRC);
+	aqctla_reg = readw(pc->mmio_base + AQCTLA);
+	aqctlb_reg = readw(pc->mmio_base + AQCTLB);
+
+	if (aqctla_reg != 0 && !FIELD_GET(AQCSFRC_CSFA_MASK, aqcsfrc_reg))
+		enabled_ch[PWM_CHA] = true;
+
+	if (aqctlb_reg != 0 && !FIELD_GET(AQCSFRC_CSFB_MASK, aqcsfrc_reg))
+		enabled_ch[PWM_CHB] = true;
+
 	clk = devm_clk_get(&pdev->dev, "fck");
 	if (IS_ERR(clk)) {
 		if (of_device_is_compatible(np, "ti,am33xx-ecap")) {
@@ -580,10 +602,6 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
 
 	chip->ops = &ehrpwm_pwm_ops;
 
-	pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(pc->mmio_base))
-		return PTR_ERR(pc->mmio_base);
-
 	/* Acquire tbclk for Time Base EHRPWM submodule */
 	pc->tbclk = devm_clk_get(&pdev->dev, "tbclk");
 	if (IS_ERR(pc->tbclk))
@@ -595,17 +613,49 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	if (enabled_ch[PWM_CHA] || enabled_ch[PWM_CHB]) {
+		ret = clk_enable(pc->tbclk);
+		if (ret) {
+			dev_err_probe(&pdev->dev, ret, "clk_enable(tbclk) failed\n");
+			goto err_clk_unprepare;
+		}
+	}
+
 	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
-		goto err_clk_unprepare;
+		goto err_disable_tbclk;
 	}
 
 	platform_set_drvdata(pdev, chip);
 	pm_runtime_enable(&pdev->dev);
 
-	return 0;
+	/*
+	 * Treat channels that were configured and not software-forced at probe
+	 * time as "pre-enabled": take a runtime PM reference so the eHRPWM block
+	 * stays powered while such channels exist. Consumers still get/put PM
+	 * on top of this bias via pwm_enable()/pwm_disable().
+	 */
+	for (ch_idx = 0; ch_idx < NUM_PWM_CHANNEL; ch_idx++) {
+		if (enabled_ch[ch_idx]) {
+			ret = pm_runtime_get_sync(&pdev->dev);
+			if (ret < 0) {
+				for (ch_disable = 0; ch_disable <= ch_idx; ch_disable++) {
+					if (enabled_ch[ch_disable])
+						pm_runtime_put_noidle(&pdev->dev);
+				}
+
+				pwmchip_remove(chip);
+				pm_runtime_disable(&pdev->dev);
+				goto err_disable_tbclk;
+			}
+		}
+	}
 
+	return 0;
+err_disable_tbclk:
+	if (enabled_ch[PWM_CHA] || enabled_ch[PWM_CHB])
+		clk_disable(pc->tbclk);
 err_clk_unprepare:
 	clk_unprepare(pc->tbclk);
 
-- 
2.43.0


  reply	other threads:[~2025-11-23 23:33 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-23 23:20 [PATCH v6 0/6] pwm: tiehrpwm: add .get_state and tidy register handling Rafael V. Volkmer
2025-11-23 23:25 ` [PATCH v6 1/6] pwm: tiehrpwm: use GENMASK() and FIELD_PREP() for register fields Rafael V. Volkmer
2025-11-23 23:27   ` [PATCH v6 2/6] pwm: tiehrpwm: use GENMASK() and FIELD_PREP() for prescalers Rafael V. Volkmer
2025-11-23 23:29     ` [PATCH v6 3/6] pwm: tiehrpwm: refactor AQCTL polarity macros Rafael V. Volkmer
2025-11-23 23:31       ` [PATCH v6 4/6] pwm: tiehrpwm: implement .get_state callback Rafael V. Volkmer
2025-11-23 23:33         ` Rafael V. Volkmer [this message]
2025-11-23 23:35           ` [PATCH v6 6/6] pwm: tiehrpwm: tidy period conflict check Rafael V. Volkmer
2025-11-24 16:51         ` [PATCH v6 4/6] pwm: tiehrpwm: implement .get_state callback Uwe Kleine-König
2025-11-25  3:48           ` Rafael V. Volkmer
2025-11-25  7:52             ` Uwe Kleine-König
2025-11-25 20:39               ` Rafael V. Volkmer
2025-11-26  7:48                 ` Uwe Kleine-König
2025-11-24 10:36   ` [PATCH v6 1/6] pwm: tiehrpwm: use GENMASK() and FIELD_PREP() for register fields Uwe Kleine-König

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251123233349.2122-1-rafael.v.volkmer@gmail.com \
    --to=rafael.v.volkmer@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=ukleinek@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®