From nobody Wed Jul 1 02:24:06 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 BD0273CF217; Thu, 25 Jun 2026 10:36:01 +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=1782383761; cv=none; b=L5GyzVh77TFCJUvy9JeCIc9qcpxTPQcFdmi6hLVgo4ZwSlUFjhGGBjDSgfw+HSnPRpjf8YaUAXPQUOVtY3iWq7hOXosYfqJQfZOT4eOSZM2GPRaDTWwo4W0Ux1w4m79moiqguGJOqKiKes43AN4PndZmdOPboNgvFGSchUdx5FM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782383761; c=relaxed/simple; bh=kgoSJfCQHW0+Dg62ei7S7n3mzCu8wyzu0Bm2onZRb/E=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BIDfcLqwEFxma2Fa/1axivHX28hgXhuJSzMy/zjcgPT0mZYSBfj0/m4KkUnrqhRAerGROk1dRN5e0ruZD9xQ1oUGJSEXryzl9nVF+uLslr5J73zZivwjBmyiKnagG3LJRD5tFkHPIcqs417Px5eWWF54E4G4gyW8c8xQOrv2PcM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TN1Qy4n4; 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="TN1Qy4n4" Received: by smtp.kernel.org (Postfix) with ESMTPS id 6E7EFC2BCB7; Thu, 25 Jun 2026 10:36:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1782383761; bh=kgoSJfCQHW0+Dg62ei7S7n3mzCu8wyzu0Bm2onZRb/E=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=TN1Qy4n40Ub0F2P1DbfuQ28HEwThFpqv0n1lbztjKGnSrKVaWt7qO+BJxlrahxK72 AyJRfeErtAVd96xN9E0IJlOZ1aX9MXBn0xMPeqZrWMjMCBRwUMQgAGtbD8S9ZDZp/9 3j77wI3GG5woLiXFA+b2szNt9HQE78d6i5FdUOvcBs6IJAdf4Qk8IqklH3zm9YVvOw KuQwFRHFo2Ut53u/WwceLZvcgedMuQIvSOdP4MAnrm+MaKCGs99F7B9Wr8qTdOCoC8 x2HltgbHMC7o3cFpm7iPUpMF2qK9CevI0ZdQNI0pl1ff2axkFZn520JQ6y1c8HRfqM 8Hv6alUDodVcg== 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 678C0CDB479; Thu, 25 Jun 2026 10:36:01 +0000 (UTC) From: Ben Zong-You Xie via B4 Relay Date: Thu, 25 Jun 2026 18:35:59 +0800 Subject: [PATCH v6 1/3] dt-bindings: pwm: add support for AE350 PWM controller 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: <20260625-andes-pwm-v6-1-3aef11711017@andestech.com> References: <20260625-andes-pwm-v6-0-3aef11711017@andestech.com> In-Reply-To: <20260625-andes-pwm-v6-0-3aef11711017@andestech.com> To: =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Ben Zong-You Xie X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=ed25519-sha256; t=1782383760; l=2621; i=ben717@andestech.com; s=20260120; h=from:subject:message-id; bh=AlnVaPc7CqtbKonPziakNqedexQPh0xwvAlumniDgw0=; b=2aYvFFnDpe6oSZumlqJ+lHU/NX2YFjCougsm0zS9IGtdrNriyDSw1bautJElHww3R7d7wuHd1 IMX2fx1WVm4Alg5fXblwKGucqa5imnv97K1GxSo2y/shx8Up9EcEtCH X-Developer-Key: i=ben717@andestech.com; a=ed25519; pk=nb8L7zQKGJpYk0yvrYKjViOZ34A36g1ZIsCmCsP518s= X-Endpoint-Received: by B4 Relay for ben717@andestech.com/20260120 with auth_id=610 X-Original-From: Ben Zong-You Xie Reply-To: ben717@andestech.com From: Ben Zong-You Xie The ATCPIT100 is a set of compact multi-function timers, which can be used as pulse width modulators (PWM) as well as simple timers. ATCPIT100 supports up to 4 PIT channels, and each PIT channel may be configured as a simple timer or PWM, or a combination of the timer and the PWM. This IP block is a core component of the Andes AE350 platform, which serves as a reference architecture for SoC designs. The QiLai SoC also integrates this controller. The binding introduces the following compatible strings: - "andestech,qilai-pwm": For the implementation integrated into the Andes QiLai SoC. - "andestech,ae350-pwm": As a fallback compatible string representing the base IP design used across the AE350 platform architecture. Reviewed-by: Rob Herring (Arm) Signed-off-by: Ben Zong-You Xie --- .../bindings/pwm/andestech,ae350-pwm.yaml | 61 ++++++++++++++++++= ++++ 1 file changed, 61 insertions(+) diff --git a/Documentation/devicetree/bindings/pwm/andestech,ae350-pwm.yaml= b/Documentation/devicetree/bindings/pwm/andestech,ae350-pwm.yaml new file mode 100644 index 000000000000..287f3c62965f --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/andestech,ae350-pwm.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/andestech,ae350-pwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Andes PWM controller on AE350 platform + +description: + This controller has 4 channels and two clock sources. Each channel can + switch the clock source by programming the corresponding register. + +maintainers: + - Ben Zong-You Xie + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + oneOf: + - items: + - enum: + - andestech,qilai-pwm + - const: andestech,ae350-pwm + - const: andestech,ae350-pwm + + reg: + maxItems: 1 + + "#pwm-cells": + const: 3 + + clocks: + items: + - description: APB bus clock + - description: External clock + + clock-names: + items: + - const: pclk + - const: extclk + +required: + - compatible + - reg + - "#pwm-cells" + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + pwm@f0400000 { + compatible =3D "andestech,ae350-pwm"; + reg =3D <0xf0400000 0x100000>; + #pwm-cells =3D <3>; + clocks =3D <&pclk>, <&extclk>; + clock-names =3D "pclk", "extclk"; + }; --=20 2.34.1 From nobody Wed Jul 1 02:24:06 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 BCEAD373BE7; Thu, 25 Jun 2026 10:36:01 +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=1782383761; cv=none; b=N8koAOG9bknzuImwRaLrfixeThlIwmLmZyOvuhQnwRikASyP5BoBAFlPzWoObhhwjSgYHBmivoeLLkcVHr/R01aufhgWvPskrPL7P/Bg1qlTLpKBkmQehSuLuO1HALaki2IM6+zHigiS2xrBCVxRw3zMLCJ1LxJEcbubvFSS8+A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782383761; c=relaxed/simple; bh=V/xpxofHZMmMUQDTiMKgFy9hguNnHuliNlESozlfCmo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qayRCzn87fGYFxjwLPnv73iB5cuEYWZDsJ5imsczTmruZUoHhT4jocXPa/TRFVKRf070/k4Ogbf3Dk07+Nls7jpvDoDt2t+feR27dVcQpkZHcvZfw1GKT+8oZwAGrH7m13EHLABe/bOCP/O6Tdd4uPCklh/uWHettXdmxyRishQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GqqgRWca; 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="GqqgRWca" Received: by smtp.kernel.org (Postfix) with ESMTPS id 87FB5C2BCF5; Thu, 25 Jun 2026 10:36:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1782383761; bh=V/xpxofHZMmMUQDTiMKgFy9hguNnHuliNlESozlfCmo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=GqqgRWcadcO1cH+eYzWNIRS0NgCoHTy7qfaLx0gbI+jB4zDMqwAYLXk83OJrMN3ME CwwQZFXlEzIU+3NilraXaJvRuXDpCnk4qSIzSF66MdUL9kUda8kjeWBQYGYBVysAF/ 7d7gUqWKO2bmxvxXap6j80pPW+fwB3HkEPViZgV6khuNWUecLEkw75r0EFSjjHhGwm 3l0p4R9dvJ1qAd6LcNfB+aB3mYL7szKvfq2u2zIKGG14ZT8nIEIMIxmWpLt4Q0257U Gok4FL/DaovCM4I+3XTA/O5yCia2FLh/oocizwKhYGJu4aICYsY4p8J/SH5IBD2wIu ws80FzcTopFzg== 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 7E9A0CDE008; Thu, 25 Jun 2026 10:36:01 +0000 (UTC) From: Ben Zong-You Xie via B4 Relay Date: Thu, 25 Jun 2026 18:36:00 +0800 Subject: [PATCH v6 2/3] pwm: add Andes PWM driver support 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: <20260625-andes-pwm-v6-2-3aef11711017@andestech.com> References: <20260625-andes-pwm-v6-0-3aef11711017@andestech.com> In-Reply-To: <20260625-andes-pwm-v6-0-3aef11711017@andestech.com> To: =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Ben Zong-You Xie X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=ed25519-sha256; t=1782383760; l=13980; i=ben717@andestech.com; s=20260120; h=from:subject:message-id; bh=AeNAEuqKCu4wIQadkRX6O5xxlYmreFQAyeoXC5E/v0s=; b=kjoDeoZ5u/vsxKTE97hCJloymKEVWRcwJEyk1Z4fIaxlm6ia+NNfc6E9OlQ0o0WWUCodwjzyl sy3l4L0Jw6vA1DT7l9JbRCFk7haVa/Vay2EnW1joVqHEc4bvimoBzVh X-Developer-Key: i=ben717@andestech.com; a=ed25519; pk=nb8L7zQKGJpYk0yvrYKjViOZ34A36g1ZIsCmCsP518s= X-Endpoint-Received: by B4 Relay for ben717@andestech.com/20260120 with auth_id=610 X-Original-From: Ben Zong-You Xie Reply-To: ben717@andestech.com From: Ben Zong-You Xie Add a driver for the PWM controller found in Andes AE350 platforms and QiLai SoCs. The Andes PWM controller features: - 4 independent channels. - Dual clock source support (APB clock and external clock) to provide a flexible range of frequencies. - Support for normal and inversed polarity. The driver implements the .apply() and .get_state() callbacks. Since the clock source of each channel can be selected by programming the register, clock selection logic is implemented to prioritize the external clock to maximize the supported period range, falling back to the APB clock for higher frequency requirements. Signed-off-by: Ben Zong-You Xie --- drivers/pwm/Kconfig | 10 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-andes.c | 343 ++++++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 354 insertions(+) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index e8886a9b64d9..52dee4b7f081 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -73,6 +73,16 @@ config PWM_AIROHA To compile this driver as a module, choose M here: the module will be called pwm-airoha. =20 +config PWM_ANDES + tristate "Andes PWM support" + depends on ARCH_ANDES || COMPILE_TEST + help + Generic PWM framework driver for Andes platform, such as QiLai SoC + and AE350 platform. + + To compile this driver as a module, choose M here: the module + will be called pwm-andes. + config PWM_APPLE tristate "Apple SoC PWM support" depends on ARCH_APPLE || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 5630a521a7cf..c92369ee251d 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_PWM) +=3D core.o obj-$(CONFIG_PWM_AB8500) +=3D pwm-ab8500.o obj-$(CONFIG_PWM_ADP5585) +=3D pwm-adp5585.o obj-$(CONFIG_PWM_AIROHA) +=3D pwm-airoha.o +obj-$(CONFIG_PWM_ANDES) +=3D pwm-andes.o obj-$(CONFIG_PWM_APPLE) +=3D pwm-apple.o obj-$(CONFIG_PWM_ARGON_FAN_HAT) +=3D pwm-argon-fan-hat.o obj-$(CONFIG_PWM_ATMEL) +=3D pwm-atmel.o diff --git a/drivers/pwm/pwm-andes.c b/drivers/pwm/pwm-andes.c new file mode 100644 index 000000000000..580e673d2cff --- /dev/null +++ b/drivers/pwm/pwm-andes.c @@ -0,0 +1,343 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Andes PWM, used in Andes AE350 platform and QiLai SoC + * + * Copyright (C) 2026 Andes Technology Corporation. + * + * Limitations: + * - When disabling a channel, the current period is not completed and the + * output is driven to the PARK level (low when ANDES_PWM_CH_CTRL_PARK is + * clear, high when it is set). + * - The current period will be completed first if reconfiguring. + * - Further, if the reconfiguration changes the clock source, the output = will + * not be the old one nor the new one. And the output will be the new one + * after writing to the reload register. + * - The hardware cannot run a 0% or 100% relative duty cycle; the driver + * emulates these by disabling the channel and parking the output at the + * constant level. + * - A period or duty cycle larger than the selected clock can represent is + * rounded down to the largest achievable value rather than rejected. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ANDES_PWM_CH_ENABLE 0x1C +#define ANDES_PWM_CH_ENABLE_PWM(ch) BIT(3 + (4 * (ch))) + +#define ANDES_PWM_CH_CTRL(ch) (0x20 + (0x10 * (ch))) +#define ANDES_PWM_CH_CTRL_MODE_PWM BIT(2) +#define ANDES_PWM_CH_CTRL_CLK BIT(3) +#define ANDES_PWM_CH_CTRL_PARK BIT(4) +#define ANDES_PWM_CH_CTRL_MASK GENMASK(4, 0) + +#define ANDES_PWM_CH_RELOAD(ch) (0x24 + (0x10 * (ch))) +#define ANDES_PWM_CH_RELOAD_HIGH GENMASK(31, 16) +#define ANDES_PWM_CH_RELOAD_LOW GENMASK(15, 0) + +#define ANDES_PWM_CH_COUNTER(ch) (0x28 + (0x10 * (ch))) + +#define ANDES_PWM_CH_MAX 4 +#define ANDES_PWM_CYCLE_MIN 1 +#define ANDES_PWM_CYCLE_MAX 0x10000 + +struct andes_pwm { + struct regmap *regmap; + struct clk *pclk; + struct clk *extclk; + unsigned int pclk_rate; + unsigned int extclk_rate; +}; + +static const struct regmap_config andes_pwm_regmap_config =3D { + .name =3D "andes_pwm", + .reg_bits =3D 32, + .reg_stride =3D 4, + .val_bits =3D 32, + .pad_bits =3D 0, + .max_register =3D ANDES_PWM_CH_COUNTER(ANDES_PWM_CH_MAX - 1), + .cache_type =3D REGCACHE_NONE, +}; + +static inline struct andes_pwm *andes_pwm_from_chip(struct pwm_chip *chip) +{ + return pwmchip_get_drvdata(chip); +} + +static int andes_pwm_enable(struct pwm_chip *chip, unsigned int channel, + bool enable) +{ + struct andes_pwm *ap =3D andes_pwm_from_chip(chip); + + return regmap_assign_bits(ap->regmap, ANDES_PWM_CH_ENABLE, + ANDES_PWM_CH_ENABLE_PWM(channel), enable); +} + +/* + * Hold the output at a constant level by parking the disabled channel. A + * disabled channel drives its output to the PARK level (low when @high is + * false, high when @high is true), which is used to emulate a 0% or 100% + * relative duty cycle. + */ +static int andes_pwm_park(struct pwm_chip *chip, unsigned int channel, + bool high) +{ + struct andes_pwm *ap =3D andes_pwm_from_chip(chip); + + regmap_assign_bits(ap->regmap, ANDES_PWM_CH_CTRL(channel), + ANDES_PWM_CH_CTRL_PARK, high); + + return andes_pwm_enable(chip, channel, false); +} + +static int andes_pwm_config(struct pwm_chip *chip, unsigned int channel, + const struct pwm_state *state) +{ + struct andes_pwm *ap =3D andes_pwm_from_chip(chip); + unsigned int clk_rate =3D ap->extclk_rate; + unsigned int ctrl =3D ANDES_PWM_CH_CTRL_MODE_PWM; + bool use_pclk =3D false; + u64 high_cycles; + u64 low_cycles; + u64 period_cycles; + u64 duty_cycles; + u32 reload; + + /* + * Reload register for PWM mode: + * + * 31 : 16 15 : 0 + * PWM16_Hi | PWM16_Lo + * + * The high duration is (PWM16_Hi + 1) cycles and the low duration is + * (PWM16_Lo + 1) cycles, so each phase spans ANDES_PWM_CYCLE_MIN to + * ANDES_PWM_CYCLE_MAX cycles. The hardware period (their sum) can reach + * 2 * ANDES_PWM_CYCLE_MAX cycles, but the PWM core requires the period + * to be chosen from the requested period alone, independent of the duty + * cycle. That holds only while both phases stay within + * ANDES_PWM_CYCLE_MAX for every duty split, so the usable period is + * capped at ANDES_PWM_CYCLE_MAX + ANDES_PWM_CYCLE_MIN cycles. + * + * The controller has two clock sources, the APB clock and an external + * clock. Since the external clock frequency must be slower than the APB + * clock, it is tried first for its wider period range; the APB clock is + * used only when the external clock is too fast to represent the period + * (it resolves fewer than two cycles) or is absent. + */ + period_cycles =3D mul_u64_u64_div_u64(clk_rate, state->period, + NSEC_PER_SEC); + if (period_cycles < 2 * ANDES_PWM_CYCLE_MIN) { + use_pclk =3D true; + clk_rate =3D ap->pclk_rate; + period_cycles =3D mul_u64_u64_div_u64(clk_rate, state->period, + NSEC_PER_SEC); + if (period_cycles < 2 * ANDES_PWM_CYCLE_MIN) + return -EINVAL; + } + + /* + * Round the period down to the largest value representable for every + * duty cycle, so the chosen period depends on the requested period + * alone. With both phases capped at ANDES_PWM_CYCLE_MAX, that bound is + * ANDES_PWM_CYCLE_MAX + ANDES_PWM_CYCLE_MIN cycles. + */ + period_cycles =3D min_t(u64, period_cycles, + ANDES_PWM_CYCLE_MAX + ANDES_PWM_CYCLE_MIN); + + /* The duty cycle cannot exceed the (possibly clamped) period. */ + duty_cycles =3D mul_u64_u64_div_u64(clk_rate, state->duty_cycle, + NSEC_PER_SEC); + duty_cycles =3D min_t(u64, duty_cycles, period_cycles); + if (state->polarity =3D=3D PWM_POLARITY_INVERSED) { + low_cycles =3D duty_cycles; + high_cycles =3D period_cycles - low_cycles; + } else { + high_cycles =3D duty_cycles; + low_cycles =3D period_cycles - high_cycles; + } + + /* + * A zero-length phase means a 0% or 100% relative duty cycle, which the + * hardware cannot run. Emit the matching constant level by parking the + * channel: high_cycles =3D=3D 0 stays low, low_cycles =3D=3D 0 stays hig= h. + */ + if (!high_cycles) + return andes_pwm_park(chip, channel, false); + if (!low_cycles) + return andes_pwm_park(chip, channel, true); + + /* + * If changing the clock source here, the output will not be the old one + * nor the new one. And the output will be the new one after writing to + * the reload register. + */ + ctrl |=3D use_pclk ? ANDES_PWM_CH_CTRL_CLK : 0; + ctrl |=3D (state->polarity =3D=3D PWM_POLARITY_INVERSED) ? + ANDES_PWM_CH_CTRL_PARK : 0; + regmap_update_bits(ap->regmap, ANDES_PWM_CH_CTRL(channel), + ANDES_PWM_CH_CTRL_MASK, ctrl); + reload =3D FIELD_PREP(ANDES_PWM_CH_RELOAD_HIGH, high_cycles - 1) | + FIELD_PREP(ANDES_PWM_CH_RELOAD_LOW, low_cycles - 1); + regmap_write(ap->regmap, ANDES_PWM_CH_RELOAD(channel), reload); + return andes_pwm_enable(chip, channel, true); +} + +static int andes_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + unsigned int channel =3D pwm->hwpwm; + + if (!state->enabled) { + if (pwm->state.enabled) + andes_pwm_enable(chip, channel, false); + + return 0; + } + + return andes_pwm_config(chip, channel, state); +} + +static int andes_pwm_get_state(struct pwm_chip *chip, struct pwm_device *p= wm, + struct pwm_state *state) +{ + struct andes_pwm *ap =3D andes_pwm_from_chip(chip); + unsigned int channel =3D pwm->hwpwm; + unsigned int ctrl; + unsigned int clk_rate; + unsigned int reload; + u64 high_cycles; + u64 low_cycles; + + regmap_read(ap->regmap, ANDES_PWM_CH_CTRL(channel), &ctrl); + clk_rate =3D FIELD_GET(ANDES_PWM_CH_CTRL_CLK, ctrl) ? ap->pclk_rate + : ap->extclk_rate; + if (!clk_rate) { + /* + * The selected clock source is unavailable, so the channel + * cannot be running; report it as disabled and avoid the + * division by zero below. + */ + state->enabled =3D false; + state->period =3D 0; + state->duty_cycle =3D 0; + return 0; + } + + state->enabled =3D regmap_test_bits(ap->regmap, ANDES_PWM_CH_ENABLE, + ANDES_PWM_CH_ENABLE_PWM(channel)) > 0; + state->polarity =3D FIELD_GET(ANDES_PWM_CH_CTRL_PARK, ctrl) ? + PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL; + regmap_read(ap->regmap, ANDES_PWM_CH_RELOAD(channel), &reload); + high_cycles =3D FIELD_GET(ANDES_PWM_CH_RELOAD_HIGH, reload) + 1; + low_cycles =3D FIELD_GET(ANDES_PWM_CH_RELOAD_LOW, reload) + 1; + + /* + * high_cycles and low_cycles are each at most ANDES_PWM_CYCLE_MAX + * (0x10000, 17 bits) and NSEC_PER_SEC is below 2^30, so the products + * below are safe from 64-bit overflow. + */ + if (state->polarity =3D=3D PWM_POLARITY_INVERSED) + state->duty_cycle =3D DIV_ROUND_UP_ULL(low_cycles * NSEC_PER_SEC, + clk_rate); + else + state->duty_cycle =3D DIV_ROUND_UP_ULL(high_cycles * NSEC_PER_SEC, + clk_rate); + + state->period =3D DIV_ROUND_UP_ULL((high_cycles + low_cycles) * + NSEC_PER_SEC, clk_rate); + + return 0; +} + +static const struct pwm_ops andes_pwm_ops =3D { + .apply =3D andes_pwm_apply, + .get_state =3D andes_pwm_get_state, +}; + +static int andes_pwm_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct pwm_chip *chip; + struct andes_pwm *ap; + void __iomem *reg_base; + unsigned long pclk_rate; + unsigned long extclk_rate; + int ret; + + chip =3D devm_pwmchip_alloc(dev, ANDES_PWM_CH_MAX, sizeof(*ap)); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + ap =3D andes_pwm_from_chip(chip); + reg_base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg_base)) + return dev_err_probe(dev, PTR_ERR(reg_base), + "Failed to map I/O space\n"); + + ap->pclk =3D devm_clk_get_enabled(dev, "pclk"); + if (IS_ERR(ap->pclk)) + return dev_err_probe(dev, PTR_ERR(ap->pclk), + "Failed to get APB clock\n"); + + ap->extclk =3D devm_clk_get_optional_enabled(dev, "extclk"); + if (IS_ERR(ap->extclk)) + return dev_err_probe(dev, PTR_ERR(ap->extclk), + "Failed to get external clock\n"); + + /* + * If the clock rate is greater than 10^9, there may be an overflow when + * calculating the cycles in andes_pwm_config() + */ + pclk_rate =3D clk_get_rate(ap->pclk); + extclk_rate =3D clk_get_rate(ap->extclk); + + ap->pclk_rate =3D pclk_rate > NSEC_PER_SEC ? 0 : pclk_rate; + ap->extclk_rate =3D extclk_rate > NSEC_PER_SEC ? 0 : extclk_rate; + + if (!ap->pclk_rate && !ap->extclk_rate) + return dev_err_probe(dev, -EINVAL, + "No usable clock: pclk %lu Hz, extclk %lu Hz\n", + pclk_rate, extclk_rate); + + ap->regmap =3D devm_regmap_init_mmio(dev, reg_base, + &andes_pwm_regmap_config); + if (IS_ERR(ap->regmap)) + return dev_err_probe(dev, PTR_ERR(ap->regmap), + "Failed to initialize regmap\n"); + + chip->ops =3D &andes_pwm_ops; + ret =3D devm_pwmchip_add(dev, chip); + if (ret) + return dev_err_probe(dev, ret, "Failed to add PWM chip\n"); + + return 0; +} + +static const struct of_device_id andes_pwm_of_match[] =3D { + { .compatible =3D "andestech,ae350-pwm" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, andes_pwm_of_match); + +static struct platform_driver andes_pwm_driver =3D { + .driver =3D { + .name =3D "andes_pwm", + .of_match_table =3D andes_pwm_of_match, + }, + .probe =3D andes_pwm_probe, +}; +module_platform_driver(andes_pwm_driver); + +MODULE_AUTHOR("Ben Zong-You Xie "); +MODULE_DESCRIPTION("Andes PWM driver"); +MODULE_LICENSE("GPL"); --=20 2.34.1 From nobody Wed Jul 1 02:24:06 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 D3A0F3D1AA6; Thu, 25 Jun 2026 10:36:01 +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=1782383761; cv=none; b=nOWIgDHdjGCXwSUCnyKU44A7Weg5xOWavTehlJZZVBCb3rWLkbaPV6gh/wa3GY4heM41yozcYf6NCQ3k3KwJmZ0PVWBwLwtsWR23dm5CMFIyl0QoeIeuAWyrU5nnDsZwyq86ajimMzwdTz2kkGKfsqQ9DSsQbjt4xiHjWc1khUo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782383761; c=relaxed/simple; bh=DZvJXYwiTn7NaQnx79Z9NMXtL6h62xhj1D2k3BWDEaI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kpvNdh2ZL3+F+BmSYESTEI98ZHRXwFwBud5Y7EGNZG1Hi/Xt8Bvz9WR9c2uS4f8DQNEZYAHWcdFIbd031WrBotAtnHxiL8TiHe1DOfy3rjzVeMbkmvbhTP0a3sE68ZXBTDczpushY83k3S5+iVKUAXg1IFCt790zNPSB4C9Qlro= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WPUslhaH; 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="WPUslhaH" Received: by smtp.kernel.org (Postfix) with ESMTPS id A4F42C2BCF6; Thu, 25 Jun 2026 10:36:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1782383761; bh=DZvJXYwiTn7NaQnx79Z9NMXtL6h62xhj1D2k3BWDEaI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=WPUslhaHiqqAYzxRNGnTQgsvCNQR+2oDI9yXqoky75kZR/x81bFOc5Xzh7+MgdfiL ysexmd0RIVhtPGVQRZpHK96qG9XMYjl7xgRvdLVJ4F/cBaMGWfiT3f/pekSWsbdkQc tanviBJkqZ6Rfy1p2JvkfevoHQx60/7JOxsYtKygT1LUrdy/qB7qhIeerKaZHkuRmX x2fuTkvqegreUOx6Oyk7nNZtMVVfkuGVMCWotsD2ylAtLDjMGlPozi5PH0EJw8mX9V LWFMqSJuLx4wlkR46/3Twdgysnlo7/SHobFULVV+ssz6AVdPzEf6WZlLOXFrTn/iiC 6vmv5T9brsGdQ== 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 9B6F8CDE009; Thu, 25 Jun 2026 10:36:01 +0000 (UTC) From: Ben Zong-You Xie via B4 Relay Date: Thu, 25 Jun 2026 18:36:01 +0800 Subject: [PATCH v6 3/3] MAINTAINERS: add an entry for Andes PWM driver 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: <20260625-andes-pwm-v6-3-3aef11711017@andestech.com> References: <20260625-andes-pwm-v6-0-3aef11711017@andestech.com> In-Reply-To: <20260625-andes-pwm-v6-0-3aef11711017@andestech.com> To: =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Ben Zong-You Xie X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=ed25519-sha256; t=1782383760; l=754; i=ben717@andestech.com; s=20260120; h=from:subject:message-id; bh=yOiq6thqiSeGFGixy89XEZx9mM4JZgZkT7AgxcDK7ko=; b=3zYmry0MbDfZ6qEOXl09L9iveMPJuWXQdFkAsLJqEBaLVnC/WxE0FjOMNW2tHIGCW48tzduCu jW/JYPmXp5BCJRtCuy3qzrIjeTSODMUpfYS1829cqEChoOIeWRaQOWv X-Developer-Key: i=ben717@andestech.com; a=ed25519; pk=nb8L7zQKGJpYk0yvrYKjViOZ34A36g1ZIsCmCsP518s= X-Endpoint-Received: by B4 Relay for ben717@andestech.com/20260120 with auth_id=610 X-Original-From: Ben Zong-You Xie Reply-To: ben717@andestech.com From: Ben Zong-You Xie Add an entry for the Andes PWM driver to the MAINTAINERS file. Signed-off-by: Ben Zong-You Xie --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2fb1c75afd16..2461683a5bbb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1874,6 +1874,12 @@ S: Supported F: Documentation/devicetree/bindings/spi/andestech,ae350-spi.yaml F: drivers/spi/spi-atcspi200.c =20 +ANDES PWM DRIVER +M: Ben Zong-You Xie +S: Supported +F: Documentation/devicetree/bindings/pwm/andestech,ae350-pwm.yaml +F: drivers/pwm/pwm-andes.c + ANDROID DRIVERS M: Greg Kroah-Hartman M: Arve Hj=C3=B8nnev=C3=A5g --=20 2.34.1