From nobody Fri Jul 24 21:52:36 2026 Received: from azure-sdnproxy.icoremail.net (azure-sdnproxy.icoremail.net [4.193.249.245]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1070D36EABE; Fri, 24 Jul 2026 08:43:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.193.249.245 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882604; cv=none; b=fBAyf1B7vPGG04h0ROT9cjgS0GcUgiaJDNaXFymCBrD39KV/rYEb35w/tCGMualPcKj1LhnKK9etwMECshw/DT36bltGSIMwldPVzev3APNJm2qwbX0TT+s8vtjiI2Y6DpqiQJh46d62WvyL/Ynholgqdi0Kcn0x2aWTbjv5XVc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882604; c=relaxed/simple; bh=a/xSDZQnb5R7Ub51W8UMWDonK4lvv4LL1dOzh1hVurA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=B7NHOFO+N4LmiMCPByjUFoN1/H04bdcHGCQ9S0A/4gJFVc4XIdWktUWv0QexTnlTjbP88BmLPK6EFHoaM5D4efAwiXJqHZ7xGdNgpr9CXJHNJ0Cr8e+6ADBE+yeFOfhdh6EX9FznmgKFwyjrTMUoXxjRFx+3R3Sov1Xn95UsAMo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com; spf=pass smtp.mailfrom=eswincomputing.com; arc=none smtp.client-ip=4.193.249.245 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=eswincomputing.com Received: from E0005152DT.eswin.cn (unknown [10.12.96.41]) by app2 (Coremail) with SMTP id TQJkCgD3_ZuaJWNqBu02AA--.3450S2; Fri, 24 Jul 2026 16:43:07 +0800 (CST) From: dongxuyang@eswincomputing.com To: ukleinek@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, ben-linux@fluff.org, ben.dooks@codethink.co.uk, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, p.zabel@pengutronix.de, daniel.lezcano@kernel.org, tglx@kernel.org Cc: ningyu@eswincomputing.com, linmin@eswincomputing.com, xuxiang@eswincomputing.com, wangguosheng@eswincomputing.com, pinkesh.vaghela@einfochips.com, Xuyang Dong Subject: [PATCH v13 1/5] dt-bindings: pwm: dwc: Document optional resets property Date: Fri, 24 Jul 2026 16:43:04 +0800 Message-Id: <20260724084304.1531-1-dongxuyang@eswincomputing.com> X-Mailer: git-send-email 2.31.1.windows.1 In-Reply-To: <20260724084153.1473-1-dongxuyang@eswincomputing.com> References: <20260724084153.1473-1-dongxuyang@eswincomputing.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 X-CM-TRANSID: TQJkCgD3_ZuaJWNqBu02AA--.3450S2 X-Coremail-Antispam: 1UD129KBjvJXoW7Ww4DAry8GFy7Cw1kurWkCrg_yoW8XrW3pa yfurZ2qr93XF13Ww4rXr1kCr13XFnYyr43Kr1Iqw42ya9xtayjqF4akw15JFW5ArWIvrWa gFZ3uw1fZFyjyr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBv14x267AKxVW5JVWrJwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK02 1l84ACjcxK6xIIjxv20xvE14v26w1j6s0DM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4U JVWxJr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_Gc CE3s1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E 2Ix0cI8IcVAFwI0_JrI_JrylYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJV W8JwACjcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lFIxGxcIEc7CjxVA2 Y2ka0xkIwI1lw4CEc2x0rVAKj4xxMxkF7I0En4kS14v26r4a6rW5MxkIecxEwVCm-wCF04 k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18 MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr4 1lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l IxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4UMIIF0xvEx4 A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x0pRuHqcUUUUU= X-CM-SenderInfo: pgrqw5xx1d0w46hv4xpqfrz1xxwl0woofrz/ Content-Type: text/plain; charset="utf-8" From: Xuyang Dong The DesignWare PWM IP has two active-low reset inputs: presetn resets the register interface logic in the pclk (bus) domain, and timer_N_resetn resets the counter/timer logic in the timer_N_clk domain. The existing snps,dw-apb-timers-pwm2 binding does not describe either of these lines. Add the resets property and describe the function of each reset to support future use of resets. Add the reset-names property to allow independent control of the two reset signals. Signed-off-by: Xuyang Dong --- .../bindings/pwm/snps,dw-apb-timers-pwm2.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/pwm/snps,dw-apb-timers-pwm2.= yaml b/Documentation/devicetree/bindings/pwm/snps,dw-apb-timers-pwm2.yaml index 7523a89a1773..1f9d72f9f359 100644 --- a/Documentation/devicetree/bindings/pwm/snps,dw-apb-timers-pwm2.yaml +++ b/Documentation/devicetree/bindings/pwm/snps,dw-apb-timers-pwm2.yaml @@ -43,6 +43,16 @@ properties: - const: bus - const: timer + resets: + items: + - description: Interface bus (presetn) reset + - description: PWM timer logic (timer_N_resetn) reset + + reset-names: + items: + - const: bus + - const: timer + snps,pwm-number: $ref: /schemas/types.yaml#/definitions/uint32 description: The number of PWM channels configured for this instance -- 2.34.1 From nobody Fri Jul 24 21:52:36 2026 Received: from zg8tmtyylji0my4xnjqumte4.icoremail.net (zg8tmtyylji0my4xnjqumte4.icoremail.net [162.243.164.118]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 21C89353A90; Fri, 24 Jul 2026 08:43:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.243.164.118 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882615; cv=none; b=RrXT8TKeB41krf7zGjl/dopPWSEvk1pRKS9mleGM3XEN2dLbhmGkFGAB6A9PW2dWt+AaYkGzQJ1qOf5P5S6hk6TszHa2OJtkENiyBE3uD6Jbe/lJMqnltJ+STzcA6zKswnT3Pm3hG7gLohRuBw2HylFIY2egxJ8xZ/Eqq7R5Kds= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882615; c=relaxed/simple; bh=8sxOBXk1JNr87/68n0T3t+zL+wugHNQJuvHPyvVkgaA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iyK35go+Ji399LWR/EVV0Rjj9JVyYmuEPGVZTcwR4g0KawHWvKI9TkK2b5VaRyGRqdy1IpnMqM08aRCJXkwCaTpkZUxFGWVrc4RSxJBBSdxSbM++lUOIkPRrxzsnfNzAsZwslW+3mByZugBllQK/140q3ZY6lGy1djdv6x8+ML4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com; spf=pass smtp.mailfrom=eswincomputing.com; arc=none smtp.client-ip=162.243.164.118 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=eswincomputing.com Received: from E0005152DT.eswin.cn (unknown [10.12.96.41]) by app1 (Coremail) with SMTP id TAJkCgA3y2+qJWNqe_s2AA--.3579S2; Fri, 24 Jul 2026 16:43:24 +0800 (CST) From: dongxuyang@eswincomputing.com To: ukleinek@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, ben-linux@fluff.org, ben.dooks@codethink.co.uk, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, p.zabel@pengutronix.de, daniel.lezcano@kernel.org, tglx@kernel.org Cc: ningyu@eswincomputing.com, linmin@eswincomputing.com, xuxiang@eswincomputing.com, wangguosheng@eswincomputing.com, pinkesh.vaghela@einfochips.com, Xuyang Dong Subject: [PATCH v13 2/5] dt-bindings: pwm: dwc: Add eswin compatible Date: Fri, 24 Jul 2026 16:43:20 +0800 Message-Id: <20260724084320.1586-1-dongxuyang@eswincomputing.com> X-Mailer: git-send-email 2.31.1.windows.1 In-Reply-To: <20260724084153.1473-1-dongxuyang@eswincomputing.com> References: <20260724084153.1473-1-dongxuyang@eswincomputing.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 X-CM-TRANSID: TAJkCgA3y2+qJWNqe_s2AA--.3579S2 X-Coremail-Antispam: 1UD129KBjvJXoW7Ww43uw4fXrW5XF1xJr1kKrg_yoW8tFWUpF WfuFWvqr1fXr17Zws5XF18CF13Xas5JF43Kr1xtr4UAayqqFWjqFWakF15AFW7Zr4xZrW3 Wan3ur13A3Wj9r7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBm14x267AKxVW5JVWrJwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK02 1l84ACjcxK6xIIjxv20xvE14v26w1j6s0DM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4U JVWxJr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_Gc CE3s1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E 2Ix0cI8IcVAFwI0_Jrv_JF1lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJV W8JwACjcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lFIxGxcIEc7CjxVA2 Y2ka0xkIwI1lw4CEc2x0rVAKj4xxMxkF7I0En4kS14v26r4a6rW5MxkIecxEwVCm-wCF04 k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18 MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr4 1lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1U MIIF0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I 8E87Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjTRNSdgDUUUU X-CM-SenderInfo: pgrqw5xx1d0w46hv4xpqfrz1xxwl0woofrz/ Content-Type: text/plain; charset="utf-8" From: Xuyang Dong EIC7700 integrates the DesignWare PWM IP described by the generic snps,dw-apb-timers-pwm2 binding. On this SoC, the presetn and timer_N_resetn inputs are physically tied together to a single reset line, so exactly one reset is both required and sufficient, unlike the generic binding where up to two independent lines are optional. Add the eswin,eic7700-pwm compatible string and constrain its resets property to exactly one entry. Signed-off-by: Xuyang Dong --- .../bindings/pwm/snps,dw-apb-timers-pwm2.yaml | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/pwm/snps,dw-apb-timers-pwm2.= yaml b/Documentation/devicetree/bindings/pwm/snps,dw-apb-timers-pwm2.yaml index 1f9d72f9f359..c65174e2045a 100644 --- a/Documentation/devicetree/bindings/pwm/snps,dw-apb-timers-pwm2.yaml +++ b/Documentation/devicetree/bindings/pwm/snps,dw-apb-timers-pwm2.yaml @@ -20,12 +20,11 @@ description: instead of having to encode the IP version number in the device tree compatible. -allOf: - - $ref: pwm.yaml# - properties: compatible: - const: snps,dw-apb-timers-pwm2 + enum: + - snps,dw-apb-timers-pwm2 + - eswin,eic7700-pwm reg: maxItems: 1 @@ -44,11 +43,13 @@ properties: - const: timer resets: + minItems: 1 items: - description: Interface bus (presetn) reset - description: PWM timer logic (timer_N_resetn) reset reset-names: + minItems: 1 items: - const: bus - const: timer @@ -64,6 +65,23 @@ required: - clocks - clock-names +allOf: + - $ref: pwm.yaml# + + - if: + properties: + compatible: + contains: + const: eswin,eic7700-pwm + then: + properties: + resets: + items: + - description: Combined APB interface and timer logic reset + reset-names: false + required: + - resets + additionalProperties: false examples: @@ -75,3 +93,12 @@ examples: clocks =3D <&bus>, <&timer>; clock-names =3D "bus", "timer"; }; + - | + pwm@50818000 { + compatible =3D "eswin,eic7700-pwm"; + reg =3D <0x50818000 0x4000>; + #pwm-cells =3D <3>; + clocks =3D <&bus>, <&timer>; + clock-names =3D "bus", "timer"; + resets =3D <&reset>; + }; -- 2.34.1 From nobody Fri Jul 24 21:52:36 2026 Received: from azure-sdnproxy.icoremail.net (azure-sdnproxy.icoremail.net [13.76.78.106]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D5AA63CE4B6; Fri, 24 Jul 2026 08:44:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.76.78.106 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882651; cv=none; b=jRfv+c3ey0N4nczEgBaEscjJqZ4HKajDf0cIPVd2SLupgDF3osKEFcmz9Rjx/0ZmmylR1KloBIiB7Q5bWsLTD/kekbkXgW+9qPVqyEQLM5D8cb9Dir8W9+HfJ78aNJ9AQrUo3V6P74BQx9XUJ6+NQxSH111KbQyzM+T+RiCVRTg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882651; c=relaxed/simple; bh=6pUgGB9pUHMG8V2lKnuIP9ouDvqzVl65Z1kl3U26t0c=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=pwbSNsVV1CKYlbGPlVZt3d89LSpx/2Nz4ur84VCc2j2NzWBBj1Z36klggonBA9RD7DdpNA233gYIDeTWGZY/DgjKCtn18LoyI/rkIJiRfq4TJ93yxCzTkcM1tlpn8P9C7iDIThP8rzhwVbB5y4NsYctgJEFxmd9oHxorJZ/XHE4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com; spf=pass smtp.mailfrom=eswincomputing.com; arc=none smtp.client-ip=13.76.78.106 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=eswincomputing.com Received: from E0005152DT.eswin.cn (unknown [10.12.96.41]) by app1 (Coremail) with SMTP id TAJkCgCnSXPHJWNqgvs2AA--.43538S2; Fri, 24 Jul 2026 16:43:52 +0800 (CST) From: dongxuyang@eswincomputing.com To: ukleinek@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, ben-linux@fluff.org, ben.dooks@codethink.co.uk, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, p.zabel@pengutronix.de, daniel.lezcano@kernel.org, tglx@kernel.org Cc: ningyu@eswincomputing.com, linmin@eswincomputing.com, xuxiang@eswincomputing.com, wangguosheng@eswincomputing.com, pinkesh.vaghela@einfochips.com, Xuyang Dong Subject: [PATCH v13 3/5] pwm: dwc: add of/platform support Date: Fri, 24 Jul 2026 16:43:46 +0800 Message-Id: <20260724084346.1690-1-dongxuyang@eswincomputing.com> X-Mailer: git-send-email 2.31.1.windows.1 In-Reply-To: <20260724084153.1473-1-dongxuyang@eswincomputing.com> References: <20260724084153.1473-1-dongxuyang@eswincomputing.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 X-CM-TRANSID: TAJkCgCnSXPHJWNqgvs2AA--.43538S2 X-Coremail-Antispam: 1UD129KBjvAXoWfCrW8JF4kWrWDJFyfuFyDWrg_yoW8ur1DKo WSkw1rXw18KFn5A397Ca42kayjvw4kta4fur1rWF4DCFn8Za15Aa4UKw4Ygryxtr1YkFW3 Ar4xXr1fAF4fJ3W8n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYN7AC8VAFwI0_Xr0_Wr1l1xkIjI8I6I8E6xAIw20EY4v20xva j40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxSw2 x7M28EF7xvwVC0I7IYx2IY67AKxVWDJVCq3wA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxVW8 Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v26r xl6s0DM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj 6xIIjxv20xvE14v26r126r1DMcIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr 0_Gr1lF7xvr2IYc2Ij64vIr41lF7I21c0EjII2zVCS5cI20VAGYxC7M4IIrI8v6xkF7I0E 8cxan2IY04v7M4kE6xkIj40Ew7xC0wCY1x0262kKe7AKxVW8ZVWrXwCY02Avz4vE-syl42 xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWU GwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6rW5MIIYrxkI7VAKI4 8JMIIF0xvE2Ix0cI8IcVAFwI0_Jr0_JF4lIxAIcVC0I7IYx2IY6xkF7I0E14v26F4j6r4U JwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcV C2z280aVCY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7sRihF4tUUUUU== X-CM-SenderInfo: pgrqw5xx1d0w46hv4xpqfrz1xxwl0woofrz/ Content-Type: text/plain; charset="utf-8" From: Xuyang Dong The dwc pwm controller can be used in non-PCI systems, so allow either platform or OF based probing. The controller is reset only when no PWM channel is enabled. Otherwise, clocks are enabled and the runtime PM state is updated to reflect the active hardware configuration. The DWC PWM controller does not provide a hardware polarity bit. Currently, the driver only supports active-low output, which is incompatible with devices requiring active-high waveforms (e.g., backlight controllers, fan speed regulators). Implement polarity control by exploiting the timer's dual load registers. The hardware uses: - LD_CNT: LOW period count - LD_CNT2: HIGH period count The total period is defined as (LD_CNT + LD_CNT2). By swapping the duty cycle between these registers, we invert the polarity while keeping the period unchanged: - PWM_POLARITY_NORMAL: write duty_cycle to LD_CNT2 (HIGH period) - PWM_POLARITY_INVERSED: write duty_cycle to LD_CNT (LOW period) Implementation: Update both apply() and get_state() to handle state->polarity consistently. Since the hardware does not store polarity, get_state() returns the last successfully applied software state, ensuring that read-back matches what was originally set. Co-developed-by: Ben Dooks Signed-off-by: Ben Dooks Signed-off-by: Xiang Xu Signed-off-by: Guosheng Wang Signed-off-by: Xuyang Dong --- drivers/pwm/Kconfig | 10 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-dwc-core.c | 172 +++++++++++++++++---- drivers/pwm/pwm-dwc-of.c | 299 +++++++++++++++++++++++++++++++++++++ drivers/pwm/pwm-dwc.h | 25 +++- 5 files changed, 468 insertions(+), 39 deletions(-) create mode 100644 drivers/pwm/pwm-dwc-of.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index e8886a9b64d9..fd1d68beab67 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -249,6 +249,16 @@ config PWM_DWC To compile this driver as a module, choose M here: the module will be called pwm-dwc. +config PWM_DWC_OF + tristate "DesignWare PWM Controller (OF bus)" + depends on HAS_IOMEM && (OF || COMPILE_TEST) + select PWM_DWC_CORE + help + PWM driver for Synopsys DWC PWM Controller on an OF bus or + a platform bus. + To compile this driver as a module, choose M here: the module + will be called pwm-dwc-of. + config PWM_EP93XX tristate "Cirrus Logic EP93xx PWM support" depends on ARCH_EP93XX || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 5630a521a7cf..acd7dfe98dff 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_PWM_CRC) +=3D pwm-crc.o obj-$(CONFIG_PWM_CROS_EC) +=3D pwm-cros-ec.o obj-$(CONFIG_PWM_DWC_CORE) +=3D pwm-dwc-core.o obj-$(CONFIG_PWM_DWC) +=3D pwm-dwc.o +obj-$(CONFIG_PWM_DWC_OF) +=3D pwm-dwc-of.o obj-$(CONFIG_PWM_EP93XX) +=3D pwm-ep93xx.o obj-$(CONFIG_PWM_FSL_FTM) +=3D pwm-fsl-ftm.o obj-$(CONFIG_PWM_GPIO) +=3D pwm-gpio.o diff --git a/drivers/pwm/pwm-dwc-core.c b/drivers/pwm/pwm-dwc-core.c index 6dabec93a3c6..eb11dfc4dc71 100644 --- a/drivers/pwm/pwm-dwc-core.c +++ b/drivers/pwm/pwm-dwc-core.c @@ -12,8 +12,10 @@ #define DEFAULT_SYMBOL_NAMESPACE "dwc_pwm" #include +#include #include #include +#include #include #include #include @@ -39,26 +41,82 @@ static int __dwc_pwm_configure_timer(struct dwc_pwm *dw= c, struct pwm_device *pwm, const struct pwm_state *state) { - u64 tmp; + u64 tmp, period_cyc; u32 ctrl; u32 high; u32 low; - /* - * Calculate width of low and high period in terms of input clock - * periods and check are the result within HW limits between 1 and - * 2^32 periods. - */ - tmp =3D DIV_ROUND_CLOSEST_ULL(state->duty_cycle, dwc->clk_ns); - if (tmp < 1 || tmp > (1ULL << 32)) - return -ERANGE; - low =3D tmp - 1; - - tmp =3D DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle, - dwc->clk_ns); - if (tmp < 1 || tmp > (1ULL << 32)) - return -ERANGE; - high =3D tmp - 1; + if (dwc->clk) + dwc->clk_rate =3D clk_get_rate(dwc->clk); + + if (dwc->features & DWC_TIM_CTRL_0N100PWM_EN) { + /* + * Calculate the total period in clock cycles first, then the + * duty cycle. Derive the complementary half as the remainder to + * avoid compounding two independent floor-truncation errors: + * floor(duty) + floor(period - duty) can be one cycle short of + * floor(period). The PWM core requires the maximal achievable + * period not exceeding the requested value. + */ + period_cyc =3D mul_u64_u64_div_u64(state->period, dwc->clk_rate, + NSEC_PER_SEC); + if (!period_cyc) + return -ERANGE; + + tmp =3D mul_u64_u64_div_u64(state->duty_cycle, dwc->clk_rate, + NSEC_PER_SEC); + /* + * Calculate the width of the low and high periods in terms of + * input clock periods, and check whether the results are within + * the hardware limits of 0 to 2^32 periods. + */ + if (tmp >=3D (1ULL << 32) || period_cyc - tmp >=3D (1ULL << 32)) + return -ERANGE; + + /* + * The hardware has no polarity register. Polarity inversion is + * achieved by swapping the low and high load-count registers: + * NORMAL (active-high): duty_cycle -> + * HIGH period (DWC_TIM_LD_CNT2) + * INVERSED (active-low): duty_cycle -> + * LOW period (DWC_TIM_LD_CNT) + */ + if (state->polarity =3D=3D PWM_POLARITY_NORMAL) { + high =3D tmp; + low =3D period_cyc - tmp; + } else { + low =3D tmp; + high =3D period_cyc - tmp; + } + } else { + /* + * Calculate width of low and high period in terms of input + * clock periods and check are the result within HW limits + * between 1 and 2^32 periods. + * Polarity inversion uses the same register-swap technique as + * the 0N100 path above. + * Derive the complementary half from the total period to avoid + * compounding two independent floor-truncation errors. + */ + tmp =3D mul_u64_u64_div_u64(state->duty_cycle, dwc->clk_rate, + NSEC_PER_SEC); + if (tmp < 1 || tmp > (1ULL << 32)) + return -ERANGE; + + period_cyc =3D mul_u64_u64_div_u64(state->period, dwc->clk_rate, + NSEC_PER_SEC); + /* period_cyc - tmp: complementary half; tmp <=3D period_cyc */ + if (period_cyc - tmp < 1 || period_cyc - tmp > (1ULL << 32)) + return -ERANGE; + + if (state->polarity =3D=3D PWM_POLARITY_NORMAL) { + high =3D tmp - 1; + low =3D period_cyc - tmp - 1; + } else { + low =3D tmp - 1; + high =3D period_cyc - tmp - 1; + } + } /* * Specification says timer usage flow is to disable timer, then @@ -74,6 +132,7 @@ static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc, * width of low period and latter the width of high period in terms * multiple of input clock periods: * Width =3D ((Count + 1) * input clock period). + * Width =3D (Count * input clock period) : supported 0% and 100%. */ dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm)); dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm)); @@ -85,6 +144,14 @@ static int __dwc_pwm_configure_timer(struct dwc_pwm *dw= c, * periods are set by Load Count registers. */ ctrl =3D DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM; + /* + * Mask interrupts to prevent unmasked timer interrupts on shared IRQ + * systems where no IRQ handler is installed. + */ + ctrl |=3D DWC_TIM_CTRL_INT_MASK; + if (dwc->features & DWC_TIM_CTRL_0N100PWM_EN) + ctrl |=3D DWC_TIM_CTRL_0N100PWM_EN; + dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm)); /* @@ -99,14 +166,18 @@ static int dwc_pwm_apply(struct pwm_chip *chip, struct= pwm_device *pwm, const struct pwm_state *state) { struct dwc_pwm *dwc =3D to_dwc_pwm(chip); - - if (state->polarity !=3D PWM_POLARITY_INVERSED) - return -EINVAL; + int ret; if (state->enabled) { - if (!pwm->state.enabled) - pm_runtime_get_sync(pwmchip_parent(chip)); - return __dwc_pwm_configure_timer(dwc, pwm, state); + if (!pwm->state.enabled) { + ret =3D pm_runtime_resume_and_get(pwmchip_parent(chip)); + if (ret < 0) + return ret; + } + ret =3D __dwc_pwm_configure_timer(dwc, pwm, state); + if (ret && !pwm->state.enabled) + pm_runtime_put_sync(pwmchip_parent(chip)); + return ret; } else { if (pwm->state.enabled) { __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); @@ -121,10 +192,23 @@ static int dwc_pwm_get_state(struct pwm_chip *chip, s= truct pwm_device *pwm, struct pwm_state *state) { struct dwc_pwm *dwc =3D to_dwc_pwm(chip); - u64 duty, period; + unsigned long clk_rate; u32 ctrl, ld, ld2; + u64 duty, period; + int ret; + + ret =3D pm_runtime_resume_and_get(pwmchip_parent(chip)); + if (ret < 0) + return ret; + + if (dwc->clk) + dwc->clk_rate =3D clk_get_rate(dwc->clk); - pm_runtime_get_sync(pwmchip_parent(chip)); + clk_rate =3D dwc->clk_rate; + if (!clk_rate) { + pm_runtime_put_sync(pwmchip_parent(chip)); + return -EINVAL; + } ctrl =3D dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm->hwpwm)); ld =3D dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); @@ -132,22 +216,46 @@ static int dwc_pwm_get_state(struct pwm_chip *chip, s= truct pwm_device *pwm, state->enabled =3D !!(ctrl & DWC_TIM_CTRL_EN); + /* + * The hardware has no polarity status register; polarity is encoded + * implicitly by which of DWC_TIM_LD_CNT / DWC_TIM_LD_CNT2 holds the + * duty-cycle period (see __dwc_pwm_configure_timer). Report the + * polarity that was last programmed by apply(). On the initial read + * (before any apply call), pwm->state.polarity defaults to + * PWM_POLARITY_NORMAL, which is the natural zero-initialised value. + */ + state->polarity =3D pwm->state.polarity; + /* * If we're not in PWM, technically the output is a 50-50 * based on the timer load-count only. */ if (ctrl & DWC_TIM_CTRL_PWM) { - duty =3D (ld + 1) * dwc->clk_ns; - period =3D (ld2 + 1) * dwc->clk_ns; - period +=3D duty; + if (ctrl & DWC_TIM_CTRL_0N100PWM_EN) { + /* + * NORMAL: duty_cycle was written to DWC_TIM_LD_CNT2. + * INVERSED: duty_cycle was written to DWC_TIM_LD_CNT. + */ + if (state->polarity =3D=3D PWM_POLARITY_NORMAL) + duty =3D ld2; + else + duty =3D ld; + period =3D (u64)ld + ld2; + } else { + if (state->polarity =3D=3D PWM_POLARITY_NORMAL) + duty =3D ld2 + 1; + else + duty =3D ld + 1; + period =3D (u64)ld + ld2 + 2; + } } else { - duty =3D (ld + 1) * dwc->clk_ns; + duty =3D ld + 1; period =3D duty * 2; + state->polarity =3D PWM_POLARITY_INVERSED; } - state->polarity =3D PWM_POLARITY_INVERSED; - state->period =3D period; - state->duty_cycle =3D duty; + state->period =3D mul_u64_u64_div_u64(period, NSEC_PER_SEC, clk_rate); + state->duty_cycle =3D mul_u64_u64_div_u64(duty, NSEC_PER_SEC, clk_rate); pm_runtime_put_sync(pwmchip_parent(chip)); @@ -169,7 +277,7 @@ struct pwm_chip *dwc_pwm_alloc(struct device *dev) return chip; dwc =3D to_dwc_pwm(chip); - dwc->clk_ns =3D 10; + dwc->clk_rate =3D NSEC_PER_SEC / 10; chip->ops =3D &dwc_pwm_ops; return chip; diff --git a/drivers/pwm/pwm-dwc-of.c b/drivers/pwm/pwm-dwc-of.c new file mode 100644 index 000000000000..4956dd36f93a --- /dev/null +++ b/drivers/pwm/pwm-dwc-of.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DesignWare PWM Controller driver OF + * + * Copyright (C) 2026 SiFive, Inc. + */ + +#define DEFAULT_SYMBOL_NAMESPACE "dwc_pwm_of" + +#include +#include +#include +#include +#include + +#include "pwm-dwc.h" + +static int dwc_pwm_plat_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct dwc_pwm_drvdata *data; + u32 ctrl[DWC_TIMERS_TOTAL]; + struct pwm_chip *chip; + struct dwc_pwm *dwc; + bool pwm_en =3D false; + u32 nr_pwm, tim_id; + unsigned int i; + int ret; + + data =3D devm_kzalloc(dev, struct_size(data, chips, 1), GFP_KERNEL); + if (!data) + return -ENOMEM; + + chip =3D dwc_pwm_alloc(dev); + if (IS_ERR(chip)) + return dev_err_probe(dev, PTR_ERR(chip), + "failed to alloc pwm\n"); + + dwc =3D to_dwc_pwm(chip); + + dwc->base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dwc->base)) + return PTR_ERR(dwc->base); + + if (!device_property_read_u32(dev, "snps,pwm-number", &nr_pwm)) { + if (nr_pwm > DWC_TIMERS_TOTAL) + dev_warn(dev, "too many PWMs (%u), capping at %u\n", + nr_pwm, chip->npwm); + else + chip->npwm =3D nr_pwm; + } + + dwc->bus_clk =3D devm_clk_get(dev, "bus"); + if (IS_ERR(dwc->bus_clk)) + return dev_err_probe(dev, PTR_ERR(dwc->bus_clk), + "failed to get bus clock\n"); + + dwc->clk =3D devm_clk_get(dev, "timer"); + if (IS_ERR(dwc->clk)) + return dev_err_probe(dev, PTR_ERR(dwc->clk), + "failed to get timer clock\n"); + + ret =3D devm_clk_rate_exclusive_get(dev, dwc->clk); + if (ret) + return dev_err_probe(dev, ret, + "failed to get exclusive rate\n"); + + dwc->clk_rate =3D clk_get_rate(dwc->clk); + if (!dwc->clk_rate) + return dev_err_probe(dev, -EINVAL, + "failed to get a valid clock rate\n"); + + dwc->rst =3D devm_reset_control_array_get_optional_exclusive(dev); + + if (IS_ERR(dwc->rst)) + return dev_err_probe(dev, PTR_ERR(dwc->rst), + "failed to get reset control\n"); + + ret =3D clk_prepare_enable(dwc->bus_clk); + if (ret) + return dev_err_probe(dev, ret, + "failed to enable bus clock\n"); + + ret =3D clk_prepare_enable(dwc->clk); + if (ret) { + ret =3D dev_err_probe(dev, ret, "failed to enable timer clock\n"); + goto disable_busclk; + } + + /* Ensure the device is out of reset before accessing MMIO registers. */ + ret =3D reset_control_deassert(dwc->rst); + if (ret) { + ret =3D dev_err_probe(dev, ret, "failed to deassert reset\n"); + goto disable_clk; + } + + /* + * Check all channels to see if any channel is enabled. + * Read the control register of each channel and extract the enable bit + */ + for (i =3D 0; i < chip->npwm; i++) { + ctrl[i] =3D dwc_pwm_readl(dwc, DWC_TIM_CTRL(i)) & DWC_TIM_CTRL_EN; + if (ctrl[i]) + pwm_en =3D true; + } + + /* + * Only issue a reset pulse when all channels are disabled, so a PWM + * channel already running (e.g. configured by firmware before Linux + * took over) is left undisturbed. + */ + if (!pwm_en) { + ret =3D reset_control_reset(dwc->rst); + if (ret) { + ret =3D dev_err_probe(dev, ret, "failed to reset\n"); + goto disable_clk; + } + } + + /* init PWM feature */ + dwc->features =3D 0; + /* + * Support for 0% and 100% duty cycle mode was added in version 2.11a + * and later. + */ + tim_id =3D dwc_pwm_readl(dwc, DWC_TIMERS_COMP_VERSION); + if (tim_id >=3D DWC_TIM_VERSION_ID_2_11A) + dwc->features |=3D DWC_TIM_CTRL_0N100PWM_EN; + + data->chips[0] =3D chip; + dev_set_drvdata(dev, data); + + /* + * Save hardware state to PM context before first resume. + * Prevents zero-initialized context from overwriting registers + * and losing bootloader-preset configuration. + */ + for (i =3D 0; i < chip->npwm; i++) { + dwc->ctx[i].cnt =3D dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(i)); + dwc->ctx[i].cnt2 =3D dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(i)); + dwc->ctx[i].ctrl =3D dwc_pwm_readl(dwc, DWC_TIM_CTRL(i)); + } + + /* + * If any PWM channel is enabled, mark device active and hold runtime PM + * references for each enabled channel. Otherwise, gate the clocks. + * + * When CONFIG_PM is disabled, pm_runtime callbacks are stubs that never + * re-enable clocks, so keep clocks on unconditionally in that case. + */ + if (pwm_en) { + pm_runtime_set_active(dev); + for (i =3D 0; i < chip->npwm; i++) { + if (ctrl[i]) + pm_runtime_get_noresume(dev); + } + } else if (IS_ENABLED(CONFIG_PM)) { + clk_disable_unprepare(dwc->clk); + clk_disable_unprepare(dwc->bus_clk); + } + + pm_runtime_enable(dev); + + ret =3D pwmchip_add(chip); + if (ret) { + ret =3D dev_err_probe(dev, ret, "failed to add pwm chip\n"); + goto pm_disable; + } + + return 0; + +pm_disable: + pm_runtime_disable(dev); + if (pwm_en) { + for (i =3D 0; i < chip->npwm; i++) { + if (ctrl[i]) + pm_runtime_put_noidle(dev); + } + goto disable_clk; + } + /* + * When CONFIG_PM is disabled, clocks were never gated and must be + * disabled here. + */ + if (!IS_ENABLED(CONFIG_PM)) + goto disable_clk; + + return ret; + +disable_clk: + clk_disable_unprepare(dwc->clk); +disable_busclk: + clk_disable_unprepare(dwc->bus_clk); + + return ret; +} + +static void dwc_pwm_plat_remove(struct platform_device *pdev) +{ + struct dwc_pwm_drvdata *data =3D platform_get_drvdata(pdev); + struct pwm_chip *chip =3D data->chips[0]; + struct dwc_pwm *dwc =3D to_dwc_pwm(chip); + unsigned int idx; + u32 ctrl; + + pwmchip_remove(chip); + pm_runtime_disable(&pdev->dev); + + if (!pm_runtime_status_suspended(&pdev->dev)) { + for (idx =3D 0; idx < chip->npwm; idx++) { + ctrl =3D dwc_pwm_readl(dwc, DWC_TIM_CTRL(idx)); + if (ctrl & DWC_TIM_CTRL_EN) { + dwc_pwm_writel(dwc, ctrl & ~DWC_TIM_CTRL_EN, + DWC_TIM_CTRL(idx)); + pm_runtime_put_noidle(&pdev->dev); + } + } + clk_disable_unprepare(dwc->clk); + clk_disable_unprepare(dwc->bus_clk); + } +} + +static int dwc_pwm_runtime_suspend(struct device *dev) +{ + struct dwc_pwm_drvdata *data =3D dev_get_drvdata(dev); + struct pwm_chip *chip =3D data->chips[0]; + struct dwc_pwm *dwc =3D to_dwc_pwm(chip); + unsigned int idx; + + for (idx =3D 0; idx < chip->npwm; idx++) { + dwc->ctx[idx].cnt =3D dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(idx)); + dwc->ctx[idx].cnt2 =3D dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(idx)); + dwc->ctx[idx].ctrl =3D dwc_pwm_readl(dwc, DWC_TIM_CTRL(idx)); + } + + clk_disable_unprepare(dwc->clk); + clk_disable_unprepare(dwc->bus_clk); + + return 0; +} + +static int dwc_pwm_runtime_resume(struct device *dev) +{ + struct dwc_pwm_drvdata *data =3D dev_get_drvdata(dev); + struct pwm_chip *chip =3D data->chips[0]; + struct dwc_pwm *dwc =3D to_dwc_pwm(chip); + unsigned int idx; + int ret; + + ret =3D clk_prepare_enable(dwc->bus_clk); + if (ret) { + dev_err(dev, "failed to enable bus clock: %d\n", ret); + return ret; + } + + ret =3D clk_prepare_enable(dwc->clk); + if (ret) { + dev_err(dev, "failed to enable timer clock: %d\n", ret); + clk_disable_unprepare(dwc->bus_clk); + return ret; + } + + for (idx =3D 0; idx < chip->npwm; idx++) { + dwc_pwm_writel(dwc, dwc->ctx[idx].cnt, DWC_TIM_LD_CNT(idx)); + dwc_pwm_writel(dwc, dwc->ctx[idx].cnt2, DWC_TIM_LD_CNT2(idx)); + dwc_pwm_writel(dwc, dwc->ctx[idx].ctrl, DWC_TIM_CTRL(idx)); + } + + return 0; +} + +static const struct dev_pm_ops dwc_pwm_pm_ops =3D { + RUNTIME_PM_OPS(dwc_pwm_runtime_suspend, dwc_pwm_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) +}; + +static const struct of_device_id dwc_pwm_dt_ids[] =3D { + { .compatible =3D "snps,dw-apb-timers-pwm2" }, + { .compatible =3D "eswin,eic7700-pwm" }, + { } +}; +MODULE_DEVICE_TABLE(of, dwc_pwm_dt_ids); + +static struct platform_driver dwc_pwm_plat_driver =3D { + .driver =3D { + .name =3D "dwc-pwm", + .pm =3D pm_ptr(&dwc_pwm_pm_ops), + .of_match_table =3D dwc_pwm_dt_ids, + }, + .probe =3D dwc_pwm_plat_probe, + .remove =3D dwc_pwm_plat_remove, +}; + +module_platform_driver(dwc_pwm_plat_driver); + +MODULE_ALIAS("platform:dwc-pwm-of"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("DesignWare PWM Controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/pwm-dwc.h b/drivers/pwm/pwm-dwc.h index 1562594e7f85..75f7c2d031c4 100644 --- a/drivers/pwm/pwm-dwc.h +++ b/drivers/pwm/pwm-dwc.h @@ -26,12 +26,19 @@ MODULE_IMPORT_NS("dwc_pwm"); #define DWC_TIMERS_TOTAL 8 /* Timer Control Register */ -#define DWC_TIM_CTRL_EN BIT(0) -#define DWC_TIM_CTRL_MODE BIT(1) -#define DWC_TIM_CTRL_MODE_FREE (0 << 1) -#define DWC_TIM_CTRL_MODE_USER (1 << 1) -#define DWC_TIM_CTRL_INT_MASK BIT(2) -#define DWC_TIM_CTRL_PWM BIT(3) +#define DWC_TIM_CTRL_EN BIT(0) +#define DWC_TIM_CTRL_MODE BIT(1) +#define DWC_TIM_CTRL_MODE_FREE (0 << 1) +#define DWC_TIM_CTRL_MODE_USER BIT(1) +#define DWC_TIM_CTRL_INT_MASK BIT(2) +#define DWC_TIM_CTRL_PWM BIT(3) +#define DWC_TIM_CTRL_0N100PWM_EN BIT(4) + +/* + * The version 2.11a and later add "Pulse Width Modulation with + * 0% and 100% Duty Cycle". + */ +#define DWC_TIM_VERSION_ID_2_11A 0x3231312a struct dwc_pwm_info { unsigned int nr; @@ -52,8 +59,12 @@ struct dwc_pwm_ctx { struct dwc_pwm { void __iomem *base; - unsigned int clk_ns; + struct clk *bus_clk; + struct clk *clk; + unsigned long clk_rate; + struct reset_control *rst; struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL]; + u32 features; }; static inline struct dwc_pwm *to_dwc_pwm(struct pwm_chip *chip) -- 2.34.1 From nobody Fri Jul 24 21:52:36 2026 Received: from azure-sdnproxy.icoremail.net (azure-sdnproxy.icoremail.net [207.46.229.174]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 631F63E8354; Fri, 24 Jul 2026 08:44:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=207.46.229.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882678; cv=none; b=KWcXK6UoU97wr+QjwdIiGUFO6gevBLzP0FqJb+vevOXeEEIiXrT2avVrR8XliE4TcCf2g6c0isllSdW05yDSCXIa/DZItk62PJ+QZiSbbT7VrPMdZl19hTWb5njtP8jJpgXYSqXYSE8amd8TiQWNpkMRiw/qFjaECgpPWSY89iM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882678; c=relaxed/simple; bh=dh/du7Uk0Ql6cULT3pGKoKFY6MRS9Z9uv8V9RNL1qA8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=H3nec8+6dRdbpiCGAyvrZLIez/grjEm/KJV6IZw9w9r7lF+40UVkf2nmV1VgN4qdzJbAwV8CNOJDfO7p5Eb7UHBVDiSijlaJr1qvcH6V9iTqV4a22dQS7owZacsa2DJUUj1wQKS0dKT57M6ZK14HQLkjXbwgVk0K5h+bESdfb8k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com; spf=pass smtp.mailfrom=eswincomputing.com; arc=none smtp.client-ip=207.46.229.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=eswincomputing.com Received: from E0005152DT.eswin.cn (unknown [10.12.96.41]) by app2 (Coremail) with SMTP id TQJkCgBXbaDmJWNqGe02AA--.20050S2; Fri, 24 Jul 2026 16:44:23 +0800 (CST) From: dongxuyang@eswincomputing.com To: ukleinek@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, ben-linux@fluff.org, ben.dooks@codethink.co.uk, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, p.zabel@pengutronix.de, daniel.lezcano@kernel.org, tglx@kernel.org Cc: ningyu@eswincomputing.com, linmin@eswincomputing.com, xuxiang@eswincomputing.com, wangguosheng@eswincomputing.com, pinkesh.vaghela@einfochips.com, Xuyang Dong , Krzysztof Kozlowski Subject: [PATCH v13 4/5] dt-bindings: timer: dwc: Update resets property items Date: Fri, 24 Jul 2026 16:44:19 +0800 Message-Id: <20260724084419.1795-1-dongxuyang@eswincomputing.com> X-Mailer: git-send-email 2.31.1.windows.1 In-Reply-To: <20260724084153.1473-1-dongxuyang@eswincomputing.com> References: <20260724084153.1473-1-dongxuyang@eswincomputing.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 X-CM-TRANSID: TQJkCgBXbaDmJWNqGe02AA--.20050S2 X-Coremail-Antispam: 1UD129KBjvJXoW7Ww43tF1kXF1rJr4rGFW8Xrb_yoW8Gr48pF WxCFs2qF93XF13Xw4kJFn2ka45Zas8Cr4xCF1IgwsFyFW7Ja1YqF4Fkr1jqFW3Ar4I9FW3 WF4xuw4Yya4jyr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBm14x267AKxVW5JVWrJwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK02 1l84ACjcxK6xIIjxv20xvE14v26w1j6s0DM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4U JVWxJr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_Gc CE3s1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E 2Ix0cI8IcVAFwI0_JF0_Jw1lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJV W8JwACjcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lFIxGxcIEc7CjxVA2 Y2ka0xkIwI1lw4CEc2x0rVAKj4xxMxkF7I0En4kS14v26r4a6rW5MxkIecxEwVCm-wCF04 k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18 MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr4 1lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1U MIIF0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I 8E87Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjTRKtCzDUUUU X-CM-SenderInfo: pgrqw5xx1d0w46hv4xpqfrz1xxwl0woofrz/ Content-Type: text/plain; charset="utf-8" From: Xuyang Dong The DesignWare DW_apb_timers IP has two active-low reset inputs: presetn resets the register interface logic in the pclk (bus) domain, and timer_N_resetn resets the counter/timer logic in the timer_N_clk domain. The existing snps,dw-apb-timer binding only describes one. Update snps,dw-apb-timer binding to allow up to two reset lines, matching the hardware capabilities of the DesignWare IP family. Acked-by: Krzysztof Kozlowski Signed-off-by: Xuyang Dong --- .../devicetree/bindings/timer/snps,dw-apb-timer.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/timer/snps,dw-apb-timer.yaml= b/Documentation/devicetree/bindings/timer/snps,dw-apb-timer.yaml index d33c9205a909..4d30cd01ac65 100644 --- a/Documentation/devicetree/bindings/timer/snps,dw-apb-timer.yaml +++ b/Documentation/devicetree/bindings/timer/snps,dw-apb-timer.yaml @@ -25,7 +25,10 @@ properties: maxItems: 1 resets: - maxItems: 1 + minItems: 1 + items: + - description: Timer ticks reference (timer_N_resetn) reset + - description: APB interface (presetn) reset clocks: minItems: 1 -- 2.34.1 From nobody Fri Jul 24 21:52:36 2026 Received: from mail.eswincomputing.com (mail.eswincomputing.com [123.124.195.78]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 279F33EB0F7; Fri, 24 Jul 2026 08:45:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=123.124.195.78 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882738; cv=none; b=biJbYnlnlHKJclsTKXRqvYZIYypjpOYxQX7HrQn9/g8wuIy0P2rGGyDQsfzPUOMdxKh3VEvp3XRdh3uG1wVqhSaNtBWHwUO7zIrZcrVyDPRDq1DlVCxiRFPa0BzfZcvn1MU1Xsjd8yekx8TmPQh8MBRA0yDdY3ugz10SxDAMjqY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784882738; c=relaxed/simple; bh=71xXZyo77HeZR+z7h3T5MQpAle6zFFn2lTgrSBG5SH4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Z82qkWmc+N9by8pZ1VRNP33aQGjxx+KcUvs0E1eQwenvfo3UWKPmxYXPWIlYidrMndj/pFMJXFPsk3960vXylnBNjRm5ZkepzSszg6Q21ttnv/3czuLHPZIL1LhA0Zaj6pchIFcLUFndpjI9QJnKbT9ZnKxdKf6HeB+cCoquzVQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com; spf=pass smtp.mailfrom=eswincomputing.com; arc=none smtp.client-ip=123.124.195.78 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=eswincomputing.com Received: from E0005152DT.eswin.cn (unknown [10.12.96.41]) by app1 (Coremail) with SMTP id TAJkCgBH22_3JWNqjPs2AA--.3626S2; Fri, 24 Jul 2026 16:44:41 +0800 (CST) From: dongxuyang@eswincomputing.com To: ukleinek@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, ben-linux@fluff.org, ben.dooks@codethink.co.uk, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, p.zabel@pengutronix.de, daniel.lezcano@kernel.org, tglx@kernel.org Cc: ningyu@eswincomputing.com, linmin@eswincomputing.com, xuxiang@eswincomputing.com, wangguosheng@eswincomputing.com, pinkesh.vaghela@einfochips.com, Xuyang Dong Subject: [PATCH v13 5/5] clocksource: dw_apb_timer: Use reset array API to handle all resets Date: Fri, 24 Jul 2026 16:44:37 +0800 Message-Id: <20260724084437.1850-1-dongxuyang@eswincomputing.com> X-Mailer: git-send-email 2.31.1.windows.1 In-Reply-To: <20260724084153.1473-1-dongxuyang@eswincomputing.com> References: <20260724084153.1473-1-dongxuyang@eswincomputing.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 X-CM-TRANSID: TAJkCgBH22_3JWNqjPs2AA--.3626S2 X-Coremail-Antispam: 1UD129KBjvJXoW7Ww4fuw4xGFWrAFyDGr43Awb_yoW8WFy3pa 1fGry3GFy8uF45ua1vya4UuFyfZ3WrGFyUJrWFkws7Aw43JFy8JrW2kry5AFy7ArW0vrWa vF4S9w1ruFWjyF7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBG14x267AKxVW5JVWrJwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK02 1l84ACjcxK6xIIjxv20xvE14v26w1j6s0DM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4U JVWxJr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_Gc CE3s1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E 2Ix0cI8IcVAFwI0_JF0_Jw1lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJV W8JwACjcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lFIxGxcIEc7CjxVA2 Y2ka0xkIwI1lw4CEc2x0rVAKj4xxMxkF7I0En4kS14v26r4a6rW5MxkIecxEwVCm-wCF04 k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18 MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr4 1lIxAIcVC0I7IYx2IY67AKxVWUCVW8JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F4U JwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcV C2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBIdaVFxhVjvjDU0xZFpf9x0pRByxiUUUUU= X-CM-SenderInfo: pgrqw5xx1d0w46hv4xpqfrz1xxwl0woofrz/ Content-Type: text/plain; charset="utf-8" From: Xuyang Dong timer_get_base_and_rate() only ever fetched a single, index-0 reset control via of_reset_control_get(np, NULL), which does not consult reset-names and always resolves to the first entry. With the binding now allowing a second entry, a device tree that lists both lines would leave the second entry permanently unasserted, since the driver never touches it. Replace it with devm_reset_control_array_get_optional_exclusive() to fetch and control all reset lines listed in the device tree, ensuring every line is properly asserted and deasserted rather than only the first. Signed-off-by: Xuyang Dong --- drivers/clocksource/dw_apb_timer_of.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw= _apb_timer_of.c index 3245eb0c602d..ffe495a8416a 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -29,9 +29,11 @@ static int __init timer_get_base_and_rate(struct device_= node *np, /* * Reset the timer if the reset control is available, wiping - * out the state the firmware may have left it + * out the state the firmware may have left it. + * Use array variant to handle multiple resets (e.g., timer + * and APB interface resets) if specified in the device tree. */ - rstc =3D of_reset_control_get(np, NULL); + rstc =3D of_reset_control_array_get_optional_exclusive(np); if (!IS_ERR(rstc)) { reset_control_assert(rstc); reset_control_deassert(rstc); -- 2.34.1