From nobody Sat Jul 25 17:34:49 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 9739D2931D7; Wed, 15 Jul 2026 11:05:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784113529; cv=none; b=UenQxTJJQuj2bEqKqRUJWju6z88MgbIE5SPTiSp8PG12krNr5tuAZAPHZixoGoh/fwGijK9ZtR5yelDHNuNVdNGy6rgkzXiWpUhVypKn/v1ZFqKSEhd00ESCoil1oPDKeMGNlBwWczyL4yGOYUbJcbbmxktvKtXNOzeoAW8wlFo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784113529; c=relaxed/simple; bh=KM0R8PNiQiY49ZGIXpf2Wtztv3ntHcSDf378ScpBA4I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Wa/ul0X0qjN+h26ckWZkIK1pgW7JJ+NrjOUVxUFALUu1OuKFCmV9UPR01nYxum6VgbIkuLHl6f6gnPPwFW+t0XC1QaOcfm/jcp/rk59tbnBMoVy8iH5FzLhvW7bYzgThyFOgiOMmmIAvv69yMfM6Bxnj/l5Ms3+8vw6TcC8jTBU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rybzPKm4; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="rybzPKm4" Received: by smtp.kernel.org (Postfix) with ESMTPS id 48927C2BCC7; Wed, 15 Jul 2026 11:05:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784113529; bh=KM0R8PNiQiY49ZGIXpf2Wtztv3ntHcSDf378ScpBA4I=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=rybzPKm4vnjHNeBGFhbAgeoMz/gTq8gw1qvpZ1Kj6klpsmhvA4CxosFyGrwl68uPV LIpQES336QO7nYHHvSgL2WVL7LKsnRpox5pXY/U6GeGuwfBVTlwXw5niMI8yKgmG3W 6w2L2fQw16p4GFAv/ja7RFzNIv6R+IusqA2FLsTV5mmqFATOTLKEOCAx+5Ng/D4DbF GQ7eAWCibbGNjjECPNS41VrVH6687eYYI5gpxAExLxlZ2oWDg3/Xy8BolRcOHp6feU aUxqsdbwwnlsl/qnOpvg4aideAic6fa+PW3aOVB9HKFwqtuaMvDXR86ri9Po8jtM59 LW8nCxc+CNlIA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2AE51C44501; Wed, 15 Jul 2026 11:05:29 +0000 (UTC) From: Keguang Zhang via B4 Relay Date: Wed, 15 Jul 2026 19:05:23 +0800 Subject: [PATCH v3 1/2] pwm: loongson: Fix low pulse buffer register handling Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-pwm-loongson-fix-v3-1-0aab2847eaa7@gmail.com> References: <20260715-pwm-loongson-fix-v3-0-0aab2847eaa7@gmail.com> In-Reply-To: <20260715-pwm-loongson-fix-v3-0-0aab2847eaa7@gmail.com> To: Binbin Zhou , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= Cc: linux-pwm@vger.kernel.org, linux-kernel@vger.kernel.org, Keguang Zhang X-Mailer: b4 0.14.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784113526; l=4134; i=keguang.zhang@gmail.com; s=20231129; h=from:subject:message-id; bh=RBaLuntmMDbcFZeZe6IvTpEXsQFnuS4Nraz+QZsXZKA=; b=8cJXsU8wikBf0B13PAPMaDzOR4ADdUDJyl+DYg+gvmpeqBVQwf091ep3FNNnB+GSnBQ9iRhcy OuWEJ3xjOYeB1LjaZAUloYpxkYo3McNmarX4XBPce4fwPLs0DTE5m/r X-Developer-Key: i=keguang.zhang@gmail.com; a=ed25519; pk=FMKGj/JgKll/MgClpNZ3frIIogsh5e5r8CeW2mr+WLs= X-Endpoint-Received: by B4 Relay for keguang.zhang@gmail.com/20231129 with auth_id=102 X-Original-From: Keguang Zhang Reply-To: keguang.zhang@gmail.com From: Keguang Zhang The Loongson PWM register at offset 0x4 is documented as the Low Pulse Buffer Register, which stores the low pulse width rather than the duty cycle. However, this register was incorrectly defined and treated as a duty-cycle register. As a result, the duty cycle and low pulse cycle are swapped in the generated PWM waveform. Program the low pulse (period - duty) into the register and adjust pwm_loongson_get_state() accordingly when reconstructing the duty cycle. Fixes: 2b62c89448dd ("pwm: Add Loongson PWM controller support") Signed-off-by: Keguang Zhang --- drivers/pwm/pwm-loongson.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/pwm/pwm-loongson.c b/drivers/pwm/pwm-loongson.c index f2fb35b7af2b..e703217a6d5e 100644 --- a/drivers/pwm/pwm-loongson.c +++ b/drivers/pwm/pwm-loongson.c @@ -22,6 +22,7 @@ */ =20 #include +#include #include #include #include @@ -33,10 +34,13 @@ #include =20 /* Loongson PWM registers */ -#define LOONGSON_PWM_REG_DUTY 0x4 /* Low Pulse Buffer Register */ +#define LOONGSON_PWM_REG_LOW 0x4 /* Low Pulse Buffer Register */ #define LOONGSON_PWM_REG_PERIOD 0x8 /* Pulse Period Buffer Register */ #define LOONGSON_PWM_REG_CTRL 0xc /* Control Register */ =20 +#define LOONGSON_PWM_MAX_LOW GENMASK(31, 0) +#define LOONGSON_PWM_MAX_PERIOD GENMASK(31, 0) + /* Control register bits */ #define LOONGSON_PWM_CTRL_REG_EN BIT(0) /* Counter Enable Bit */ #define LOONGSON_PWM_CTRL_REG_OE BIT(3) /* Pulse Output Enable Control Bi= t, Valid Low */ @@ -118,20 +122,21 @@ static int pwm_loongson_enable(struct pwm_chip *chip,= struct pwm_device *pwm) static int pwm_loongson_config(struct pwm_chip *chip, struct pwm_device *p= wm, u64 duty_ns, u64 period_ns) { - u64 duty, period; + u64 low, duty, period; struct pwm_loongson_ddata *ddata =3D to_pwm_loongson_ddata(chip); =20 - /* duty =3D duty_ns * ddata->clk_rate / NSEC_PER_SEC */ - duty =3D mul_u64_u64_div_u64(duty_ns, ddata->clk_rate, NSEC_PER_SEC); - if (duty > U32_MAX) - duty =3D U32_MAX; - /* period =3D period_ns * ddata->clk_rate / NSEC_PER_SEC */ period =3D mul_u64_u64_div_u64(period_ns, ddata->clk_rate, NSEC_PER_SEC); - if (period > U32_MAX) - period =3D U32_MAX; + if ((!FIELD_FIT(LOONGSON_PWM_MAX_PERIOD, period))) + period =3D LOONGSON_PWM_MAX_PERIOD; =20 - pwm_loongson_writel(ddata, duty, LOONGSON_PWM_REG_DUTY); + /* duty =3D duty_ns * ddata->clk_rate / NSEC_PER_SEC */ + duty =3D mul_u64_u64_div_u64_roundup(duty_ns, ddata->clk_rate, NSEC_PER_S= EC); + low =3D period - duty; + if ((!FIELD_FIT(LOONGSON_PWM_MAX_LOW, low))) + low =3D LOONGSON_PWM_MAX_LOW; + + pwm_loongson_writel(ddata, low, LOONGSON_PWM_REG_LOW); pwm_loongson_writel(ddata, period, LOONGSON_PWM_REG_PERIOD); =20 return 0; @@ -166,15 +171,20 @@ static int pwm_loongson_apply(struct pwm_chip *chip, = struct pwm_device *pwm, static int pwm_loongson_get_state(struct pwm_chip *chip, struct pwm_device= *pwm, struct pwm_state *state) { - u32 duty, period, ctrl; + u32 low, period, ctrl; struct pwm_loongson_ddata *ddata =3D to_pwm_loongson_ddata(chip); =20 - duty =3D pwm_loongson_readl(ddata, LOONGSON_PWM_REG_DUTY); + low =3D pwm_loongson_readl(ddata, LOONGSON_PWM_REG_LOW); period =3D pwm_loongson_readl(ddata, LOONGSON_PWM_REG_PERIOD); ctrl =3D pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); =20 - /* duty & period have a max of 2^32, so we can't overflow */ - state->duty_cycle =3D DIV64_U64_ROUND_UP((u64)duty * NSEC_PER_SEC, ddata-= >clk_rate); + /* low & period have a max of 2^32, so we can't overflow */ + if (low > period) + state->duty_cycle =3D 0; + else + state->duty_cycle =3D + DIV64_U64_ROUND_UP((u64)(period - low) * NSEC_PER_SEC, ddata->clk_ra= te); + state->period =3D DIV64_U64_ROUND_UP((u64)period * NSEC_PER_SEC, ddata->c= lk_rate); state->polarity =3D (ctrl & LOONGSON_PWM_CTRL_REG_INVERT) ? PWM_POLARITY_= INVERSED : PWM_POLARITY_NORMAL; --=20 2.43.0 From nobody Sat Jul 25 17:34:49 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 974263546FA; Wed, 15 Jul 2026 11:05:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784113529; cv=none; b=Aftd4HMq9bi1IjsM94JJHyYjUfZi/ENpmP+j6vulaOBLK3ktqSJxBMQW5W/pYgDrsilhRNpDwsNxUu3vdue+dCPY+OOedIxEENAzEqosUD4Pnpsm9sZxN7LaiqBcqbcomJM2ut+aiXeSivV4rIDIpHpLEBCRfguEjMtQKFX0xaI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784113529; c=relaxed/simple; bh=FUOvUmj3ObiKDADM819etyhdJNDhRItkgYTkrK29MCg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=el9BNAKj1fI27qrn4ppsPY3lYskjhgsCYY9KSKAr8GYCkEZUiJEob3WEmR/jEkKtKHxFBr3Ss3IIxfNRhx59J6KPBt98LCrNr5HwL1vc1K37mcZ3Apeo9dnB6rfKSoIrO50cX4Ihts1DrGhP6aTisVsrv5Q7BErAqGWo3Pvt8ro= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JmQe+TrM; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JmQe+TrM" Received: by smtp.kernel.org (Postfix) with ESMTPS id 559B3C2BCF4; Wed, 15 Jul 2026 11:05:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784113529; bh=FUOvUmj3ObiKDADM819etyhdJNDhRItkgYTkrK29MCg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=JmQe+TrMtmR5nBFkX4eTmdm8CawtVbzU/ieMhp/AylsdITXpXzbjQ/6NM151DG3KC guyPPi7ebNhBSorYZmSXVPVckVCNtsQFGnKGauLjoCI9Tcbb931CH/Jf3UZqMnPlhY o3ATXcEyBwy5WSwJNYAXKUVXJzt5kH9cIXtmJnKUbxJT9aFbwQ8sFhS+y7UJ7WJbPM GpEBi7f99oVyhn+dtHvPnrFiIpKGV3B91k/akBIYWofkNiYs4DGF8XajxdAF/prQ3p AohZ1wZ3Q+Q3jj/jMZBWv2ekEBZP9vG0TUshK8+RZlbhxUCHDy1pdrraZYN661X3NZ OAxLgSYymheHg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3910AC4450E; Wed, 15 Jul 2026 11:05:29 +0000 (UTC) From: Keguang Zhang via B4 Relay Date: Wed, 15 Jul 2026 19:05:24 +0800 Subject: [PATCH v3 2/2] pwm: loongson: Reload PWM configuration through counter reset Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-pwm-loongson-fix-v3-2-0aab2847eaa7@gmail.com> References: <20260715-pwm-loongson-fix-v3-0-0aab2847eaa7@gmail.com> In-Reply-To: <20260715-pwm-loongson-fix-v3-0-0aab2847eaa7@gmail.com> To: Binbin Zhou , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= Cc: linux-pwm@vger.kernel.org, linux-kernel@vger.kernel.org, Keguang Zhang X-Mailer: b4 0.14.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784113526; l=1594; i=keguang.zhang@gmail.com; s=20231129; h=from:subject:message-id; bh=biFtvzcfE9GMfI0AelNWdMjYeCU43VSlkKbfLk28ODs=; b=PClAz4w6153hlGuTdMEpO1CayKm0GYsVyst61lz/k7k+AG5yBqA5h4oZzJVTPI+2rWjb9kIP0 0u7G12YgEo4Ddg0fbyq1Waxxj9DdT4elzY+gciVYqBRVMbYRIfdcfG5 X-Developer-Key: i=keguang.zhang@gmail.com; a=ed25519; pk=FMKGj/JgKll/MgClpNZ3frIIogsh5e5r8CeW2mr+WLs= X-Endpoint-Received: by B4 Relay for keguang.zhang@gmail.com/20231129 with auth_id=102 X-Original-From: Keguang Zhang Reply-To: keguang.zhang@gmail.com From: Keguang Zhang The Loongson PWM controller latches the LOW and PERIOD registers only at the start of each PWM period. After disabling and re-enabling the PWM, the controller resumes from the previous counter value and completes the current period before re-latching the updated LOW and PERIOD values. Reset the PWM counter when disabling the PWM and release it when enabling the PWM so that the updated LOW and PERIOD values are latched before the PWM starts running again. Fixes: 2b62c89448dd ("pwm: Add Loongson PWM controller support") Signed-off-by: Keguang Zhang --- drivers/pwm/pwm-loongson.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pwm/pwm-loongson.c b/drivers/pwm/pwm-loongson.c index e703217a6d5e..c317d62fe813 100644 --- a/drivers/pwm/pwm-loongson.c +++ b/drivers/pwm/pwm-loongson.c @@ -103,6 +103,7 @@ static void pwm_loongson_disable(struct pwm_chip *chip,= struct pwm_device *pwm) struct pwm_loongson_ddata *ddata =3D to_pwm_loongson_ddata(chip); =20 val =3D pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); + val |=3D LOONGSON_PWM_CTRL_REG_RST; val &=3D ~LOONGSON_PWM_CTRL_REG_EN; pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL); } @@ -113,6 +114,7 @@ static int pwm_loongson_enable(struct pwm_chip *chip, s= truct pwm_device *pwm) struct pwm_loongson_ddata *ddata =3D to_pwm_loongson_ddata(chip); =20 val =3D pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); + val &=3D ~LOONGSON_PWM_CTRL_REG_RST; val |=3D LOONGSON_PWM_CTRL_REG_EN; pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL); =20 --=20 2.43.0