From nobody Mon Dec 1 22:03:43 2025 Received: from mail-dy1-f175.google.com (mail-dy1-f175.google.com [74.125.82.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E6FD735972 for ; Fri, 28 Nov 2025 00:39:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764290360; cv=none; b=sXtnVfjzQTdKd8OW4OIPUzGXr91F/3G2z2meht346LsURHOGs22n9L9L69jEgpLLiv9WDt15nTygpq1GtulB9swSdXz4SwYiGAM5NN/xAJFG4Y1kiRtxqt7R8Js5xC5tWh2X/wCij6qTDFfEFwKPvH/2T5Vo3+7G4gBvXiRgu6I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764290360; c=relaxed/simple; bh=a+ErtWdGgzML7jxeerkz3o5bNQ2OjAjVgWc3l2NvJsg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MwJv6qf2KLw48itdKIs6LHZvicY1Vq8XGbl0xL+8y+L2sVktWFFg11t0MRTol5Yrku3kVA9K7e/C8PngAHtXjMLxFxVMRD6p5v6Snd+VoGIzLgmE7kI7SxbKupbwoztSVS0FhB/EwMB+36nXGbbqL7QOimlAYw+NZtrqUkNkPc0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=HSaMDjtd; arc=none smtp.client-ip=74.125.82.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="HSaMDjtd" Received: by mail-dy1-f175.google.com with SMTP id 5a478bee46e88-2a45877bd5eso3289021eec.0 for ; Thu, 27 Nov 2025 16:39:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1764290358; x=1764895158; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=YJfQ8EGmp2loECfkqUR8E4KO61R5QbpXVzwiV7sg5RE=; b=HSaMDjtdgUyGHvHTtbqRZWbzKWU8m1M6dLln70/qooTRNAH/hulSFiqA8Ny8KoSqnk 2v2igSs5SAa+al3keP1PBeXn8gDznfVrM6iSqu1j93xNQe84lN1O9BNbOedall5GvkCg uCjVwEZFsEJ2AQu/4G5PpFgx247YnDEsAtx+4RZfp//r1l2+9MnGVPxrahwyWWFwU1Fe lZ3LFpqoc5Yo2KzIfyf4pF+ArK1SXggDazqYOF5yf0xzPmx+8bPedQg5oF3tKQ1oAqJ/ /BOYye9B32+wufMMU8qc+jGndFajejh8ef7fmVgtZCMEIpGfHx94jL13Ze0hYJy3AqIJ rFnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764290358; x=1764895158; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=YJfQ8EGmp2loECfkqUR8E4KO61R5QbpXVzwiV7sg5RE=; b=LHgBthc4DoEu4ew6K39KRS/+1/emHq3emLA5jnCKoipAsK4v5mhFGp7QIewmdTsYEL LMZeJabqSpY6OldPR2XTlw+eQkwpKkv2pBTQBXSYawKqUn3+h3/DZT0Dtv7VyerusYMn cGE7aH/xwBsNlcdytob7lG5wfx4w1QT2pYWzGVD5Lyl+iCtytft1ItsCXuauq0ZSi3JC pq9sIkI0K00jbgXd5Aj7UEwF5QBpEm04f8FQCiraPA6wRbO+rSURTHet0vUEj8gICM2V Agh4SCp6ZaxH+hjxcuVbEbO0IndxJiWsDbLeRy3+2BnYgp4Ycd84DGjada6/lSakXsg1 +hGQ== X-Gm-Message-State: AOJu0Yzzgbb9KpYiqpJUuJGzwfCzgjWnaodbbh+gZjmuzbr7Et4vjWoj IigNBn7W2eXJzOEmHd+Hx3MmcihgQCTAdyKvz8N4KoDWWOZpVYrHlF0/ X-Gm-Gg: ASbGnct73B56Vf17quNrXTeo+hTsbsm/TVPERX3Zn6OAouoN/Ph1blH//mb/6jd6naL VMWV6L0MTSCax4Lwqmc67yzv82n4ddZUB+wHT/4fUyUvBGkh1/gkAWzY3drCAbBcejV/73KM9kB aboGqk7oBc+yppGVwxUj4pwhdm4HgNEmvLRgGMdRFEs/QdW9Or8SPCG2D3rKO4cBQtkk3kx4vbl BH039tIzvRTtYmS9xaW01styIHskFQKH6a1OHm/Z7PbthZOhGJkjS9OY0w+DcwmADeJuiZvBA1I ofUkSSy52g+d4F0QfWn+hgQDDz45FYhW615fogQKJuzrYnruxGqY0jtU2/kEcpXSS0Xfw9UaOEH gji4VaesLGlw6yTCSV+DbJGExbkaXTeCndtpTksrylulr8129TKV5xap/MoIZITY0r8TpcPpf67 +4mqM0DfesoFv3EEP16likC9BjjlkPZQ4fNf8JSEcYXQo= X-Google-Smtp-Source: AGHT+IGNUwo9ubyy8ujnAFo6D0PFW/JSPgvTWJlI5LVUgs3ky818XTmQwwQ/ozc/xy/VNMrZCtt28A== X-Received: by 2002:a05:7301:4382:b0:2a4:5ff6:4438 with SMTP id 5a478bee46e88-2a6ff5307b5mr12830564eec.1.1764290357568; Thu, 27 Nov 2025 16:39:17 -0800 (PST) Received: from ParadiseLost.localdomain (lohr.com.br. [177.69.253.233]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-11dcaee7076sm12404561c88.4.2025.11.27.16.39.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Nov 2025 16:39:17 -0800 (PST) From: "Rafael V. Volkmer" To: ukleinek@kernel.org Cc: linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org, rafael.v.volkmer@gmail.com Subject: [PATCH v7 9/9] pwm: tiehrpwm: handle already-running channels at probe Date: Thu, 27 Nov 2025 21:36:34 -0300 Message-ID: <20251128003634.247529-10-rafael.v.volkmer@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251128003634.247529-1-rafael.v.volkmer@gmail.com> References: <20251128003634.247529-1-rafael.v.volkmer@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Some systems leave eHRPWM outputs running when Linux probes the driver, for example when firmware or the bootloader configured and enabled a channel before handing control to the kernel. So far, the driver always assumed both channels were disabled at probe time and started with zero tbclk and runtime PM references. Teach ehrpwm_pwm_probe() to take a best-effort snapshot of AQCSFRC and AQCTLA/B before touching clocks or runtime PM, and treat channels that are configured and not software-forced in AQCSFRC as "pre-enabled". For each such channel, take one tbclk enable and one pm_runtime_get_sync() reference so that later per-channel enable/disable paths cannot underflow the clock or runtime PM usage counts. If the eHRPWM block is power-gated or its clock is disabled while we probe, the AQ* registers are expected to read back as 0 and the driver will simply treat the instance as fully disabled, preserving the previous behaviour. Error paths unwind both tbclk and runtime PM references per channel to keep the reference counts balanced. This makes tiehrpwm robust when attaching to hardware that is already driving PWM outputs at probe time. Signed-off-by: Rafael V. Volkmer --- drivers/pwm/pwm-tiehrpwm.c | 81 +++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index d472d717abca..b2503a675484 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -478,13 +478,20 @@ static int ehrpwm_pwm_probe(struct platform_device *p= dev) 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[TIEHRPWM_NUM_PWM_CHANNEL] =3D { false, false }; =20 chip =3D devm_pwmchip_alloc(&pdev->dev, TIEHRPWM_NUM_PWM_CHANNEL, sizeof(= *pc)); if (IS_ERR(chip)) return PTR_ERR(chip); + pc =3D to_ehrpwm_pwm_chip(chip); =20 + pc->mmio_base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pc->mmio_base)) + return PTR_ERR(pc->mmio_base); + clk =3D devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(clk)) { if (of_device_is_compatible(np, "ti,am33xx-ecap")) { @@ -493,6 +500,22 @@ static int ehrpwm_pwm_probe(struct platform_device *pd= ev) } } =20 + /* + * 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 =3D ehrpwm_read(pc->mmio_base, TIEHRPWM_AQCSFRC); + aqctla_reg =3D ehrpwm_read(pc->mmio_base, TIEHRPWM_AQCTLA); + aqctlb_reg =3D ehrpwm_read(pc->mmio_base, TIEHRPWM_AQCTLB); + + if (aqctla_reg !=3D 0 && !FIELD_GET(TIEHRPWM_AQCSFRC_CSFA_MASK, aqcsfrc_r= eg)) + enabled_ch[0] =3D true; + + if (aqctlb_reg !=3D 0 && !FIELD_GET(TIEHRPWM_AQCSFRC_CSFB_MASK, aqcsfrc_r= eg)) + enabled_ch[1] =3D true; + if (IS_ERR(clk)) return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Failed to get fck\n"); =20 @@ -504,10 +527,6 @@ static int ehrpwm_pwm_probe(struct platform_device *pd= ev) =20 chip->ops =3D &ehrpwm_pwm_ops; =20 - pc->mmio_base =3D 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 =3D devm_clk_get(&pdev->dev, "tbclk"); if (IS_ERR(pc->tbclk)) @@ -519,17 +538,67 @@ static int ehrpwm_pwm_probe(struct platform_device *p= dev) return ret; } =20 + /* + * For channels that were already running when we probed, take one + * tbclk enable per channel, so that later per-channel disable paths + * cannot underflow the clock reference count. + */ + for (ch_idx =3D 0; ch_idx < TIEHRPWM_NUM_PWM_CHANNEL; ch_idx++) { + if (enabled_ch[ch_idx]) { + ret =3D clk_enable(pc->tbclk); + if (ret) { + dev_err_probe(&pdev->dev, ret, + "clk_enable(tbclk) failed for ch %d\n", + ch_idx); + + for (ch_disable =3D 0; ch_disable < ch_idx; ch_disable++) { + if (enabled_ch[ch_disable]) + clk_disable(pc->tbclk); + } + + goto err_clk_unprepare; + } + } + } + ret =3D pwmchip_add(chip); if (ret < 0) { dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); - goto err_clk_unprepare; + goto err_disable_tbclk; } =20 platform_set_drvdata(pdev, chip); pm_runtime_enable(&pdev->dev); =20 + /* + * 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 =3D 0; ch_idx < TIEHRPWM_NUM_PWM_CHANNEL; ch_idx++) { + if (enabled_ch[ch_idx]) { + ret =3D pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + for (ch_disable =3D 0; ch_disable <=3D 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; =20 +err_disable_tbclk: + for (ch_idx =3D 0; ch_idx < TIEHRPWM_NUM_PWM_CHANNEL; ch_idx++) { + if (enabled_ch[ch_idx]) + clk_disable(pc->tbclk); + } err_clk_unprepare: clk_unprepare(pc->tbclk); =20 --=20 2.43.0