From patchwork Thu Mar 5 09:19:55 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Genoud X-Patchwork-Id: 30 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (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 86D892C375E for ; Thu, 5 Mar 2026 09:20:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772702428; cv=none; b=fKDkg9AGpJTPBrTQIovsMDCxN+pU0LC46BkV7hSZ5sv53UlWGPmRlzpVPCjMZfDJVIA4AFgLSuYCT0LMrEbqNxjhym8wd0snADdIMeL6SuL8X30Cj/S6AROTI65hr1NrETH82IYqFMjyBJ1955FbXFARNQkk1IrdFVy46wxlGmY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772702428; c=relaxed/simple; bh=DD5lYpM6XZ+Usu3exk9H3DdSb0hJben/UXTnT6KdqKM=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=frfod3xFs0krj95dRT/6ZMlMJGw+OVfeEufQz6KWKeYgO5QgNuRbAt9y3GlzbTSYdNm7yQrg3gSRQZhQU78t82jW5Y+en44GM+qWcSbR63J5dqb75sTiFSEpb3y48Voz724HO/0Nyli5XoKCtq/hwyuRdfIbmQTVJj5D5qxpjOw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=UmZ3SJc0; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="UmZ3SJc0" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id DF7F81A2CD6; Thu, 5 Mar 2026 09:20:24 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id B25105FDEB; Thu, 5 Mar 2026 09:20:24 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 1E4B710369570; Thu, 5 Mar 2026 10:20:14 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1772702420; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding; bh=UkvhX1eGnzYEIZ/ydvqM1n36ebV8YAFKvf0gHruqeB0=; b=UmZ3SJc0Zji3xNMUrwvviAdpYax1HkPBKYFgvhsumSNQGNzWVHEmHhfkt+TkttVf/aqP6t eWexiZkQlFooD2ryhEgv3UKafV+ataLrHzMtcL4pIpyjJia9HCnm2HrJTbHfOZ4MIAeX0I xy2g/UG55w0ScsDkuLPiBrzzSJNRTupLfbtmd/ue8kbmbf3mkcfY9XdklCsncL73Z5mdEI E0j76e3CA6eXc1UhKjgmdiyvsBMXSt9MHB0xH87vWcslY2eb2bJ9vTop59QT4Xy83y80u/ TbqaVS74poxBdKumJkC25nX73HnaIGsTNK30lyh5BPy7KJ1injH+ky167S+gPQ== From: Richard Genoud To: =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Philipp Zabel Cc: Paul Kocialkowski , Thomas Petazzoni , John Stultz , Joao Schim , linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, Richard Genoud Subject: [PATCH v4 0/4] Introduce Allwinner H616 PWM controller Date: Thu, 5 Mar 2026 10:19:55 +0100 Message-ID: <20260305091959.2530374-1-richard.genoud@bootlin.com> X-Mailer: git-send-email 2.47.3 Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 Status: O Allwinner H616 PWM controller is quite different from the A10 one. It can drive 6 PWM channels, and like for the A10, each channel has a bypass that permits to output a clock, bypassing the PWM logic, when enabled. But, the channels are paired 2 by 2, sharing a first set of MUX/prescaler/gate. Then, for each channel, there's another prescaler (that will be bypassed if the bypass is enabled for this channel). It looks like that: _____ ______ ________ OSC24M --->| | | | | | APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy |_____| |______| |________| ________ | | +->| /div_k |---> PWM_clock_x | |________| | ______ | | | +-->| Gate |----> PWM_bypass_clock_x | |______| PWM_clock_src_xy -----+ ________ | | | +->| /div_k |---> PWM_clock_y | |________| | ______ | | | +-->| Gate |----> PWM_bypass_clock_y |______| Where xy can be 0/1, 2/3, 4/5 PWM_clock_x/y serve for the PWM purpose. PWM_bypass_clock_x/y serve for the clock-provider purpose. The common clock framework has been used to manage those clocks. This PWM driver serves as a clock-provider for PWM_bypass_clocks. This is needed for example by the embedded AC300 PHY which clock comes from PMW5 pin (PB12). Usually, to get a clock from a PWM driver, we use the pwm-clock driver so that the PWM driver doesn't need to be a clk-provider itself. While this works in most cases, here it just doesn't. That's because the pwm-clock request a period from the PWM driver, without any clue that it actually wants a clock at a specific frequency, and not a PWM signal with duty cycle capability. So, the PWM driver doesn't know if it can use the bypass or not, it doesn't even have the real accurate frequency information (23809524 Hz instead of 24MHz) because PWM drivers only deal with periods. With pwm-clock, we loose a precious information along the way (that we actually want a clock and not a PWM signal). That's ok with simple PWM drivers that don't have multiple input clocks, but in this case, without this information, we can't know for sure which clock to use. And here, for instance, if we ask for a 24MHz clock, pwm-clock will requests 42ns (assigned-clocks doesn't help for that matter). The logic is to select the highest clock (100MHz) with no prescaler and a duty cycle value of 2/4 => we have 25MHz instead of 24MHz. And that's a perfectly fine choice for a PMW, because we still can change the duty cycle in the range [0-4]/4. But obviously for a clock, we don't care about the duty cycle, but more about the clock accuracy. And actually, this PWM is really a PWM AND a real clock when the bypass is set. This series is based onto v6.19-rc4 NB: checkpatch is not happy with patch 2, but it's a false positive. It doesn't detect that PWM_XY_SRC_MUX/GATE/DIV are structures, but as it's more readable like that, I prefer keeping it that way. NB2: for geopolitical reasons, I didn't re-use the old series that Paul was referring to. Changes since v3: - gather Acked-by/Tested-by - fix cast from pointer to integer of different size (kernel test robot with arc platform) - add devm_action for clk_hw_unregister_composite as suggested by Philipp - remove now unused pwm_remove as suggested by Philipp Changes since v2: - use U32_MAX instead of defining UINT32_MAX - add a comment on U32_MAX usage in clk_round_rate() - change clk_table_div_m (use macros) - fix formatting (double space, superfluous comma, extra line feed) - fix the parent clock order - simplify code by using scoped_guard() - add missing const in to_h616_pwm_chip() and rename to h616_pwm_from_chip() - add/remove missing/superflous error messages - rename cnt->period_ticks, duty_cnt->duty_ticks - fix PWM_PERIOD_MAX - add .remove() callback - fix DIV_ROUND_CLOSEST_ULL->DIV_ROUND_UP_ULL - add H616_ prefix - protect _reg in macros - switch to waveforms instead of apply/get_state - shrink struct h616_pwm_channel - rebase on v6.19-rc4 Changes since v1: - rebase onto v6.19-rc1 - add missing headers - remove MODULE_ALIAS (suggested by Krzysztof) - use sun4i-pwm binding instead of creating a new one (suggested by Krzysztof) - retrieve the parent clocks from the devicetree - switch num_parents to unsigned int Richard Genoud (4): dt-bindings: pwm: allwinner: add h616 pwm compatible pwm: sun50i: Add H616 PWM support arm64: dts: allwinner: h616: add PWM controller MAINTAINERS: Add entry on Allwinner H616 PWM driver .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml | 19 +- MAINTAINERS | 5 + .../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 47 + drivers/pwm/Kconfig | 12 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-sun50i-h616.c | 936 ++++++++++++++++++ 6 files changed, 1019 insertions(+), 1 deletion(-) create mode 100644 drivers/pwm/pwm-sun50i-h616.c base-commit: 11439c4635edd669ae435eec308f4ab8a0804808