* Re: [PATCH RFC 0/4] arm64: rockchip: The hunt for exact pixel clocks on RK3576
From: Sebastian Reichel @ 2026-04-17 22:24 UTC (permalink / raw)
To: Alexey Charkov
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Michael Turquette, Stephen Boyd, Pavel Zhovner, Andy Yan,
devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
linux-clk, Cristian Ciocaltea
In-Reply-To: <20260417-rk3576-dclk-v1-0-26a9d0dcb2de@flipper.net>
[-- Attachment #1: Type: text/plain, Size: 6942 bytes --]
Hello Alexey,
On Fri, Apr 17, 2026 at 07:11:43PM +0400, Alexey Charkov wrote:
> Dear all,
>
> Need the help of the collective wisdom of the community.
>
> The problem I'm trying to solve is reliably obtaining the exact pixel
> clock for arbitrary display modes supported by the RK3576 SoC.
>
> Rockchip RK3576 has three display output processors VP0~VP2, each
> supporting different ranges of display modes, roughly as follows:
> - VP0: 4K 120Hz
> - VP1: 2.5k 60Hz
> - VP2: 1080p 60Hz
>
> Each one obviously needs a pixel clock. The required frequencies for the
> pixel clocks vary greatly depending on the display mode, and need to be
> matched within a tight tolerance, or else many displays will refuse to
> work. E.g. the preferred (maximum) display mode out of VP1 is particularly
> awkward, because it requires a pixel clock of 248.88 MHz, which cannot
> be obtained using integer dividers from its default clock source (GPLL
> at 1188 MHz), and the nearest approximation is 237.6 MHz, which is well
> outside the tolerance of e.g. DP specification, resulting in a blank
> screen on most displays by default.
>
> The clock sources are of course configurable, in particular there are muxes
> connected to each VP for selecting the source of the pixel clock:
> - Each VP can take the clock either from the (single!) HDMI PHY or from
> its dedicated dclk_vpX_src mux
> - The dclk_vpX_src mux can select the clock from a number of system PLLs
> (GPLL, CPLL, VPLL, BPLL, LPLL)
>
> While the system PLLs can be configured to output a wide range of
> frequencies, they are shared between many system components. E.g. on the
> current mainline kernel on one of my RK3576 boards I've got the following:
> GPLL: 1188 MHz, enable count 20
> CPLL: 1000 MHz, enable count 17
> VPLL: 594 MHz, enable count 0 (yaay!)
> BPLL, LPLL: 816 MHz, enable count 0 (but these last ones don't have
> predividers, so are less flexible)
>
> So ultimately there is exactly one free fractional PLL (VPLL) which can be
> used to generate arbitrary pixel clocks, but we have up to three consumers
> trying to drive different display modes from it (e.g. HDMI on VP0, DP on
> VP1 and MIPI DSI on VP2). We also want to be able to adjust the PLL output
> frequency on the fly to satisfy the requirements of the selected display
> mode.
>
> And this is where I'm stuck. Trying to satisfy the requirements of up to
> three consumers while changing the PLL frequency on the fly sounds like
> a poorly tractable mathematical problem (is it 3-SAT?). We can take the
> HDMI output out of the equation, because it can be driven from the HDMI
> PHY (which is capable of arbitrary rates) instead of the mux, but that
> makes the decision of which dclk source to use for a VP block dependent on
> which downstream consumer is connected to it (HDMI vs. something else).
It becomes more messy: The HDMI PHY cannot be used as clock source
for modes exceeding 4K@60Hz.
> Even then we somehow need two devices to cooperate in picking a PLL
> frequency that satisfies the requirements of both of them, and change to it
> without display corruption. I'm not even sure if the CCF has mechanisms
> for that?..
>
> What follows is a brief set of patches which illustrate a partial solution
> for the case of "I just need 2.5k60Hz on VP1 via DP and don't care about
> the rest". It switches the VP1 unconditionally to use VPLL as the source
> for its dclk mux, allows changing the VPLL frequency on the fly, and also
> changes the frequency calculation logic to allow for nearest-match
> frequencies which are not necessarily rounded down. These are not meant
> to be merged as-is, as I see the following issues:
> - The flag allowing the PLL to change rate is in the clock driver, while
> the reparenting to an unused PLL is in the device tree. If these go out
> of sync, we might end up trying to change the frequency of a PLL which
> is used by other consumers (I presume that could be dangerous)
It is a problem, see e.g. this patch from Heiko removing the flag
for an RK3588 VOP source clock:
https://lore.kernel.org/linux-rockchip/20251008133135.3745785-1-heiko@sntech.de/
Also note, that there is some more general ongoing work regarding
this:
See: https://lore.kernel.org/linux-clk/20260327-clk-scaling-v8-0-86cd0aba3c5f@redhat.com/
> - If VP0 happens to be driving DP output, it won't be able to produce the
> 2560x1440@60Hz mode for the same reasons as VP1 - then it must also be
> reparented to VPLL and allowed to change its frequency on the fly
There is also the problem that nearest match might be sensible for the
display, but is not generally safe. For other clocks you might
effectively overclock, which shouldn't be done by default.
> It does bring me from a state of "always blank screen on DP output until
> the mode is switched to something magically working" to a state of
> "most monitors work at the default preferred mode" though.
>
> It is tempting to just reparent both VP0 and VP1 to VPLL and allow both of
> them to change its frequency, while leaving VP2 on the default (fixed)
> GPLL and relying on the fact that 148.5 MHz (the required frequency for
> its maximum supported mode of 1920x1080@60Hz) is conveniently 1188/8 MHz -
> just what GPLL can provide. Then also force whichever VP is driving HDMI
> output to use the HDMI PHY as its clock source. But we still have the
> problem of DT vs. driver coordination, and I'm not sure how to define
> the policy for "if you've got HDMI connected, you must use the HDMI PHY
> clock for the respective VP, whichever VP that is".
Sorry, I don't have any complete solutions - except that I can tell
you that the VOP2 driver already automatically switches the clock
source to the HDMI PHY for HDMI outputs if the pixel rates allows it:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c#n1757
Greetings,
-- Sebastian
> I would very much appreciate any thoughts on how to approach this.
>
> Signed-off-by: Alexey Charkov <alchark@flipper.net>
> ---
> Alexey Charkov (4):
> arm64: dts: rockchip: rk3576: assign dclk_vp1_src to VPLL
> clk: rockchip: pll: use round-nearest in determine_rate
> clk: rockchip: rk3576: allow dclk_vp1_src to propagate rate to parent PLL
> clk: rockchip: rk3576: add ROUND_CLOSEST to dclk_vp1_src divider
>
> arch/arm64/boot/dts/rockchip/rk3576.dtsi | 2 ++
> drivers/clk/rockchip/clk-pll.c | 16 ++++++++--------
> drivers/clk/rockchip/clk-rk3576.c | 4 ++--
> 3 files changed, 12 insertions(+), 10 deletions(-)
> ---
> base-commit: c7275b05bc428c7373d97aa2da02d3a7fa6b9f66
> change-id: 20260417-rk3576-dclk-4c95bbb67581
>
> Best regards,
> --
> Alexey Charkov <alchark@flipper.net>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v4 2/6] dt-bindings: input: cpcap-pwrbutton: convert to DT schema
From: Rob Herring (Arm) @ 2026-04-17 21:53 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Tony Lindgren, Pavel Machek, devicetree, David Lechner,
linux-kernel, Conor Dooley, Dmitry Torokhov, Lee Jones,
linux-input, linux-leds, Krzysztof Kozlowski
In-Reply-To: <20260417071106.21984-3-clamor95@gmail.com>
On Fri, 17 Apr 2026 10:11:02 +0300, Svyatoslav Ryhel wrote:
> Convert power button devicetree bindings for the Motorola CPCAP MFD from
> TXT to YAML format. This patch does not change any functionality; the
> bindings remain the same.
>
> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> ---
> .../bindings/input/cpcap-pwrbutton.txt | 20 ------------
> .../input/motorola,cpcap-pwrbutton.yaml | 32 +++++++++++++++++++
> 2 files changed, 32 insertions(+), 20 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
> create mode 100644 Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
doc reference errors (make refcheckdocs):
Warning: Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Documentation/devicetree/bindings/mfd/motorola-cpcap.txt: Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
See https://patchwork.kernel.org/project/devicetree/patch/20260417071106.21984-3-clamor95@gmail.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply
* Re: [PATCH v4 1/6] dt-bindings: leds: leds-cpcap: convert to DT schema
From: Rob Herring (Arm) @ 2026-04-17 21:53 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: devicetree, Krzysztof Kozlowski, linux-input, Lee Jones,
Dmitry Torokhov, Conor Dooley, David Lechner, Pavel Machek,
Tony Lindgren, linux-leds, linux-kernel
In-Reply-To: <20260417071106.21984-2-clamor95@gmail.com>
On Fri, 17 Apr 2026 10:11:01 +0300, Svyatoslav Ryhel wrote:
> Convert LEDs devicetree bindings for the Motorola CPCAP MFD from TXT to
> YAML format. This patch does not change any functionality; the bindings
> remain the same.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> ---
> .../devicetree/bindings/leds/leds-cpcap.txt | 29 -------------
> .../bindings/leds/motorola,cpcap-leds.yaml | 42 +++++++++++++++++++
> 2 files changed, 42 insertions(+), 29 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/leds/leds-cpcap.txt
> create mode 100644 Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
doc reference errors (make refcheckdocs):
Warning: Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/leds/leds-cpcap.txt
Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Documentation/devicetree/bindings/mfd/motorola-cpcap.txt: Documentation/devicetree/bindings/leds/leds-cpcap.txt
See https://patchwork.kernel.org/project/devicetree/patch/20260417071106.21984-2-clamor95@gmail.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply
* Re: [PATCH v6 3/3] dts: s32g: Add GPR syscon region
From: Jared Kangas @ 2026-04-17 21:36 UTC (permalink / raw)
To: Dan Carpenter
Cc: Chester Lin, Matthias Brugger, Ghennadi Procopciuc,
NXP S32 Linux Team, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-kernel, imx,
devicetree, linux-kernel, linaro-s32, netdev
In-Reply-To: <0e922537c02d1c47734142090f98eb78e921ed34.1769764941.git.dan.carpenter@linaro.org>
Hi Dan,
On Fri, Jan 30, 2026 at 04:19:52PM +0300, Dan Carpenter wrote:
> Add the GPR syscon region for the s32 chipset.
>
> Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
> ---
>
> [snip]
>
> diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
> index e314f3c7d61d..be03db737384 100644
> --- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
> +++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
> @@ -383,6 +383,11 @@ usdhc0-200mhz-grp4 {
> };
> };
>
> + gpr: syscon@4007c000 {
> + compatible = "nxp,s32g3-gpr", "syscon";
> + reg = <0x4007c000 0x3000>;
> + };
> +
> ocotp: nvmem@400a4000 {
> compatible = "nxp,s32g3-ocotp", "nxp,s32g2-ocotp";
> reg = <0x400a4000 0x400>;
> @@ -808,6 +813,7 @@ gmac0: ethernet@4033c000 {
> compatible = "nxp,s32g2-dwmac";
> reg = <0x4033c000 0x2000>, /* gmac IP */
> <0x4007c004 0x4>; /* GMAC_0_CTRL_STS */
> + nxp,phy-sel = <&gpr 0x4>;
> interrupt-parent = <&gic>;
> interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
> interrupt-names = "macirq";
I gave this a test on an S32G-VNP-RDB3 and didn't see any issues on the
dwmac-s32 side, but this appears to trigger a panic when reading the new
debugfs regmap/*/registers file for the syscon node:
# grep 4007c000 /proc/vmallocinfo
0xffff800083da8000-0xffff800083dac000 16384 ioremap_prot+0x74/0xe0 phys=0x000000004007c000 ioremap
# cat /sys/kernel/debug/regmap/dummy-syscon@0x000000004007c000/registers
Internal error: synchronous external abort: 0000000096000210 [#1] SMP
[...]
CPU: 0 UID: 0 PID: 4344 Comm: cat Tainted: G M E X ------ --- 6.12.0+ #226 PREEMPT_RT
Tainted: [M]=MACHINE_CHECK, [E]=UNSIGNED_MODULE, [X]=AUX
[...]
pc : regmap_mmio_read32le+0x44/0xa0
lr : regmap_mmio_read32le+0x44/0xa0
[...]
x23: ffff00080c080000 x22: ffff000802ac4c00 x21: ffff800087b13c9c
x20: ffff800080a46494 x19: ffff800083da810c x18: 0000000000000004
[...]
x5 : ffff800080a46448 x4 : ffff800083da8000 x3 : ffff800080a46494
x2 : ffff800080a47230 x1 : ffff800083da810c x0 : 0000000000000020
Call trace:
regmap_mmio_read32le+0x44/0xa0 (P)
regmap_mmio_read+0x4c/0x80
[...]
Code: 52800400 8b214093 aa1303e1 97f4caf0 (b9400275)
---[ end trace 0000000000000000 ]---
Kernel panic - not syncing: synchronous external abort: Fatal exception
Running this through decodecode gives:
All code
========
0: 52800400 mov w0, #0x20 // #32
4: 8b214093 add x19, x4, w1, uxtw
8: aa1303e1 mov x1, x19
c: 97f4caf0 bl 0xffffffffffd32bcc
10:* b9400275 ldr w21, [x19] <-- trapping instruction
Code starting with the faulting instruction
===========================================
0: b9400275 ldr w21, [x19]
x19's offset from the base address in /proc/vmallocinfo is 0x10c, which
points to a bad read at physical address 0x4007c10c; I also confirmed
that the preceding memory reads back without issues:
# head -c 990 /sys/kernel/debug/regmap/dummy-syscon@0x000000004007c000/registers | tail -1
0104: 00000000
# head -c 1005 /sys/kernel/debug/regmap/dummy-syscon@0x000000004007c000/registers | tail -1
0108: 00000000
# head -c 1020 /sys/kernel/debug/regmap/dummy-syscon@0x000000004007c000/registers | tail -1
<panic>
Best,
Jared
^ permalink raw reply
* [regression] of: mis-parsing Depthcharge's /firmware
From: Brian Norris @ 2026-04-17 21:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Rob Herring
Cc: Sasha Levin, Krzysztof Kozlowski, AngeloGioacchino Del Regno,
Linus Torvalds, Krzysztof Kozlowski, Conor Dooley, linux-kernel,
devicetree, Matthias Brugger, Doug Anderson, Julius Werner,
chrome-platform
In-Reply-To: <20241209092809.GA3246424@google.com>
Hi all,
(New subject; was "Re: [GIT PULL] Devicetree updates for v6.13")
On Mon, Dec 09, 2024 at 05:28:09PM +0800, Chen-Yu Tsai wrote:
> steelix.dtb is the same, plus the firmware now inserts #address-cells
> and #size-cells under /firmware. This fix has landed for all future
> ChromeOS devices via our main firmware branch [1].
>
> AFAIK they also have a bad FDT END symbol. This was only recently
> discovered and fixed for future devices [2].
>
>
> ChenYu
>
> [1] Gerrit: https://crrev.com/c/6051580
> [2] Gerrit: https://review.coreboot.org/c/coreboot/+/85462
This all comes back to bite us, since nobody went back to patch the
existing Chromebook device trees, and now we've added a true regression
on top:
In commit 6e5773d52f4a ("of/address: Fix WARN when attempting
translating non-translatable addresses") we now reject devices without
'#address-cells', and this breaks the DTs generated by bootloaders
without Chen-Yu's https://crrev.com/c/6051580 fix (this is ... pretty
much all Chromebooks). Specifically, Linux now refuses to add 'reg'
resources to the /firmware/coreboot device, and we fail with:
[ 11.886271] coreboot_table firmware:coreboot: probe with driver coreboot_table failed with error -22
This is almost certainly a DTB ABI regression.
This was noticed here (OpenWrt supports some Chromium-based WiFi routers
that use Depthcharge-based bootloaders from many years ago):
https://github.com/openwrt/openwrt/issues/21243
For now, I just patched up the OpenWrt DTS files like so:
https://github.com/openwrt/openwrt/pull/22951
But what should we do going forward? I note that Rob says "We may
revisit this later and address with a fixup to the DT itself" in commit
8600058ba28a ("of: Add coreboot firmware to excluded default cells
list").
That never happened, and a ton of Chromium devices are still broken.
(They don't have WARNINGs, but /sys/firmware/vpd, etc., is still
missing.)
Can we patch of_bus_default_match() to accept an empty 'ranges' [1]? Or
should I go patch every Chromium-device DTS file I can find? So far, I
think I can get that done in 17 files in the upstream tree...
Brian
[1] From ePAPR:
"If the [ranges] property is defined with an <empty> value, it
specifies that the parent and child address 28 space is identical, and
no address translation is required."
And:
"An ePAPR-compliant boot program shall supply #address-cells and
#size-cells on all nodes 16 that have children.
If missing, a client program should assume a default value of 2 for
#address-cells, and a value of 1 for #size-cells."
So far, this does the trick, but I didn't review all the ramifications
here.
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 4034d798c55a..f86386c407d4 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -328,7 +328,15 @@ static int of_bus_default_flags_match(struct device_node *np)
static int of_bus_default_match(struct device_node *np)
{
- return of_property_present(np, "#address-cells");
+ int len;
+
+ if (of_property_present(np, "#address-cells"))
+ return true;
+
+ if (of_find_property(np, "ranges", &len) && len == 0)
+ return true;
+
+ return false;
}
/*
^ permalink raw reply related
* Re: [PATCH v2 2/2] input: misc: Add PixArt PAJ7620 gesture sensor driver
From: Dmitry Torokhov @ 2026-04-17 21:24 UTC (permalink / raw)
To: Harpreet Saini
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, David Lechner,
devicetree, linux-input, linux-kernel
In-Reply-To: <20260417052527.62535-3-sainiharpreet29@yahoo.com>
Hi Harpreet,
On Fri, Apr 17, 2026 at 01:25:27AM -0400, Harpreet Saini wrote:
> This driver adds support for the PixArt PAJ7620 gesture sensor.
> It implements hand gesture recognition (up, down, left, right,
> etc.) and reports them as standard input key events. The driver
> includes power management support via Runtime PM.
Sashiko has identified a number of valid concerns, please address them.
Also consider:
- moving powering up and down the chip into open()/close() for input
device
- getting keymap from device properties and allowing adjusting it from
userspace vi EVIOCSKEYCODE
- no capitals in type names
- use 'error' instead of 'ret' for variables holding only error code
or 0.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [GIT PULL] Devicetree updates for v7.1
From: pr-tracker-bot @ 2026-04-17 21:23 UTC (permalink / raw)
To: Rob Herring
Cc: Linus Torvalds, Saravana Kannan, Krzysztof Kozlowski,
Conor Dooley, linux-kernel, devicetree
In-Reply-To: <20260417184448.GA1533367-robh@kernel.org>
The pull request you sent on Fri, 17 Apr 2026 13:44:48 -0500:
> ssh://git@gitolite.kernel.org/pub/scm/linux/kernel/git/robh/linux.git tags/devicetree-for-7.1
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/e2d10998e4293a27c0389870b5fdf736a71d61ef
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ permalink raw reply
* Re: [PATCH v4 2/8] dt-bindings: arm: Add zx297520v3 board binding
From: Rob Herring (Arm) @ 2026-04-17 21:08 UTC (permalink / raw)
To: Stefan Dösinger
Cc: linux-kernel, Conor Dooley, Jonathan Corbet, Alexandre Belloni,
Greg Kroah-Hartman, linux-doc, devicetree, Drew Fustini,
Linus Walleij, Jiri Slaby, Russell King, soc, Arnd Bergmann,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-arm-kernel,
linux-serial, Shuah Khan
In-Reply-To: <20260416-send-v4-2-e19d02b944ec@gmail.com>
On Thu, 16 Apr 2026 23:19:10 +0300, Stefan Dösinger wrote:
> Add a compatible for boards based on the ZTE zx297520v3 SoC.
>
> Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>
>
> ---
>
> The list of devices is the devices I have access to for testing. There
> are many more devices based on this board and it is not always easy to
> identify them. Often they are sold without any branding ("4G home
> router") or with mobile carrier branding.
> ---
> Documentation/devicetree/bindings/arm/zte.yaml | 25 +++++++++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 26 insertions(+)
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
./Documentation/devicetree/bindings/arm/zte.yaml:19:13: [warning] wrong indentation: expected 14 but found 12 (indentation)
dtschema/dtc warnings/errors:
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20260416-send-v4-2-e19d02b944ec@gmail.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply
* Re: [PATCH V13 02/12] PCI: host-generic: Add common helpers for parsing Root Port properties
From: Bjorn Helgaas @ 2026-04-17 19:55 UTC (permalink / raw)
To: Sherry Sun
Cc: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
Frank Li, s.hauer@pengutronix.de, kernel@pengutronix.de,
festevam@gmail.com, lpieralisi@kernel.org, kwilczynski@kernel.org,
mani@kernel.org, bhelgaas@google.com, Hongxing Zhu,
l.stach@pengutronix.de, imx@lists.linux.dev,
linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <VI0PR04MB1211449884AC3BC8E3711F1AB92202@VI0PR04MB12114.eurprd04.prod.outlook.com>
On Fri, Apr 17, 2026 at 03:17:16AM +0000, Sherry Sun wrote:
> > On Thu, Apr 16, 2026 at 07:14:12PM +0800, Sherry Sun wrote:
> > > Introduce generic helper functions to parse Root Port device
> > > tree nodes and extract common properties like reset GPIOs. This
> > > allows multiple PCI host controller drivers to share the same
> > > parsing logic.
> > >
> > > Define struct pci_host_port to hold common Root Port properties
> > > (currently only reset GPIO descriptor) and add
> > > pci_host_common_parse_ports() to parse Root Port nodes from
> > > device tree.
> >
> > Are the Root Port and the RC the only possible places for 'reset'
> > GPIO descriptions in DT? I think PERST# routing is outside the
> > PCIe spec, so it seems like a system could provide a PERST# GPIO
> > routed to any Switch Upstream Port or Endpoint (I assume a PERST#
> > connected to a switch would apply to both the upstream port and
> > the downstream ports).
>
> Thanks for the feedback. You're right that PERST# routing could
> theoretically be connected to any device in the hierarchy. However,
> for this patch series, I've focused on the most common use case in
> practice: use Root Port level PERST# instead of the legacy Root
> Complex level PERST#.
>
> Root Port level PERST# - This is the primary target, where each Root
> Port has individual control over devices connected to it. RC level
> PERST# - Legacy binding support, where a single GPIO controls all
> ports.
>
> We can extend this framework later if real hardware emerges that
> needs Switch or EP-level PERST# control. I can add a comment
> documenting this limitation if needed.
>
> BTW, Mani and Rob had some great discussions in dt-schema about
> PERST# and WAKE# sideband signals settings.
> You can check here:
> https://github.com/devicetree-org/dt-schema/issues/168
> https://github.com/devicetree-org/dt-schema/pull/126
> https://github.com/devicetree-org/dt-schema/pull/170
The upshot of all those conversations is that WAKE# and PERST# can be
routed to arbitrary devices independent of the PCI topology.
I think extending host-generic to look for 'reset' in Root Port nodes
is the right thing. My concern is more about where we store it. This
patch saves it in a new "pci_host_port" struct, but someday we'll want
a place to save the PERST# GPIOs for several slots behind a switch.
Then we'll have two different ways to save the same information.
WAKE# signals might be more pertinent -- we definitely need to support
multiple WAKE# signals below a single Root Port, and it seems like
PERST# and WAKE# GPIOs should be saved the same place.
I'm wondering if both should go in the pci_dev itself. I guess the
implication is that a pci_dev->reset GPIO would describe a PERST#
connected to the device *below* the pci_dev, at least for Downstream
Ports.
I don't know about WAKE# signals. When it's in a connector, there's
probably only a single possible WAKE# per Downstream Port. But is it
possible have multiple WAKE# signals from a multi-function device
that's on the motherboard? Saving the WAKE# GPIO in the Downstream
Port wouldn't accommodate that case.
^ permalink raw reply
* Re: [PATCH v2] dt-bindings: iio: gyroscope: add mount-matrix for bmg160
From: Vishwas Rajashekar @ 2026-04-17 19:07 UTC (permalink / raw)
To: Conor Dooley
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
H. Nikolaus Schaller, linux-iio, devicetree, linux-kernel, luca
In-Reply-To: <20260416-level-unbitten-eb3bf8d4a6c7@spud>
On Thursday, April 16th, 2026 at 21:12, Conor Dooley <conor@kernel.org> wrote:
> On Thu, Apr 16, 2026 at 08:33:21PM +0530, Vishwas Rajashekar via B4 Relay wrote:
> > From: Vishwas Rajashekar <vishwas.dev@vrajashkr.com>
> >
> > Adds mount-matrix as an optional property to dt-bindings
> > for the bmg160 gyroscope as the driver reads this optional
> > property during probe.
>
> Ultimately, what the driver does is not relevant here. All that matters
> is that the property is relevant to the hardware. Please come up with a
> commit message that avoids mentioning linux drivers and instead explains
> why it is relevant to the hardware.
>
> pw-bot: changes-requested
>
> Cheers,
> Conor.
>
Thank you for the feedback! I've updated the commit message in v3.
> >
> > Signed-off-by: Vishwas Rajashekar <vishwas.dev@vrajashkr.com>
> > ---
> > The bmg160 driver reads an optional mount-matrix using
> > "iio_read_mount_matrix" in "bmg160_core_probe" and stores
> > this orientation data in "struct bmg160_data". As the "mount-matrix"
> > property is used by the driver, this change proposes to add it to
> > the corresponding dt-bindings.
> > ---
> > Changes in v2:
> > - Addressed review feedback: add mount-matrix example for bmg160
> > - Link to v1: https://patch.msgid.link/20260415-bmg160-mount-matrix-dt-binding-v1-1-0e2c85964ee6@vrajashkr.com
> >
> > To: Jonathan Cameron <jic23@kernel.org>
> > To: David Lechner <dlechner@baylibre.com>
> > To: Nuno Sá <nuno.sa@analog.com>
> > To: Andy Shevchenko <andy@kernel.org>
> > To: Rob Herring <robh@kernel.org>
> > To: Krzysztof Kozlowski <krzk+dt@kernel.org>
> > To: Conor Dooley <conor+dt@kernel.org>
> > To: "H. Nikolaus Schaller" <hns@goldelico.com>
> > Cc: linux-iio@vger.kernel.org
> > Cc: devicetree@vger.kernel.org
> > Cc: linux-kernel@vger.kernel.org
> > ---
> > Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml b/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
> > index 3c6fe74af0b8..ec97778cca78 100644
> > --- a/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
> > +++ b/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
> > @@ -22,6 +22,9 @@ properties:
> > vdd-supply: true
> > vddio-supply: true
> >
> > + mount-matrix:
> > + description: an optional 3x3 mounting rotation matrix.
> > +
> > spi-max-frequency:
> > maximum: 10000000
> >
> > @@ -52,6 +55,9 @@ examples:
> > reg = <0x69>;
> > interrupt-parent = <&gpio6>;
> > interrupts = <18 IRQ_TYPE_EDGE_RISING>;
> > + mount-matrix = "0", "1", "0",
> > + "1", "0", "0",
> > + "0", "0", "1";
> > };
> > };
> > ...
> >
> > ---
> > base-commit: 591cd656a1bf5ea94a222af5ef2ee76df029c1d2
> > change-id: 20260414-bmg160-mount-matrix-dt-binding-e76ddde94866
> >
> > Best regards,
> > --
> > Vishwas Rajashekar <vishwas.dev@vrajashkr.com>
> >
> >
>
Regards,
Vishwas
^ permalink raw reply
* Re: [PATCH] dt-bindings: iio: gyroscope: add mount-matrix for bmg160
From: Vishwas Rajashekar @ 2026-04-17 18:59 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
H. Nikolaus Schaller, linux-iio, devicetree, linux-kernel, luca
In-Reply-To: <20260416-warping-penguin-of-glory-41d59c@quoll>
On Thursday, April 16th, 2026 at 16:19, Krzysztof Kozlowski <krzk@kernel.org> wrote:
> On Wed, Apr 15, 2026 at 09:13:40PM +0530, Vishwas Rajashekar wrote:
> > Adds mount-matrix as an optional property to dt-bindings
> > for the bmg160 gyroscope as the driver reads this optional
> > property during probe.
> >
> > Signed-off-by: Vishwas Rajashekar <vishwas.dev@vrajashkr.com>
> > ---
> > The bmg160 driver reads an optional mount-matrix using
> > "iio_read_mount_matrix" in "bmg160_core_probe" and stores
> > this orientation data in "struct bmg160_data". As the "mount-matrix"
> > property is used by the driver, this change proposes to add it to
> > the corresponding dt-bindings.
> > ---
> > Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml b/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
> > index 3c6fe74af0b8..ea8689660adf 100644
> > --- a/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
> > +++ b/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
> > @@ -22,6 +22,9 @@ properties:
> > vdd-supply: true
> > vddio-supply: true
> >
> > + mount-matrix:
> > + description: an optional 3x3 mounting rotation matrix.
> > +
>
> Extend also example, please.
>
> Best regards,
> Krzysztof
>
>
Thank you for the feedback! I've extended the existing example in v2.
Regards,
Vishwas
^ permalink raw reply
* [GIT PULL] Devicetree updates for v7.1
From: Rob Herring @ 2026-04-17 18:44 UTC (permalink / raw)
To: Linus Torvalds
Cc: Saravana Kannan, Krzysztof Kozlowski, Conor Dooley, linux-kernel,
devicetree
Linus,
Please pull DT updates for 7.1.
There's a couple of conflicts now with your current tree. linux-next has
the correct resolutions.
Rob
The following changes since commit 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f:
Linux 7.0-rc1 (2026-02-22 13:18:59 -0800)
are available in the Git repository at:
ssh://git@gitolite.kernel.org/pub/scm/linux/kernel/git/robh/linux.git tags/devicetree-for-7.1
for you to fetch changes up to a74c2e55ab66519ffa2069ac9ae83cd937bff4c4:
dt-bindings: display: panel: panel-simple: Add lg,sw49410 compatible (2026-04-16 08:57:47 -0500)
----------------------------------------------------------------
Devicetree updates for v7.1:
DT core:
- Cleanup of the reserved memory code to keep CMA specifics in CMA code
- Add and convert several users to new of_machine_get_match() helper
- Validate nul termination in string properties
- Update dtc to upstream v1.7.2-69-g53373d135579
- Limit matching reserved memory devices to /reserved-memory nodes
- Fix some UAF in unittests
- Remove Baikal SoC bus driver
- Fix false DT_SPLIT_BINDING_PATCH checkpatch warning
- Allow fw_devlink device-tree on x86
- Fix kerneldoc return description for of_property_count_elems_of_size()
DT bindings:
- Add fsl,imx25-aips, fsl,imx25-tcq, qcom,eliza-pdc,
qcom,eliza-spmi-pmic-arb, qcom,hawi-imem, qcom,milos-imem,
qcom,hawi-pdc, and lg,sw49410 bindings
- Convert arm,vexpress-scc to DT schema
- Deprecate Qualcomm generic CPU compatibles. Add Apple M3 CPU cores.
- Move some dual-link display panels to the dual-link schema
- Drop mux controller node name constraints
- Remove Baikal SoC bus bindings
- Fix a false warning in the thermal trip node binding
----------------------------------------------------------------
Abel Vesa (2):
dt-bindings: qcom,pdc: document the Eliza Power Domain Controller
dt-bindings: spmi: qcom,x1e80100-spmi-pmic-arb: Document Eliza compatible
Andy Shevchenko (2):
bus: Remove not-going-to-be-supported code for Baikal SoC
dt-bindings: bus: Remove unused bindings
Frank Li (2):
dt-bindings: fsl: add compatible string fsl,imx25-aips
dt-bindings: input: touchscreen: convert fsl-mx25-tcq.txt to yaml
Geert Uytterhoeven (7):
dt-bindings: interrupt-controller: arm,gic-v3: Fix EPPI range
of: Add of_machine_get_match() helper
of: Convert to of_machine_get_match()
cpufreq: airoha: Convert to of_machine_get_match()
cpufreq: qcom-nvmem: Convert to of_machine_get_match()
cpufreq: ti-cpufreq: Convert to of_machine_get_match()
soc: qcom: pd-mapper: Convert to of_machine_get_match()
Herve Codina (1):
of: property: Allow fw_devlink device-tree on x86
Janne Grunau (1):
dt-bindings: arm: cpus: Add Apple M3 CPU core compatibles
Kenny Cheng (1):
of: fix incorrect device creation for reserved memory nodes
Khushal Chitturi (1):
dt-bindings: ARM: arm,vexpress-scc: convert to DT schema
Konrad Dybcio (1):
dt-bindings: sram: Allow multiple-word prefixes to sram subnode
Krzysztof Kozlowski (2):
dt-bindings: arm: cpus: Deprecate Qualcomm generic compatibles
dt-bindings: display: lt8912b: Drop redundant endpoint properties
Luca Weiss (1):
dt-bindings: sram: Document qcom,milos-imem
Marek Szyprowski (7):
of: reserved_mem: remove fdt node from the structure
of: reserved_mem: use -ENODEV instead of -ENOENT
of: reserved_mem: switch to ops based OF_DECLARE()
of: reserved_mem: replace CMA quirks by generic methods
of: reserved_mem: rearrange code a bit
of: reserved_mem: clarify fdt_scan_reserved_mem*() functions
of: reserved_mem: rework fdt_init_reserved_mem_node()
Marek Vasut (2):
dt-bindings: display: simple: Move AUO 21.5" FHD to dual-link
dt-bindings: display: simple: Move Innolux G156HCE-L01 panel to dual-link
Markus Heidelberg (1):
docs: dt: unittest: update to current unittest filenames
Mukesh Ojha (2):
dt-bindings: sram: Document qcom,hawi-imem compatible
dt-bindings: qcom,pdc: document the Hawi Power Domain Controller
Paul Sajna (1):
dt-bindings: display: panel: panel-simple: Add lg,sw49410 compatible
Pengpeng Hou (2):
drivers/of: fdt: validate stdout-path properties before parsing them
drivers/of: fdt: validate flat DT string properties before string use
Rob Herring (Arm) (4):
checkpatch: Fix false DT_SPLIT_BINDING_PATCH warnings
Merge branch 'dt-reserved-mem-cleanups' into dt/next
scripts/dtc: Update to upstream version v1.7.2-69-g53373d135579
dt-bindings: thermal: Fix false warning with 'phandle' in trips nodes
Song Hongyi (1):
of: property: fix typo in kernel-doc return description
Swamil Jain (1):
dt-bindings: display: ti, am65x-dss: Fix AM62L DSS reg and clock constraints
Tommaso Merciai (1):
dt-bindings: mux: Remove nodename pattern constraints
Vivian Wang (1):
dt-bindings: opp-v2: Fix example 3 CPU reg value
Wentao Liang (2):
of: unittest: fix use-after-free in of_unittest_changeset()
of: unittest: fix use-after-free in testdrv_probe()
Xu Yang (1):
dt-bindings: connector: add pd-disable dependency
.../devicetree/bindings/arm/arm,vexpress-scc.yaml | 53 +++
Documentation/devicetree/bindings/arm/cpus.yaml | 292 +++++++--------
.../bindings/arm/freescale/fsl,imx51-m4if.yaml | 1 +
.../devicetree/bindings/arm/vexpress-scc.txt | 33 --
.../devicetree/bindings/bus/baikal,bt1-apb.yaml | 90 -----
.../devicetree/bindings/bus/baikal,bt1-axi.yaml | 107 ------
.../bindings/connector/usb-connector.yaml | 1 +
.../bindings/display/bridge/lontium,lt8912b.yaml | 3 -
.../panel/panel-simple-lvds-dual-ports.yaml | 4 +
.../bindings/display/panel/panel-simple.yaml | 6 +-
.../bindings/display/ti/ti,am65x-dss.yaml | 70 +++-
.../bindings/input/touchscreen/fsl,imx25-tcq.yaml | 69 ++++
.../bindings/input/touchscreen/fsl-mx25-tcq.txt | 34 --
.../bindings/interrupt-controller/arm,gic-v3.yaml | 2 +-
.../bindings/interrupt-controller/qcom,pdc.yaml | 2 +
.../devicetree/bindings/mux/mux-controller.yaml | 6 -
Documentation/devicetree/bindings/opp/opp-v2.yaml | 8 +-
.../bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml | 4 +-
Documentation/devicetree/bindings/sram/sram.yaml | 4 +-
.../devicetree/bindings/thermal/thermal-zones.yaml | 111 +++---
Documentation/devicetree/of_unittest.rst | 20 +-
.../translations/zh_CN/devicetree/of_unittest.rst | 21 +-
drivers/bus/Kconfig | 30 --
drivers/bus/Makefile | 2 -
drivers/bus/bt1-apb.c | 396 ---------------------
drivers/bus/bt1-axi.c | 292 ---------------
drivers/cpufreq/airoha-cpufreq.c | 7 +-
drivers/cpufreq/qcom-cpufreq-nvmem.c | 16 +-
drivers/cpufreq/ti-cpufreq.c | 12 +-
drivers/memory/tegra/tegra210-emc-table.c | 19 +-
drivers/of/base.c | 20 +-
drivers/of/fdt.c | 44 +--
drivers/of/of_private.h | 2 +-
drivers/of/of_reserved_mem.c | 320 ++++++++++-------
drivers/of/platform.c | 12 +-
drivers/of/property.c | 28 +-
drivers/of/unittest.c | 4 +-
drivers/soc/qcom/qcom_pd_mapper.c | 8 +-
include/linux/cma.h | 10 -
include/linux/dma-map-ops.h | 3 -
include/linux/of.h | 11 +-
include/linux/of_reserved_mem.h | 16 +-
kernel/dma/coherent.c | 19 +-
kernel/dma/contiguous.c | 86 +++--
kernel/dma/swiotlb.c | 19 +-
scripts/checkpatch.pl | 2 +-
scripts/dtc/checks.c | 2 +-
scripts/dtc/dtc-lexer.l | 3 -
scripts/dtc/dtc.h | 2 +-
scripts/dtc/libfdt/fdt.c | 8 +
scripts/dtc/libfdt/fdt_rw.c | 9 +-
scripts/dtc/version_gen.h | 2 +-
52 files changed, 795 insertions(+), 1550 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml
delete mode 100644 Documentation/devicetree/bindings/arm/vexpress-scc.txt
delete mode 100644 Documentation/devicetree/bindings/bus/baikal,bt1-apb.yaml
delete mode 100644 Documentation/devicetree/bindings/bus/baikal,bt1-axi.yaml
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/fsl,imx25-tcq.yaml
delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/fsl-mx25-tcq.txt
delete mode 100644 drivers/bus/bt1-apb.c
delete mode 100644 drivers/bus/bt1-axi.c
^ permalink raw reply
* [PATCH v3] dt-bindings: iio: gyroscope: add mount-matrix for bmg160
From: Vishwas Rajashekar via B4 Relay @ 2026-04-17 18:41 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
H. Nikolaus Schaller
Cc: linux-iio, devicetree, linux-kernel, luca, Vishwas Rajashekar
From: Vishwas Rajashekar <vishwas.dev@vrajashkr.com>
The mount-matrix property supplies a 3x3 matrix that is used
to transform the values from the gyroscope to get vector
values that are relative to the way the sensor has been mounted
on the device. When the property is not specified, the identity
matrix is used.
This change adds mount-matrix as an optional property to the
dt-bindings for the bmg160 gyroscope.
Signed-off-by: Vishwas Rajashekar <vishwas.dev@vrajashkr.com>
---
The bmg160 driver reads an optional mount-matrix using
"iio_read_mount_matrix" in "bmg160_core_probe" and stores
this orientation data in "struct bmg160_data". As the "mount-matrix"
property is used by the driver, this change proposes to add it to
the corresponding dt-bindings.
---
Changes in v3:
- Addressed review feedback: updated the commit message to indicate
relevance to hardware and remove references to the Linux driver.
- Link to v2: https://patch.msgid.link/20260416-bmg160-mount-matrix-dt-binding-v2-1-e66cf5cff8e8@vrajashkr.com
Changes in v2:
- Addressed review feedback: add mount-matrix example for bmg160
- Link to v1: https://patch.msgid.link/20260415-bmg160-mount-matrix-dt-binding-v1-1-0e2c85964ee6@vrajashkr.com
To: Jonathan Cameron <jic23@kernel.org>
To: David Lechner <dlechner@baylibre.com>
To: Nuno Sá <nuno.sa@analog.com>
To: Andy Shevchenko <andy@kernel.org>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: "H. Nikolaus Schaller" <hns@goldelico.com>
Cc: linux-iio@vger.kernel.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml b/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
index 3c6fe74af0b8..ec97778cca78 100644
--- a/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
+++ b/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
@@ -22,6 +22,9 @@ properties:
vdd-supply: true
vddio-supply: true
+ mount-matrix:
+ description: an optional 3x3 mounting rotation matrix.
+
spi-max-frequency:
maximum: 10000000
@@ -52,6 +55,9 @@ examples:
reg = <0x69>;
interrupt-parent = <&gpio6>;
interrupts = <18 IRQ_TYPE_EDGE_RISING>;
+ mount-matrix = "0", "1", "0",
+ "1", "0", "0",
+ "0", "0", "1";
};
};
...
---
base-commit: 591cd656a1bf5ea94a222af5ef2ee76df029c1d2
change-id: 20260414-bmg160-mount-matrix-dt-binding-e76ddde94866
Best regards,
--
Vishwas Rajashekar <vishwas.dev@vrajashkr.com>
^ permalink raw reply related
* Re: [PATCH 04/11] media: iris: Add helper to create a context bank device on iris vpu bus
From: Dmitry Baryshkov @ 2026-04-17 18:23 UTC (permalink / raw)
To: Vishnu Reddy
Cc: Bryan O'Donoghue, Vikash Garodia, Dikshita Agarwal,
Abhinav Kumar, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joerg Roedel, Will Deacon,
Robin Murphy, Bjorn Andersson, Konrad Dybcio, Stefan Schmidt,
Hans Verkuil, linux-media, linux-arm-msm, devicetree,
linux-kernel, iommu
In-Reply-To: <b0ba2172-3f66-c912-29e9-0a48b4480987@oss.qualcomm.com>
On Fri, Apr 17, 2026 at 08:49:44PM +0530, Vishnu Reddy wrote:
>
> On 4/14/2026 8:48 PM, Dmitry Baryshkov wrote:
> > On Tue, Apr 14, 2026 at 10:30:00AM +0530, Vishnu Reddy wrote:
> > > From: Vikash Garodia<vikash.garodia@oss.qualcomm.com>
> > >
> > > Add a helper function to allocate and register context bank (CB) device
> > > on the iris vpu bus. The function ID associated with the CB is specified
> > > from the platform data, allowing the bus dma_configure callback to apply
> > > correct stream ID mapping when device is registered.
> > >
> > > Signed-off-by: Vikash Garodia<vikash.garodia@oss.qualcomm.com>
> > > Signed-off-by: Vishnu Reddy<busanna.reddy@oss.qualcomm.com>
> > > ---
> > > drivers/media/platform/qcom/iris/iris_resources.c | 33 +++++++++++++++++++++++
> > > drivers/media/platform/qcom/iris/iris_resources.h | 1 +
> > > 2 files changed, 34 insertions(+)
> > >
> > > diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c
> > > index 773f6548370a..a25e0f2e9d26 100644
> > > --- a/drivers/media/platform/qcom/iris/iris_resources.c
> > > +++ b/drivers/media/platform/qcom/iris/iris_resources.c
> > > @@ -6,6 +6,7 @@
> > > #include <linux/clk.h>
> > > #include <linux/devfreq.h>
> > > #include <linux/interconnect.h>
> > > +#include <linux/iris_vpu_bus.h>
> > > #include <linux/pm_domain.h>
> > > #include <linux/pm_opp.h>
> > > #include <linux/pm_runtime.h>
> > > @@ -141,3 +142,35 @@ int iris_disable_unprepare_clock(struct iris_core *core, enum platform_clk_type
> > > return 0;
> > > }
> > > +
> > > +static void iris_release_cb_dev(struct device *dev)
> > > +{
> > > + kfree(dev);
> > > +}
> > > +
> > > +struct device *iris_create_cb_dev(struct iris_core *core, const char *name, const u32 *f_id)
> > Please move into the bus code and make it generic enough.
> Do you suggest to add a wrapper to pass the varying inputs to the generic
> bus, something like this
> struct device* create_and_register_device(dma_mask, parent_dev, *release,
> dev_name,...)
Definitely not the release function. The devname is also not that
important. The rest, yes, you are correct.
> > > +{
> > > + struct device *dev;
> > > + int ret;
> > > +
> > > + dev = kzalloc_obj(*dev);
> > > + if (!dev)
> > > + return ERR_PTR(-ENOMEM);
> > > +
> > > + dev->release = iris_release_cb_dev;
> > > + dev->bus = &iris_vpu_bus_type;
> > > + dev->parent = core->dev;
> > > + dev->coherent_dma_mask = core->iris_platform_data->dma_mask;
> > > + dev->dma_mask = &dev->coherent_dma_mask;
> > Would you also need to set the of_node? See
> > device_set_of_node_from_dev()
>
> It might be needed for FastRPC as they are following sub node approach, Iris
> does not need.
Wouldn't it save you from passing it to of_dma_configure_id()?
> > > +
> > > + dev_set_name(dev, "%s", name);
> > > + dev_set_drvdata(dev, (void *)f_id);
> > > +
> > > + ret = device_register(dev);
> > > + if (ret) {
> > > + put_device(dev);
> > > + return ERR_PTR(ret);
> > > + }
> > > +
> > > + return dev;
> > > +}
> > > diff --git a/drivers/media/platform/qcom/iris/iris_resources.h b/drivers/media/platform/qcom/iris/iris_resources.h
> > > index 6bfbd2dc6db0..4a494627ff23 100644
> > > --- a/drivers/media/platform/qcom/iris/iris_resources.h
> > > +++ b/drivers/media/platform/qcom/iris/iris_resources.h
> > > @@ -15,5 +15,6 @@ int iris_unset_icc_bw(struct iris_core *core);
> > > int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw);
> > > int iris_disable_unprepare_clock(struct iris_core *core, enum platform_clk_type clk_type);
> > > int iris_prepare_enable_clock(struct iris_core *core, enum platform_clk_type clk_type);
> > > +struct device *iris_create_cb_dev(struct iris_core *core, const char *name, const u32 *f_id);
> > > #endif
> > >
> > > --
> > > 2.34.1
> > >
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 02/11] media: iris: Add iris vpu bus support and register it with iommu_buses
From: Dmitry Baryshkov @ 2026-04-17 18:19 UTC (permalink / raw)
To: Vishnu Reddy
Cc: Bryan O'Donoghue, Vikash Garodia, Dikshita Agarwal,
Abhinav Kumar, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joerg Roedel, Will Deacon,
Robin Murphy, Bjorn Andersson, Konrad Dybcio, Stefan Schmidt,
Hans Verkuil, linux-media, linux-arm-msm, devicetree,
linux-kernel, iommu
In-Reply-To: <26b71f52-3355-d4e9-f640-007123e3aba2@oss.qualcomm.com>
On Fri, Apr 17, 2026 at 08:29:21PM +0530, Vishnu Reddy wrote:
> apologies for re-sending (earlier responses was rejected due to HTML format)
Ugh.
>
> On 4/17/2026 8:22 PM, Vishnu Reddy wrote:
> > On 4/14/2026 8:44 PM, Dmitry Baryshkov wrote:
> > > On Tue, Apr 14, 2026 at 10:29:58AM +0530, Vishnu Reddy wrote:
> > > > From: Vikash Garodia<vikash.garodia@oss.qualcomm.com>
> > > >
> > > > Add a dedicated iris VPU bus type and register it into the iommu_buses
> > > > list. Iris devices require their own bus so that each device can run its
> > > > own dma_configure() logic.
> > > This really tells nothing, unless one has full context about the Iris
> > > needs. Start by describing the issue (that the device needs to have
> > > multiple devices talking to describe IOMMUs / VAs for several hardware
> > > functions), then continue by describing what is needed from the IOMMU
> > > subsys.
> >
> > This series handles firmware device which do not require multiple
> > devices part.
> > given this device need for specific IOMMU configuration, I'll update the
> > description
> > accordingly.
> >
> > > > Signed-off-by: Vikash Garodia<vikash.garodia@oss.qualcomm.com>
> > > > Signed-off-by: Vishnu Reddy<busanna.reddy@oss.qualcomm.com>
> > > > ---
> > > > drivers/iommu/iommu.c | 4 ++++
> > > > drivers/media/platform/qcom/iris/Makefile | 4 ++++
> > > > drivers/media/platform/qcom/iris/iris_vpu_bus.c | 32 +++++++++++++++++++++++++
> > > > include/linux/iris_vpu_bus.h | 13 ++++++++++
> > > How are you supposed to merge this? Through IOMMU tree? Through venus
> > > tree? Can we add one single bus to the IOMMU code and use it for Iris,
> > > Venus, FastRPC, host1x and all other device drivers which require
> > > per-device DMA configuration?
> >
> > Separating out the bus definition and the Iris driver handling would
> > provide a
> > cleaner merge path.
Then why wasn't it done from the ground up?
> >
> > > Your colleagues from the FastRPC team posted a very similar code few
> > > weeks ago and got exactly the same feedback. Is there a reason why your
> > > teams don't sync on the IOMMU parts at all?
> >
> > I would admit that I missed to review that, thank you for bringing that
> > discussion.
> > FastRPC patches generalizes the handling for host1x, FastRPC and the
> > same can be
> > extended for Iris. I have left few comments there.
> >
> > > > 4 files changed, 53 insertions(+)
> > > >
> > > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> > > > index 61c12ba78206..d8ed6ef70ecd 100644
> > > > --- a/drivers/iommu/iommu.c
> > > > +++ b/drivers/iommu/iommu.c
> > > > @@ -13,6 +13,7 @@
> > > > #include <linux/bug.h>
> > > > #include <linux/types.h>
> > > > #include <linux/init.h>
> > > > +#include <linux/iris_vpu_bus.h>
> > > > #include <linux/export.h>
> > > > #include <linux/slab.h>
> > > > #include <linux/errno.h>
> > > > @@ -179,6 +180,9 @@ static const struct bus_type * const iommu_buses[] = {
> > > > #ifdef CONFIG_CDX_BUS
> > > > &cdx_bus_type,
> > > > #endif
> > > > +#if IS_ENABLED(CONFIG_VIDEO_QCOM_IRIS)
> > > > + &iris_vpu_bus_type,
> > > > +#endif
> > > > };
> > > > /*
> > > > diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile
> > > > index 2abbd3aeb4af..6f4052b98491 100644
> > > > --- a/drivers/media/platform/qcom/iris/Makefile
> > > > +++ b/drivers/media/platform/qcom/iris/Makefile
> > > > @@ -31,3 +31,7 @@ qcom-iris-objs += iris_platform_gen1.o
> > > > endif
> > > > obj-$(CONFIG_VIDEO_QCOM_IRIS) += qcom-iris.o
> > > > +
> > > > +ifdef CONFIG_VIDEO_QCOM_IRIS
> > > > +obj-y += iris_vpu_bus.o
> > > > +endif
> > > > diff --git a/drivers/media/platform/qcom/iris/iris_vpu_bus.c b/drivers/media/platform/qcom/iris/iris_vpu_bus.c
> > > > new file mode 100644
> > > > index 000000000000..b51bb4b82b0e
> > > > --- /dev/null
> > > > +++ b/drivers/media/platform/qcom/iris/iris_vpu_bus.c
> > > > @@ -0,0 +1,32 @@
> > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > +/*
> > > > + * Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved.
> > > > + */
> > > > +
> > > > +#include <linux/device.h>
> > > > +#include <linux/of_device.h>
> > > > +
> > > > +#include "iris_platform_common.h"
> > > > +
> > > > +static int iris_vpu_bus_dma_configure(struct device *dev)
> > > > +{
> > > > + const u32 *f_id = dev_get_drvdata(dev);
> > > > +
> > > > + if (!f_id)
> > > > + return -ENODEV;
> > > > +
> > > > + return of_dma_configure_id(dev, dev->parent->of_node, true, f_id);
> > > I think it was discussed that this is not enough. Some of devices need
> > > multiple function IDs.
> >
> > In this glymur series we are following the legacy way of handling IOMMUs
> > and does not
> > require multi map.
Why can't we land the version that has multiple entries? It's as if the
teams are totally not in sync. The corresponding version is in works, it
has been implemented, etc.
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 4/4] arm64: dts: qcom: sdm630: assign adsp_mem region to ADSP FastRPC node
From: Dmitry Baryshkov @ 2026-04-17 18:12 UTC (permalink / raw)
To: Nickolay Goppen
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-arm-msm, devicetree, linux-kernel,
~postmarketos/upstreaming
In-Reply-To: <20260415-qcom-sdm660-cdsp-adsp-fastrpc-dts-fix-v1-4-03b475b29554@mainlining.org>
On Wed, Apr 15, 2026 at 12:40:26PM +0300, Nickolay Goppen wrote:
> Downstream [1] ADSP FastRPC node has the adsp_mem region assigned, so
> assign it to the ADSP FastRPC node.
>
> [1]: https://github.com/xiaomi-sdm660/android_kernel_xiaomi_sdm660/blob/11-EAS/arch/arm/boot/dts/qcom/sdm660.dtsi#L1693
>
> Signed-off-by: Nickolay Goppen <setotau@mainlining.org>
> ---
> arch/arm64/boot/dts/qcom/sdm630.dtsi | 1 +
> 1 file changed, 1 insertion(+)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 2/4] arm64: dts: qcom: sdm630: set adsp compute-cbs' regs properly
From: Dmitry Baryshkov @ 2026-04-17 18:08 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Nickolay Goppen, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, devicetree,
linux-kernel, ~postmarketos/upstreaming
In-Reply-To: <455942ab-a55e-48cd-a37b-6ab9efde84f4@oss.qualcomm.com>
On Wed, Apr 15, 2026 at 11:50:09AM +0200, Konrad Dybcio wrote:
> On 4/15/26 11:40 AM, Nickolay Goppen wrote:
> > Changing FastRPC compute-cbs' reg values to matching iommu streams
> > solves SMMU translation errors when trying to use FastRPC on ADSP
> > so change FastRPC compute-cbs' reg values that way
> >
> > Signed-off-by: Nickolay Goppen <setotau@mainlining.org>
> > ---
>
> Fixes: af2ce7296643 ("arm64: dts: qcom: sdm630: Add FastRPC nodes to ADSP")
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>
> Konrad
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 1/4] arm64: dts: qcom: sdm660: set cdsp compute-cbs' regs properly
From: Dmitry Baryshkov @ 2026-04-17 18:08 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Nickolay Goppen, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, devicetree,
linux-kernel, ~postmarketos/upstreaming
In-Reply-To: <42649c1c-3868-44ea-8186-49e34abf10b9@oss.qualcomm.com>
On Wed, Apr 15, 2026 at 11:43:29AM +0200, Konrad Dybcio wrote:
> On 4/15/26 11:40 AM, Nickolay Goppen wrote:
> > Changing FastRPC compute-cbs' reg values to matching iommu streams
> > solves SMMU translation errors when trying to use FastRPC on CDSP
> > so change FastRPC compute-cbs' reg values that way
> >
> > Signed-off-by: Nickolay Goppen <setotau@mainlining.org>
> > ---
>
> Fixes: c0c32a9e3493 ("arm64: dts: qcom: sdm630/660: Add CDSP-related nodes")
With Fixes in place:
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
>
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>
> Konrad
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 2/4] hwmon: Add Qualcomm PMIC BCL hardware monitor driver
From: Manaf Meethalavalappu Pallikunhi @ 2026-04-17 18:08 UTC (permalink / raw)
To: Daniel Lezcano, Guenter Roeck
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, amit.kucheria, Daniel Lezcano, Gaurav Kohli,
linux-hwmon, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <6f4b27c5-074e-403a-90b8-fe7ef3a993b5@oss.qualcomm.com>
Hi Daniel/Guenter,
On 3/20/2026 9:38 PM, Daniel Lezcano wrote:
>
> Hi Guenter,
>
> On 3/20/26 16:22, Guenter Roeck wrote:
>> On 3/20/26 07:52, Daniel Lezcano wrote:
>
> [ ... ]
>
>>>> +
>>>> +ADD_BCL_HWMON_ALARM_MAPS(in, min, lcrit);
>>>> +ADD_BCL_HWMON_ALARM_MAPS(curr, max, crit);
>>>> +
>>>> +/* Interrupt names for each alarm level */
>>>> +static const char * const bcl_int_names[ALARM_MAX] = {
>>>> + [LVL0] = "bcl-max-min",
>>>> + [LVL1] = "bcl-critical",
>>>> +};
>>>
>>> IIUC there are three levels of alarms but the hwmon only has max/min
>>> and critical. Would it make sense to do adaptative min / max ? So when
>>
>> hwmon has lcrit, min, max, and crit alarms for all sensor types, plus
>> an additional _cap_alarm for power attributes and _emergency_alarm
>> for temperature attributes. There is also a generic _alarm attribute
>> for each sensor, which is supposed to be used if the specific alarm
>> type is not known.
>>
>> What exactly are the three levels of alarms ?
>
> Manaf can give more clarifications, but it is like we have yellow,
> orange and red alarms. So there is an additional alarm comparing to what
> is available in hwmon. The proposed driver maps orange and red alarms,
> respectively to bcl-max and bcl-critical.
Yes, it is different limit level alarms (3 low voltage and 3 over
current) like yellow, orange and Red.
Currently I mapped, yellow and orange. Red is not enabled.
Thanks,
Manaf
>
> I'm just asking if it is important to have this 'yellow' alarm ? And as
> there is a missing alarm to describe it in hwmon, how can we use it ?
^ permalink raw reply
* Re: [PATCH v8 2/2] iio: dac: ad5706r: Add support for AD5706R DAC
From: Andy Shevchenko @ 2026-04-17 18:05 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Alexis Czezar Torreno, Lars-Peter Clausen, Michael Hennerich,
Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-iio,
devicetree, linux-kernel
In-Reply-To: <20260417135624.000030e5@huawei.com>
On Fri, Apr 17, 2026 at 01:56:24PM +0100, Jonathan Cameron wrote:
> On Fri, 17 Apr 2026 11:35:12 +0300
> Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> > On Fri, Apr 17, 2026 at 04:27:16PM +0800, Alexis Czezar Torreno wrote:
...
> > > +#define AD5706R_DAC_RESOLUTION 16
> > > +#define AD5706R_DAC_MAX_CODE GENMASK(15, 0)
> >
> > I know Jonathan asked for this, hence it's comment for him.
> > I think that BIT() notation in a form of (BIT(16) - 1) is
> > also appropriate here as it gives the relationship to the
> > resolution of the given register / bitfield in HW.
> >
> > GENMASK() works for me, but it might require an additional
> > operation to deduce the above.
> >
> > (Note, there is no request to change or resend for you, Alexis. It's just
> > a remark to make Jonathan to think about which one suits better. He might
> > change that whilst applying.)
> >
> I'm not against that form. It was more being against bare BIT(16) as that was
> 1 greater than the maximum value it can take.
> However making the relationship explicit would be even better.
>
> #define AD5705_DAC_MAX_CODE (BIT(AD5706R_DAC_RESOLUTION) - 1)
While that's technically correct, I would still prefer an explicit number
#define AD5705_DAC_MAX_CODE (BIT(16) - 1)
Note, GENMASK() is also fine with me, this is really a minor difference.
> I might tweak it when picking this up.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH 2/4] hwmon: Add Qualcomm PMIC BCL hardware monitor driver
From: Manaf Meethalavalappu Pallikunhi @ 2026-04-17 18:01 UTC (permalink / raw)
To: Daniel Lezcano
Cc: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, amit.kucheria, Daniel Lezcano,
Gaurav Kohli, linux-hwmon, linux-arm-msm, devicetree,
linux-kernel
In-Reply-To: <ab1fSWx7pqlSANph@mai.linaro.org>
Hi Daniel,
On 3/20/2026 8:22 PM, Daniel Lezcano wrote:
> Hi Manaf,
>
> On Fri, Feb 06, 2026 at 02:44:06AM +0530, Manaf Meethalavalappu Pallikunhi wrote:
>> Add support for Qualcomm PMIC Battery Current Limiting (BCL) hardware
>> monitor driver. The BCL peripheral is present in Qualcomm PMICs and
>> provides real-time monitoring and protection against battery
>> overcurrent and under voltage conditions.
>>
>> The driver monitors:
>> - Battery voltage with configurable low voltage thresholds
>> - Battery current with configurable high current thresholds
>> - Two limit alarm interrupts (max/min, critical)
>
> Can you describe the behavior of the alarm ?
>
> I assume the alarm is raised when a threshold is crossed from normal
> to anormal condition leading to a hwmon event.
>
> * Does the BCL trigger an interrupt when going back to the normal condition ?
NO, there is no any clear interrupt to software, It can trigger only
from normal to abnormal condition.
>
> * When is the alarm flag reset ?
The hardware implements predefined deglitch set and clear timers for
each alarm level, configured by early‑boot firmware. Alarm state
transitions occur only if the input current or voltage persists beyond
or within the specified threshold for the defined deglitch duration.
>
> * Can we have a flood of events if the current / voltage is wavering
> around the thresholds ?
Yes, it is possible. Short deglitch timings on higher-level alarms can
cause spurious interrupts. Also, corrective actions in IPs in hardware
path may cause current or voltage to vary around the threshold.
The Purpose of different BCL alarms is to provide quick entry and slow
exit for BCL. This avoids oscillation, and allows SW time to observe the
system reaction during the hardware mitigation. SW should not need to
react to each interrupt. SW takes additional steps if the system is
stressed.
When an alarm is triggered, clients are notified via a hwmon_event,
corrective actions are initiated, interrupt for that level will be
disabled, and polling is enabled (50–100 ms) until the alarm condition
clears. Upon alarm reset, clients are notified again, interrupts are
re‑enabled, and polling is stopped.
>
> Overall, the driver is too big, so hard to review. It is better to
> provide a simplified version with one version supported.
>
>> The driver integrates with the Linux hwmon subsystem and provides
>> standard hwmon attributes for monitoring battery conditions.
>>
>> Signed-off-by: Manaf Meethalavalappu Pallikunhi <manaf.pallikunhi@oss.qualcomm.com>
>> ---
>> MAINTAINERS | 9 +
>> drivers/hwmon/Kconfig | 9 +
>> drivers/hwmon/Makefile | 1 +
>> drivers/hwmon/qcom-bcl-hwmon.c | 982 +++++++++++++++++++++++++++++++++++++++++
>> drivers/hwmon/qcom-bcl-hwmon.h | 311 +++++++++++++
>> 5 files changed, 1312 insertions(+)
>
> [ ... ]
>
>> diff --git a/drivers/hwmon/qcom-bcl-hwmon.c b/drivers/hwmon/qcom-bcl-hwmon.c
>> new file mode 100644
>> index 000000000000..a7e3b865de5c
>> --- /dev/null
>> +++ b/drivers/hwmon/qcom-bcl-hwmon.c
>> @@ -0,0 +1,982 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Qualcomm pmic BCL hardware driver for battery overcurrent and
>> + * battery or system under voltage monitor
>> + *
>> + * Copyright (c) 2026, Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>
> Old copyright format
Ack
>
>> +#include <linux/devm-helpers.h>
>> +#include <linux/err.h>
>> +#include <linux/hwmon.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/mod_devicetable.h>
>> +#include <linux/mutex.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/property.h>
>> +#include <linux/regmap.h>
>> +#include <linux/workqueue.h>
>> +
>> +#include "qcom-bcl-hwmon.h"
>> +
>> +ADD_BCL_HWMON_ALARM_MAPS(in, min, lcrit);
>> +ADD_BCL_HWMON_ALARM_MAPS(curr, max, crit);
>> +
>> +/* Interrupt names for each alarm level */
>> +static const char * const bcl_int_names[ALARM_MAX] = {
>> + [LVL0] = "bcl-max-min",
>> + [LVL1] = "bcl-critical",
>> +};
>
> IIUC there are three levels of alarms but the hwmon only has max/min
> and critical. Would it make sense to do adaptative min / max ? So when
> LVL0 is reached, update min / max with LVL1 value, LVL2 is critical
> and does not change ?
>
>> +static const char * const bcl_channel_label[CHANNEL_MAX] = {
>> + "BCL Voltage",
>> + "BCL Current",
>> +};
>
> s/[CHANNEL_MAX]/[]/
Ack
>
>> +/* Common Reg Fields */
>> +static const struct reg_field common_reg_fields[COMMON_FIELD_MAX] = {
>> + [F_V_MAJOR] = REG_FIELD(REVISION2, 0, 7),
>> + [F_V_MINOR] = REG_FIELD(REVISION1, 0, 7),
>> + [F_CTL_EN] = REG_FIELD(EN_CTL1, 7, 7),
>> + [F_LVL0_ALARM] = REG_FIELD(STATUS, 0, 0),
>> + [F_LVL1_ALARM] = REG_FIELD(STATUS, 1, 1),
>> +};
>> +
>> +/* BCL Version/Modes specific fields */
>> +static const struct reg_field bcl_v1_reg_fields[] = {
>> + [F_IN_MON_EN] = REG_FIELD(MODE_CTL1, 0, 2),
>> + [F_IN_L0_THR] = REG_FIELD(VADC_L0_THR, 0, 7),
>> + [F_IN_L1_THR] = REG_FIELD(VCMP_L1_THR, 0, 5),
>> + [F_IN_INPUT_EN] = REG_FIELD(VADC_CONV_REQ, 0, 0),
>> + [F_IN_INPUT] = REG_FIELD(VADC_DATA1, 0, 7),
>> + [F_CURR_MON_EN] = REG_FIELD(IADC_CONV_REQ, 0, 0),
>> + [F_CURR_H0_THR] = REG_FIELD(IADC_H0_THR, 0, 7),
>> + [F_CURR_H1_THR] = REG_FIELD(IADC_H1_THR, 0, 7),
>> + [F_CURR_INPUT] = REG_FIELD(IADC_DATA1, 0, 7),
>> +};
>> +
>> +static const struct reg_field bcl_v2_reg_fields[] = {
>> + [F_IN_MON_EN] = REG_FIELD(VCMP_CTL, 0, 1),
>> + [F_IN_L0_THR] = REG_FIELD(VADC_L0_THR, 0, 7),
>> + [F_IN_L1_THR] = REG_FIELD(VCMP_L1_THR, 0, 5),
>> + [F_IN_INPUT_EN] = REG_FIELD(VADC_CONV_REQ, 0, 0),
>> + [F_IN_INPUT] = REG_FIELD(VADC_DATA1, 0, 7),
>> + [F_CURR_MON_EN] = REG_FIELD(IADC_CONV_REQ, 0, 0),
>> + [F_CURR_H0_THR] = REG_FIELD(IADC_H0_THR, 0, 7),
>> + [F_CURR_H1_THR] = REG_FIELD(IADC_H1_THR, 0, 7),
>> + [F_CURR_INPUT] = REG_FIELD(IADC_DATA1, 0, 7),
>> +};
>
> Please begin with a simplified driver supporting one version and then
> add more versions. That will help for the review process.
Basic functionality of all versions are the same, mainly the register
offsets and scaling factors are different. Hence added all of them.
Will check and update with single target BCL hardware in V2.
>
> [ ... ]
>
>> +/* V1 BMX and core */
>> +static const struct bcl_desc pm7250b_data = {
>> + .reg_fields = bcl_v1_reg_fields,
>> + .num_reg_fields = F_MAX_FIELDS,
>> + .data_field_bits_size = 8,
>> + .thresh_field_bits_size = 7,
>> + .channel[IN] = {
>> + .base = 2250,
>> + .max = 3600,
>> + .step = 25,
>> + .default_scale_nu = 194637,
>> + .thresh_type = {ADC, INDEX},
>> + },
>> + .channel[CURR] = {
>> + .max = 10000,
>> + .default_scale_nu = 305180,
>> + .thresh_type = {ADC, ADC},
>> + },
>> +};
>>
>> +/* V2 BMX and core */
>
> Ditto
Ack
>
> [ ... ]
>
>> +/**
>> + * bcl_convert_raw_to_milliunit - Convert raw value to milli unit
>> + * @desc: BCL device descriptor
>> + * @raw_val: Raw ADC value from hardware
>> + * @type: type of the channel, in or curr
>> + * @field_width: bits size for data or threshold field
>> + *
>> + * Return: value in milli unit
>> + */
>> +static unsigned int bcl_convert_raw_to_milliunit(const struct bcl_desc *desc, int raw_val,
>> + enum bcl_channel_type type, u8 field_width)
>> +{
>> + u32 def_scale = desc->channel[type].default_scale_nu;
>> + u32 lsb_weight = field_width > 8 ? 1 : 1 << field_width;
>> + u32 scaling_factor = def_scale * lsb_weight;
>
> This is confusing, can you explain ?
>
> if 'field_width' == 7, then we do def_scale * 1^7 ?
>
> Why ?
This behavior exists to support multiple BCL hardware generations with
different register layouts.
In older implementations, only a single byte is provided for ADC data,
which maps to the MSB byte of a 16‑bit ADC value. The LSB byte is not
available, meaning values are effectively reported in MSB‑byte
granularity. As a result, the value must be scaled by 256 to account for
the missing LSB bits.
Newer generations provide full 16‑bit ADC support, where both MSB and
LSB bytes are available and no additional scaling is required.
For threshold registers in the v1 hardware, only the upper 7 bits of the
ADC value are mapped (field_width = 7), while the remaining 9 LSB bits
are implicitly zero. This requires adjusting the scale factor
accordingly to align software values with the actual ADC resolution.
>
>> + return div_s64((s64)raw_val * scaling_factor, 1000000);
>
> If it is milliunit why dividing by 10^6 ?
>
>> +/**
>> + * bcl_convert_milliunit_to_index - Convert milliunit to in or curr index
>> + * @desc: BCL device descriptor
>> + * @val: in or curr value in milli unit
>> + * @type: type of the channel, in or curr
>> + *
>> + * Converts a value in milli unit to an index for BCL that use indexed thresholds.
>> + *
>> + * Return: Voltage index value
>> + */
>> +static unsigned int bcl_convert_milliunit_to_index(const struct bcl_desc *desc, int val,
>> + enum bcl_channel_type type)
>> +{
>> + return div_s64((s64)val - desc->channel[type].base, desc->channel[type].step);
>> +}
>> +
>> +/**
>> + * bcl_convert_index_to_milliunit - Convert in or curr index to milli unit
>> + * @desc: BCL device descriptor
>> + * @val: index value
>> + * @type: type of the channel, in or curr
>> + *
>> + * Converts an index value to milli unit for BCL that use indexed thresholds.
>> + *
>> + * Return: Voltage value in millivolts
>> + */
>> +static unsigned int bcl_convert_index_to_milliunit(const struct bcl_desc *desc, int val,
>> + enum bcl_channel_type type)
>> +{
>> + return desc->channel[type].base + val * desc->channel[type].step;
>
> To be sure, is it (A + val) * B, or, A + (val * B) ?
Ack, it is A + (val * B)
>
>> +}
>> +
>> +static int bcl_in_thresh_write(struct bcl_device *bcl, long value, enum bcl_limit_alarm lvl)
>> +{
>> + const struct bcl_desc *desc = bcl->desc;
>> + u32 raw_val;
>> +
>> + int thresh = clamp_val(value, desc->channel[IN].base, desc->channel[IN].max);
>> +
>> + if (desc->channel[IN].thresh_type[lvl] == ADC)
>> + raw_val = bcl_convert_milliunit_to_raw(desc, thresh, IN,
>> + desc->thresh_field_bits_size);
>> + else
>> + raw_val = bcl_convert_milliunit_to_index(desc, thresh, IN);
>> +
>> + return regmap_field_write(bcl->fields[F_IN_L0_THR + lvl], raw_val);
>> +}
>> +
>> +static int bcl_curr_thresh_write(struct bcl_device *bcl, long value, enum bcl_limit_alarm lvl)
>> +{
>> + const struct bcl_desc *desc = bcl->desc;
>> + u32 raw_val;
>> +
>> + /* Clamp only to curr max */
>> + int thresh = clamp_val(value, value, desc->channel[CURR].max);
>> +
>> + if (desc->channel[CURR].thresh_type[lvl] == ADC)
>> + raw_val = bcl_convert_milliunit_to_raw(desc, thresh, CURR,
>> + desc->thresh_field_bits_size);
>> + else
>> + raw_val = bcl_convert_milliunit_to_index(desc, thresh, CURR);
>> +
>> + return regmap_field_write(bcl->fields[F_CURR_H0_THR + lvl], raw_val);
>> +}
>> +
>> +static int bcl_in_thresh_read(struct bcl_device *bcl, enum bcl_limit_alarm lvl, long *out)
>> +{
>> + int ret, thresh;
>> + u32 raw_val = 0;
>> + const struct bcl_desc *desc = bcl->desc;
>> +
>> + ret = bcl_read_field_value(bcl, F_IN_L0_THR + lvl, &raw_val);
>> + if (ret)
>> + return ret;
>> +
>> + if (desc->channel[IN].thresh_type[lvl] == ADC)
>> + thresh = bcl_convert_raw_to_milliunit(desc, raw_val, IN,
>> + desc->thresh_field_bits_size);
>> + else
>> + thresh = bcl_convert_index_to_milliunit(desc, raw_val, IN);
>> +
>> + *out = thresh;
>> +
>> + return 0;
>> +}
>> +
>> +static int bcl_curr_thresh_read(struct bcl_device *bcl, enum bcl_limit_alarm lvl, long *out)
>> +{
>> + int ret, thresh;
>> + u32 raw_val = 0;
>> + const struct bcl_desc *desc = bcl->desc;
>> +
>> + ret = bcl_read_field_value(bcl, F_CURR_H0_THR + lvl, &raw_val);
>> + if (ret)
>> + return ret;
>> +
>> + if (desc->channel[CURR].thresh_type[lvl] == ADC)
>> + thresh = bcl_convert_raw_to_milliunit(desc, raw_val, CURR,
>> + desc->thresh_field_bits_size);
>> + else
>> + thresh = bcl_convert_index_to_milliunit(desc, raw_val, CURR);
>> +
>> + *out = thresh;
>> +
>> + return 0;
>> +}
>> +
>> +static int bcl_curr_input_read(struct bcl_device *bcl, long *out)
>> +{
>> + int ret;
>> + u32 raw_val = 0;
>> + const struct bcl_desc *desc = bcl->desc;
>> +
>> + ret = bcl_read_field_value(bcl, F_CURR_INPUT, &raw_val);
>> + if (ret)
>> + return ret;
>> +
>> + /*
>> + * The sensor sometime can read a value 0 if there are
>> + * consecutive reads
>> + */
>
> In order to prevent the userspace to read in a too high rate the
> values of a hwmon, where I guess it is the reason why the value can be
> 0, the cached value is returned if two reads are under a minimal
> jiffies based interval.
>
> Something like:
>
> if (time_before(jiffies, last_updated + HZ))
> return bcl->last_curr_input;
>
> If it is correct, then that could be put at the beginning of the
> function instead of checking the zero value.
ACK, Will check and update in V2
>
>> + if (raw_val != 0)
>> + bcl->last_curr_input =
>> + bcl_convert_raw_to_milliunit(desc, raw_val, CURR,
>> + desc->data_field_bits_size);
>> +
>> + *out = bcl->last_curr_input;
>> +
>> + return 0;
>> +}
>> +
>> +static int bcl_in_input_read(struct bcl_device *bcl, long *out)
>> +{
>> + int ret;
>> + u32 raw_val = 0;
>> + const struct bcl_desc *desc = bcl->desc;
>> +
>> + ret = bcl_read_field_value(bcl, F_IN_INPUT, &raw_val);
>> + if (ret)
>> + return ret;
>> +
>> + if (raw_val < GENMASK(desc->data_field_bits_size - 1, 0))
>> + bcl->last_in_input =
>> + bcl_convert_raw_to_milliunit(desc, raw_val, IN,
>> + desc->data_field_bits_size);
>> +
>> + *out = bcl->last_in_input;
>> +
>> + return 0;
>> +}
>> +
>> +static int bcl_read_alarm_status(struct bcl_device *bcl,
>> + enum bcl_limit_alarm lvl, long *status)
>> +{
>> + int ret;
>> + u32 raw_val = 0;
>> +
>> + ret = bcl_read_field_value(bcl, F_LVL0_ALARM + lvl, &raw_val);
>> + if (ret)
>> + return ret;
>> +
>> + *status = raw_val;
>> +
>> + return 0;
>> +}
>> +
>> +static unsigned int bcl_get_version_major(const struct bcl_device *bcl)
>> +{
>> + u32 raw_val = 0;
>> +
>> + bcl_read_field_value(bcl, F_V_MAJOR, &raw_val);
>> +
>> + return raw_val;
>> +}
>> +
>> +static unsigned int bcl_get_version_minor(const struct bcl_device *bcl)
>> +{
>> + u32 raw_val = 0;
>> +
>> + bcl_read_field_value(bcl, F_V_MINOR, &raw_val);
>> +
>> + return raw_val;
>> +}
>> +
>> +static void bcl_hwmon_notify_event(struct bcl_device *bcl, enum bcl_limit_alarm alarm)
>> +{
>> + if (bcl->in_mon_enabled)
>> + hwmon_notify_event(bcl->hwmon_dev, hwmon_in,
>> + in_lvl_to_attr_map[alarm], 0);
>> + if (bcl->curr_mon_enabled)
>> + hwmon_notify_event(bcl->hwmon_dev, hwmon_curr,
>> + curr_lvl_to_attr_map[alarm], 0);
>> +}
>
> What is the rate of the events we can face if they are mitigations
> happening under the hood from the HW ?
Hardware can generate events on the order of microseconds to
milliseconds, depending on the source (ADC or comparator) for that level
alarm. However, as noted earlier, software is not expected to monitor or
handle every interrupt.
>
>> +static void bcl_alarm_enable_poll(struct work_struct *work)
>> +{
>> + struct bcl_alarm_data *alarm = container_of(work, struct bcl_alarm_data,
>> + alarm_poll_work.work);
>> + struct bcl_device *bcl = alarm->device;
>> + long status;
>> +
>> + guard(mutex)(&bcl->lock);
>> +
>> + if (bcl_read_alarm_status(bcl, alarm->type, &status))
>> + goto re_schedule;
>> +
>> + if (!status & !alarm->irq_enabled) {
>> + bcl_enable_irq(alarm);
>> + bcl_hwmon_notify_event(bcl, alarm->type);
>> + return;
>> + }
>> +
>> +re_schedule:
>> + schedule_delayed_work(&alarm->alarm_poll_work,
>> + msecs_to_jiffies(BCL_ALARM_POLLING_MS));
>> +}
>> +
>> +static irqreturn_t bcl_handle_alarm(int irq, void *data)
>> +{
>> + struct bcl_alarm_data *alarm = data;
>> + struct bcl_device *bcl = alarm->device;
>> + long status;
>> +
>> + guard(mutex)(&bcl->lock);
>> +
>> + if (bcl_read_alarm_status(bcl, alarm->type, &status) || !status)
>> + return IRQ_HANDLED;
>
> So it is possible to have an interrupt but not an alarm (!status) ?
There can be a case where , by the time software handle interrupts
status can be reset due to hardware mitigation.
>
>> + if (!bcl->hwmon_dev)
>> + return IRQ_HANDLED;
>
> This should not be needed, revisit the init routine
Ack
>
>> +
>> + bcl_hwmon_notify_event(bcl, alarm->type);
>> +
>> + bcl_disable_irq(alarm);
>> + schedule_delayed_work(&alarm->alarm_poll_work,
>> + msecs_to_jiffies(BCL_ALARM_POLLING_MS));
>
> Why ?
I hope I explained this in above comment.
>
>> + dev_dbg(bcl->dev, "Irq:%d triggered for bcl type:%d\n",
>> + irq, alarm->type);
>
> Please remove, that is debug code
Ack
>
>> + return IRQ_HANDLED;
>> +}
>> +
>> +static umode_t bcl_hwmon_is_visible(const void *data,
>> + enum hwmon_sensor_types type,
>> + u32 attr, int channel)
>> +{
>> + const struct bcl_device *bcl = data;
>> +
>> + switch (type) {
>> + case hwmon_in:
>> + if (!bcl->in_mon_enabled)
>> + return 0;
>> + switch (attr) {
>> + case hwmon_in_input:
>> + return bcl->in_input_enabled ? 0444 : 0;
>> + case hwmon_in_label:
>> + case hwmon_in_min_alarm:
>> + case hwmon_in_lcrit_alarm:
>> + return 0444;
>> + case hwmon_in_min:
>> + case hwmon_in_lcrit:
>> + return 0644;
>> + default:
>> + return 0;
>> + }
>> + case hwmon_curr:
>> + if (!bcl->curr_mon_enabled)
>> + return 0;
>> + switch (attr) {
>> + case hwmon_curr_input:
>> + case hwmon_curr_label:
>> + case hwmon_curr_max_alarm:
>> + case hwmon_curr_crit_alarm:
>> + return 0444;
>> + case hwmon_curr_max:
>> + case hwmon_curr_crit:
>> + return 0644;
>> + default:
>> + return 0;
>> + }
>> + default:
>> + return 0;
>> + }
>> +}
>> +
>> +static int bcl_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
>> + u32 attr, int channel, long val)
>
> What is the benefit of the userspace to set the thresholds ? Should
> they be a platform property ?
Both use cases are required
1. Platform‑specific properties are needed to override default settings
when a platform requires different configurations due to factors such as
battery OCP Spec, attached peripherals, or differences in BCL mitigation
behavior.
2. For certain batteries, voltage droop behavior varies with ambient
conditions—particularly at low temperatures—and at low state of charge.
In these scenarios, it is recommended to trigger BCL mitigation more
aggressively than under normal conditions. User space can proactively
detect these conditions and adjust the thresholds dynamically at runtime.
>
> Should the thresholds be check to be in ascending order and separated
> with 100mV (for IN) ?
The sysfs nodes are different for each level, we don't know what order
client will request, right ? Each level settings are independent in
hardware. for IN, we can have 25mV granularity for thresholds as per
HW spec.
>
>> +{
>> + struct bcl_device *bcl = dev_get_drvdata(dev);
>> + int ret = -EOPNOTSUPP;
>> +
>> + guard(mutex)(&bcl->lock);
>> +
>> + switch (type) {
>> + case hwmon_in:
>> + switch (attr) {
>> + case hwmon_in_min:
>> + case hwmon_in_lcrit:
>> + ret = bcl_in_thresh_write(bcl, val, in_attr_to_lvl_map[attr]);
>> + break;
>> + default:
>> + ret = -EOPNOTSUPP;
>> + }
>> + break;
>> + case hwmon_curr:
>> + switch (attr) {
>> + case hwmon_curr_max:
>> + case hwmon_curr_crit:
>> + ret = bcl_curr_thresh_write(bcl, val, curr_attr_to_lvl_map[attr]);
>> + break;
>> + default:
>> + ret = -EOPNOTSUPP;
>> + }
>> + break;
>> + default:
>> + break;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static int bcl_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
>> + u32 attr, int channel, long *value)
>> +{
>> + struct bcl_device *bcl = dev_get_drvdata(dev);
>> + int ret;
>> +
>> + guard(mutex)(&bcl->lock);
>> +
>> + switch (type) {
>> + case hwmon_in:
>> + switch (attr) {
>> + case hwmon_in_input:
>> + ret = bcl_in_input_read(bcl, value);
>> + break;
>> + case hwmon_in_min:
>> + case hwmon_in_lcrit:
>> + ret = bcl_in_thresh_read(bcl, in_attr_to_lvl_map[attr], value);
>> + break;
>> + case hwmon_in_min_alarm:
>> + case hwmon_in_lcrit_alarm:
>> + ret = bcl_read_alarm_status(bcl, in_attr_to_lvl_map[attr], value);
>> + break;
>> + default:
>> + ret = -EOPNOTSUPP;
>> + }
>> + break;
>
> Please split this function into:
>
> case hwmon_in:
> return bcl_in_read();
> case hwmon_curr:
> return bcl_curr_read();
> default:
> return -EOPNOTSUPP;
>
Ack
>> + case hwmon_curr:
>> + switch (attr) {
>> + case hwmon_curr_input:
>> + ret = bcl_curr_input_read(bcl, value);
>> + break;
>> + case hwmon_curr_max:
>> + case hwmon_curr_crit:
>> + ret = bcl_curr_thresh_read(bcl, curr_attr_to_lvl_map[attr], value);
>> + break;
>> + case hwmon_curr_max_alarm:
>> + case hwmon_curr_crit_alarm:
>> + ret = bcl_read_alarm_status(bcl, curr_attr_to_lvl_map[attr], value);
>> + break;
>> + default:
>> + ret = -EOPNOTSUPP;
>> + }
>> + break;
>> + default:
>> + ret = -EOPNOTSUPP;
>> + break;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static int bcl_hwmon_read_string(struct device *dev,
>> + enum hwmon_sensor_types type,
>> + u32 attr, int channel, const char **str)
>> +{
>> + switch (type) {
>> + case hwmon_in:
>> + if (attr != hwmon_in_label)
>> + break;
>> + *str = bcl_channel_label[IN];
>
> Why not use 'channel' passed as parameter ?
Ack, Since we are already enabling IN macros, explictly used it. I can
change it into channel id.
>
>> + return 0;
>> + case hwmon_curr:
>> + if (attr != hwmon_curr_label)
>> + break;
>> + *str = bcl_channel_label[CURR];
>> + return 0;
>> + default:
>> + break;
>> + }
>> +
>> + return -EOPNOTSUPP;
>
> Given there are few channels I suggest to simplify to:
>
> if (type == hwmon_in && attr == hwmon_in_label) {
> *str = "BCL Voltage";
> } else if (type == hwmon_curr && attr == hwmon_curr_label) {
> *str = "BCL Current";
> } else {
> *str = NULL;
> }
>
> return *str ? 0 : -EOPNOTSUPP;
>
> Up to you.
Ack
>
>> +}
>> +
>> +static const struct hwmon_ops bcl_hwmon_ops = {
>> + .is_visible = bcl_hwmon_is_visible,
>> + .read = bcl_hwmon_read,
>> + .read_string = bcl_hwmon_read_string,
>> + .write = bcl_hwmon_write,
>> +};
>> +
>> +static const struct hwmon_channel_info *bcl_hwmon_info[] = {
>> + HWMON_CHANNEL_INFO(in,
>> + HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_MIN |
>> + HWMON_I_LCRIT | HWMON_I_MIN_ALARM |
>> + HWMON_I_LCRIT_ALARM),
>> + HWMON_CHANNEL_INFO(curr,
>> + HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_MAX |
>> + HWMON_C_CRIT | HWMON_C_MAX_ALARM |
>> + HWMON_C_CRIT_ALARM),
>> + NULL,
>> +};
>> +
>> +static const struct hwmon_chip_info bcl_hwmon_chip_info = {
>> + .ops = &bcl_hwmon_ops,
>> + .info = bcl_hwmon_info,
>> +};
>> +
>> +static int bcl_curr_thresh_update(struct bcl_device *bcl)
>> +{
>> + int ret, i;
>> +
>> + if (!bcl->curr_thresholds[0])
>> + return 0;
>> +
>> + for (i = 0; i < ALARM_MAX; i++) {
>> + ret = bcl_curr_thresh_write(bcl, bcl->curr_thresholds[i], i);
>> + if (ret < 0)
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void bcl_hw_channel_mon_init(struct bcl_device *bcl)
>> +{
>> + bcl->in_mon_enabled = bcl_in_monitor_enabled(bcl);
>> + bcl->in_input_enabled = bcl_in_input_enabled(bcl);
>> + bcl->curr_mon_enabled = bcl_curr_monitor_enabled(bcl);
>
> Can you describe why we can have this optionnal ?
There are different type of BCL where same hw is used with reduced
fuctionality due to limitation of source/input of alarm in underlying pmic.
>
> Why not set bcl_hwmon_info[] regarding what is enabled instead of
> having boolean checks all over the place ?
I could see multiple reference where all dynamic controls of
channel/channel attributes are controlled via is_visible callback. I
followed the same approach here.
>
>> +}
>> +
>> +static int bcl_alarm_irq_init(struct platform_device *pdev,
>> + struct bcl_device *bcl)
>> +{
>> + int ret = 0, irq_num = 0, i = 0;
>> + struct bcl_alarm_data *alarm;
>> +
>> + for (i = LVL0; i < ALARM_MAX; i++) {
>> + alarm = &bcl->bcl_alarms[i];
>> + alarm->type = i;
>> + alarm->device = bcl;
>> +
>> + ret = devm_delayed_work_autocancel(bcl->dev, &alarm->alarm_poll_work,
>> + bcl_alarm_enable_poll);
>> + if (ret)
>> + return ret;
>
> Why ?
I hope I explained it in above comment.
>
>> + irq_num = platform_get_irq_byname(pdev, bcl_int_names[i]);
>> + if (irq_num <= 0)
>> + continue;
>> +
>> + ret = devm_request_threaded_irq(&pdev->dev, irq_num, NULL,
>> + bcl_handle_alarm, IRQF_ONESHOT,
>> + bcl_int_names[i], alarm);
>> + if (ret) {
>> + dev_err(&pdev->dev, "Error requesting irq(%s).err:%d\n",
>> + bcl_int_names[i], ret);
>> + return ret;
>> + }
>> + enable_irq_wake(alarm->irq);
>> + alarm->irq_enabled = true;
>> + alarm->irq = irq_num;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int bcl_regmap_field_init(struct device *dev, struct bcl_device *bcl,
>> + const struct bcl_desc *data)
>> +{
>> + int i;
>> + struct reg_field fields[F_MAX_FIELDS];
>> +
>> + BUILD_BUG_ON(ARRAY_SIZE(common_reg_fields) != COMMON_FIELD_MAX);
>
> No, this error implies the way the fields are declared is fragile, may
> be revisit the declaration.
Ack
>
>> +
>> + for (i = 0; i < data->num_reg_fields; i++) {
>> + if (i < COMMON_FIELD_MAX)
>> + fields[i] = common_reg_fields[i];
>> + else
>> + fields[i] = data->reg_fields[i];
>> +
>> + /* Need to adjust BCL base from regmap dynamically */
>> + fields[i].reg += bcl->base;
>> + }
>> +
>> + return devm_regmap_field_bulk_alloc(dev, bcl->regmap, bcl->fields,
>> + fields, data->num_reg_fields);
>> +}
>> +
>> +static int bcl_get_device_property_data(struct platform_device *pdev,
>> + struct bcl_device *bcl)
>
> *dev could be passed as parameter instead of *pdev
Ack
>
>> +{
>> + struct device *dev = &pdev->dev;
>> + int ret;
>> + u32 reg;
>> +
>> + ret = device_property_read_u32(dev, "reg", ®);
>> + if (ret < 0)
>> + return ret;
>> +
>> + bcl->base = reg;
>> +
>> + device_property_read_u32_array(dev, "overcurrent-thresholds-milliamp",
>> + bcl->curr_thresholds, 2);
>
> Why don't you want this as a required property ?
Default settings will be enabled in early boot firmware. If need to
change different setting, then only need to enable this property due to
different platform factors mentioned above.
>
>> + return 0;
>> +}
>> +
>> +static int bcl_probe(struct platform_device *pdev)
>> +{
>> + struct bcl_device *bcl;
>> + int ret;
>> +
>> + bcl = devm_kzalloc(&pdev->dev, sizeof(*bcl), GFP_KERNEL);
>> + if (!bcl)
>> + return -ENOMEM;
>> +
>> + bcl->dev = &pdev->dev;
>> + bcl->desc = device_get_match_data(&pdev->dev);
>> + if (!bcl->desc)
>> + return -EINVAL;
>> +
>> + ret = devm_mutex_init(bcl->dev, &bcl->lock);
>> + if (ret)
>> + return ret;
>> +
>> + bcl->regmap = dev_get_regmap(pdev->dev.parent, NULL);
>> + if (!bcl->regmap) {
>> + dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
>> + return -EINVAL;
>> + }
>> +
>> + ret = bcl_get_device_property_data(pdev, bcl);
>> + if (ret < 0)
>> + return ret;
>> +
>> + ret = bcl_regmap_field_init(bcl->dev, bcl, bcl->desc);
>> + if (ret < 0) {
>> + dev_err(&pdev->dev, "Unable to allocate regmap fields, err:%d\n", ret);
>> + return ret;
>> + }
>> +
>> + if (!bcl_hw_is_enabled(bcl))
>> + return -ENODEV;
>> +
>> + ret = bcl_curr_thresh_update(bcl);
>> + if (ret < 0)
>> + return ret;
>> +
>> + ret = bcl_alarm_irq_init(pdev, bcl);
>> + if (ret < 0)
>> + return ret;
>> +
>> + bcl_hw_channel_mon_init(bcl);
>> +
>> + dev_set_drvdata(&pdev->dev, bcl);
>> +
>> + bcl->hwmon_name = devm_hwmon_sanitize_name(&pdev->dev,
>> + dev_name(bcl->dev));
>> + if (IS_ERR(bcl->hwmon_name)) {
>> + dev_err(&pdev->dev, "Failed to sanitize hwmon name\n");
>> + return PTR_ERR(bcl->hwmon_name);
>> + }
>> +
>> + bcl->hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
>> + bcl->hwmon_name,
>> + bcl,
>> + &bcl_hwmon_chip_info,
>> + NULL);
>> + if (IS_ERR(bcl->hwmon_dev)) {
>> + dev_err(&pdev->dev, "Failed to register hwmon device: %ld\n",
>> + PTR_ERR(bcl->hwmon_dev));
>> + return PTR_ERR(bcl->hwmon_dev);
>> + }
>> +
>> + dev_dbg(&pdev->dev, "BCL hwmon device with version: %u.%u registered\n",
>> + bcl_get_version_major(bcl), bcl_get_version_minor(bcl));
>> +
>> + return 0;
>> +}
>> +
>> +static const struct of_device_id bcl_match[] = {
>> + {
>> + .compatible = "qcom,bcl-v1",
>> + .data = &pm7250b_data,
>> + }, {
>> + .compatible = "qcom,bcl-v2",
>> + .data = &pm8350_data,
>> + }, {
>> + .compatible = "qcom,bcl-v3-bmx",
>> + .data = &pm8550b_data,
>> + }, {
>> + .compatible = "qcom,bcl-v3-wb",
>> + .data = &pmw5100_data,
>> + }, {
>> + .compatible = "qcom,bcl-v3-core",
>> + .data = &pm8550_data,
>> + }, {
>> + .compatible = "qcom,bcl-v4-bmx",
>> + .data = &pmih010_data,
>> + }, {
>> + .compatible = "qcom,bcl-v4-wb",
>> + .data = &pmw6100_data,
>> + }, {
>> + .compatible = "qcom,bcl-v4-core",
>> + .data = &pmh010_data,
>> + }, {
>> + .compatible = "qcom,bcl-v4-pmv010",
>> + .data = &pmv010_data,
>> + },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(of, bcl_match);
>> +
>> +static struct platform_driver bcl_driver = {
>> + .probe = bcl_probe,
>> + .driver = {
>> + .name = BCL_DRIVER_NAME,
>> + .of_match_table = bcl_match,
>> + },
>> +};
>> +
>> +MODULE_AUTHOR("Manaf Meethalavalappu Pallikunhi <manaf.pallikunhi@oss.qualcomm.com>");
>> +MODULE_DESCRIPTION("QCOM BCL HWMON driver");
>> +module_platform_driver(bcl_driver);
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/hwmon/qcom-bcl-hwmon.h b/drivers/hwmon/qcom-bcl-hwmon.h
>> new file mode 100644
>> index 000000000000..28a7154d9486
>> --- /dev/null
>> +++ b/drivers/hwmon/qcom-bcl-hwmon.h
>
> As there is nothing shared with other files, no header is needed.
Ack
>
>> @@ -0,0 +1,311 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (c) 2026, Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef __QCOM_BCL_HWMON_H__
>> +#define __QCOM_BCL_HWMON_H__
>> +
>> +#define BCL_DRIVER_NAME "qcom-bcl-hwmon"
>> +
>> +/* BCL common regmap offset */
>> +#define REVISION1 0x0
>> +#define REVISION2 0x1
>> +#define STATUS 0x8
>> +#define INT_RT_STS 0x10
>> +#define EN_CTL1 0x46
>> +
>> +/* BCL GEN1 regmap offsets */
>> +#define MODE_CTL1 0x41
>> +#define VADC_L0_THR 0x48
>> +#define VCMP_L1_THR 0x49
>> +#define IADC_H0_THR 0x4b
>> +#define IADC_H1_THR 0x4c
>> +#define VADC_CONV_REQ 0x72
>> +#define IADC_CONV_REQ 0x82
>> +#define VADC_DATA1 0x76
>> +#define IADC_DATA1 0x86
>> +
>> +/* BCL GEN3 regmap offsets */
>> +#define VCMP_CTL 0x44
>> +#define VCMP_L0_THR 0x47
>> +#define PARAM_1 0x0e
>> +#define IADC_H1_THR_GEN3 0x4d
>> +
>> +#define BCL_IN_INC_MV 25
>> +#define BCL_ALARM_POLLING_MS 50
>> +
>> +/**
>> + * enum bcl_limit_alarm - BCL alarm threshold levels
>> + * @LVL0: Level 0 alarm threshold (mapped to in_min_alarm or curr_max_alarm)
>> + * @LVL1: Level 1 alarm threshold (mapped to in_lcrit_alarm or curr_crit_alarm)
>> + * @ALARM_MAX: sentinel value
>> + *
>> + * Defines the three threshold levels for BCL monitoring. Each level corresponds
>> + * to different severity of in or curr conditions.
>> + */
>> +enum bcl_limit_alarm {
>> + LVL0,
>> + LVL1,
>> + ALARM_MAX,
>> +};
>
> These are too generic names and they can collide with other
> subsystems. BCL_LIMIT_ALRM_LVL0/1, BLC_LIMIT_ALRM_MAX should be fine.
Ack
>
>> +/**
>> + * enum bcl_channel_type - BCL supported sensor channel type
>> + * @IN: in (voltage) channel
>> + * @CURR: curr (current) channel
>> + * @CHANNEL_MAX: sentinel value
>> + *
>> + * Defines the supported channel types for bcl.
>> + */
>> +enum bcl_channel_type {
>
> s/bcl_channel_type/bcl_channel/ ?
Ack
>
>> + IN,
>> + CURR,
>> +
>> + CHANNEL_MAX,
>> +};
>
> Same comment: BCL_CHANNEL_IN, BCL_CHANNEL_CURR, BCL_CHANNEL_MAX
Ack
>
>> +/**
>> + * enum bcl_thresh_type - voltage or current threshold representation type
>> + * @ADC: Raw ADC value representation
>> + * @INDEX: Index-based voltage or current representation
>> + *
>> + * Specifies how voltage or current thresholds are stored and interpreted in
>> + * registers. Some PMICs use raw ADC values while others use indexed values.
>> + */
>> +enum bcl_thresh_type {
>> + ADC,
>> + INDEX,
>> +};
>
> Ditto
Ack
>
>> +/**
>> + * enum bcl_fields - BCL register field identifiers
>> + * @F_V_MAJOR: Major revision info field
>> + * @F_V_MINOR: Minor revision info field
>> + * @F_CTL_EN: Monitor enable control field
>> + * @F_LVL0_ALARM: Level 0 alarm status field
>> + * @F_LVL1_ALARM: Level 1 alarm status field
>> + * @COMMON_FIELD_MAX: sentinel value for common fields
>> + * @F_IN_MON_EN: voltage monitor enable control field
>> + * @F_IN_L0_THR: voltage level 0 threshold field
>> + * @F_IN_L1_THR: voltage level 1 threshold field
>> + * @F_IN_INPUT_EN: voltage input enable control field
>> + * @F_IN_INPUT: voltage input data field
>> + * @F_CURR_MON_EN: current monitor enable control field
>> + * @F_CURR_H0_THR: current level 0 threshold field
>> + * @F_CURR_H1_THR: current level 1 threshold field
>> + * @F_CURR_INPUT: current input data field
>> + * @F_MAX_FIELDS: sentinel value
>> + *
>> + * Enumeration of all register fields used by the BCL driver for accessing
>> + * registers through regmap fields.
>> + */
>> +enum bcl_fields {
>> + F_V_MAJOR,
>> + F_V_MINOR,
>> +
>> + F_CTL_EN,
>> +
>> + /* common alarm for in and curr channel */
>> + F_LVL0_ALARM,
>> + F_LVL1_ALARM,
>> +
>> + COMMON_FIELD_MAX,
>> +
>> + F_IN_MON_EN = COMMON_FIELD_MAX,
>> + F_IN_L0_THR,
>> + F_IN_L1_THR,
>> +
>> + F_IN_INPUT_EN,
>> + F_IN_INPUT,
>> +
>> + F_CURR_MON_EN,
>> + F_CURR_H0_THR,
>> + F_CURR_H1_THR,
>> +
>> + F_CURR_INPUT,
>> +
>> + F_MAX_FIELDS
>> +};
>
> Usually this is described with macro, not enum.
We need field index in ascending order. enum by default will do the
same, right ?
>
>> +#define ADD_BCL_HWMON_ALARM_MAPS(_type, lvl0_attr, lvl1_attr) \
>> + \
>> +static const u8 _type##_attr_to_lvl_map[] = { \
>> + [hwmon_##_type##_##lvl0_attr] = LVL0, \
>> + [hwmon_##_type##_##lvl1_attr] = LVL1, \
>> + [hwmon_##_type##_##lvl0_attr##_alarm] = LVL0, \
>> + [hwmon_##_type##_##lvl1_attr##_alarm] = LVL1, \
>> +}; \
>> + \
>> +static const u8 _type##_lvl_to_attr_map[ALARM_MAX] = { \
>> + [LVL0] = hwmon_##_type##_##lvl0_attr##_alarm, \
>> + [LVL1] = hwmon_##_type##_##lvl1_attr##_alarm, \
>> +}
>
> Please avoid these macros, they don't help to the readability.
Ack
>
>> +/**
>> + * struct bcl_channel_cfg - BCL channel related configuration
>> + * @default_scale_nu: Default scaling factor in nano unit
>> + * @base: Base threshold value in milli unit
>> + * @max: Maximum threshold value in milli unit
>> + * @step: step increment value between two indexed threshold value
>> + * @thresh_type: Array specifying threshold representation type for each alarm level
>> + *
>> + * Contains hardware-specific configuration and scaling parameters for different
>> + * channel(voltage and current)..
>> + */
>> +
>> +struct bcl_channel_cfg {
>> + u32 default_scale_nu;
>> + u32 base;
>> + u32 max;
>> + u32 step;
>> + u8 thresh_type[ALARM_MAX];
>> +};
>> +
>> +/**
>> + * struct bcl_desc - BCL device descriptor
>> + * @reg_fields: Array of register field definitions for this device variant
>> + * @channel: Each channel specific(voltage or current) configuration
>> + * @num_reg_fields: Number of register field definitions for this device variant
>> + * @data_field_bits_size: data read register bit size
>> + * @thresh_field_bits_size: lsb bit size those are not included in threshold register
>> + *
>> + * Contains hardware-specific configuration and scaling parameters for different
>> + * BCL variants. Each PMIC model may have different register layouts and
>> + * conversion factors.
>> + */
>> +
>> +struct bcl_desc {
>> + const struct reg_field *reg_fields;
>> + struct bcl_channel_cfg channel[CHANNEL_MAX];
>> + u8 num_reg_fields;
>> + u8 data_field_bits_size;
>> + u8 thresh_field_bits_size;
>> +};
>> +
>> +struct bcl_device;
>
> No forward declaration, reorg the structure definitions below
Ack
>
>> +/**
>> + * struct bcl_alarm_data - BCL alarm interrupt data
>> + * @irq: IRQ number assigned to this alarm
>> + * @irq_enabled: Flag indicating if IRQ is enabled
>> + * @type: Alarm level type (LVL0, or LVL1)
>> + * @device: Pointer to parent BCL device structure
>> + * @alarm_poll_work: delayed_work to poll alarm status
>
> Why do you want to poll the alarm status if there is an interrupt ?
Please see above response for the same.
>
>> + *
>> + * Stores interrupt-related information for each alarm threshold level.
>> + * Used by the IRQ handler to identify which alarm triggered.
>> + */
>> +struct bcl_alarm_data {
>> + int irq;
>> + bool irq_enabled;
>> + enum bcl_limit_alarm type;
>> + struct bcl_device *device;
>> + struct delayed_work alarm_poll_work;
>> +};
>> +
>> +/**
>> + * struct bcl_device - Main BCL device structure
>> + * @dev: Pointer to device structure
>> + * @regmap: Regmap for accessing PMIC registers
>> + * @fields: Array of regmap fields for register access
>> + * @bcl_alarms: Array of alarm data structures for each threshold level
>> + * @lock: Mutex for protecting concurrent hardware access
>> + * @in_mon_enabled: Flag indicating if voltage monitoring is enabled
>> + * @curr_mon_enabled: Flag indicating if current monitoring is enabled
>> + * @curr_thresholds: Current threshold values in milliamps from dt-binding(LVL0 and LVL1)
>> + * @base: the BCL regbase offset from regmap
>> + * @in_input_enabled: Flag indicating if voltage input reading is enabled
>> + * @last_in_input: Last valid voltage input reading in millivolts
>> + * @last_curr_input: Last valid current input reading in milliamps
>> + * @desc: Pointer to device descriptor with hardware-specific parameters
>> + * @hwmon_dev: Pointer to registered hwmon device
>> + * @hwmon_name: Sanitized name for hwmon device
>> + *
>> + * Main driver structure containing all state and configuration for a BCL
>> + * monitoring instance. Manages voltage and current monitoring, thresholds,
>> + * and alarm handling.
>> + */
>> +struct bcl_device {
>> + struct device *dev;
>
> This field is unnecessary if the debug message is removed from the
> interrupt handler.
Ack
>
>> + struct regmap *regmap;
>> + u16 base;
>> + struct regmap_field *fields[F_MAX_FIELDS];
>> + struct bcl_alarm_data bcl_alarms[ALARM_MAX];
>> + struct mutex lock;
>
> What is this lock for ?
To synchronize userspace request and irq handler handling.
I also need to add per alarm lock to avoid some race conditon based on
another comment.
Thanks,
Manaf
>
>> + u32 curr_thresholds[ALARM_MAX];
>> + u32 last_in_input;
>> + u32 last_curr_input;
>> + bool in_mon_enabled;
>> + bool curr_mon_enabled;
>> + bool in_input_enabled;
>> + const struct bcl_desc *desc;
>> + struct device *hwmon_dev;
>> + char *hwmon_name;
>> +};
>> +
>> +/**
>> + * bcl_read_field_value - Read alarm status for a given level
>> + * @bcl: BCL device structure
>> + * @id: Index in bcl->fields[]
>> + * @val: Pointer to store val
>> + *
>> + * Return: 0 on success or regmap error code
>> + */
>> +static inline int bcl_read_field_value(const struct bcl_device *bcl, enum bcl_fields id, u32 *val)
>> +{
>> + return regmap_field_read(bcl->fields[id], val);
>> +}
>> +
>> +/**
>> + * bcl_field_enabled - Generic helper to check if a regmap field is enabled
>> + * @bcl: BCL device structure
>> + * @field: Index in bcl->fields[]
>> + *
>> + * Return: true if field is non-zero, false otherwise
>> + */
>> +static inline bool bcl_field_enabled(const struct bcl_device *bcl, enum bcl_fields id)
>> +{
>> + int ret;
>> + u32 val = 0;
>> +
>> + ret = regmap_field_read(bcl->fields[id], &val);
>> + if (ret)
>> + return false;
>> +
>> + return !!val;
>> +}
>> +
>> +#define bcl_in_input_enabled(bcl) bcl_field_enabled(bcl, F_IN_INPUT_EN)
>> +#define bcl_curr_monitor_enabled(bcl) bcl_field_enabled(bcl, F_CURR_MON_EN)
>> +#define bcl_in_monitor_enabled(bcl) bcl_field_enabled(bcl, F_IN_MON_EN)
>> +#define bcl_hw_is_enabled(bcl) bcl_field_enabled(bcl, F_CTL_EN)
>> +
>> +/**
>> + * bcl_enable_irq - Generic helper to enable alarm irq
>> + * @alarm: BCL level alarm data
>> + */
>> +static inline void bcl_enable_irq(struct bcl_alarm_data *alarm)
>> +{
>> + if (alarm->irq_enabled)
>> + return;
>> + alarm->irq_enabled = true;
>> + enable_irq(alarm->irq);
>> + enable_irq_wake(alarm->irq);
>> +}
>> +
>> +/**
>> + * bcl_disable_irq - Generic helper to disable alarm irq
>> + * @alarm: BCL level alarm data
>> + */
>> +static inline void bcl_disable_irq(struct bcl_alarm_data *alarm)
>> +{
>> + if (!alarm->irq_enabled)
>> + return;
>> + alarm->irq_enabled = false;
>> + disable_irq_nosync(alarm->irq);
>> + disable_irq_wake(alarm->irq);
>> +}
>> +#endif /* __QCOM_BCL_HWMON_H__ */
>>
>> --
>> 2.43.0
>>
>
^ permalink raw reply
* Re: [PATCH 00/40] arm64: dts: rockchip: Wire up frl-enable-gpios for RK3576/RK3588 boards
From: Cristian Ciocaltea @ 2026-04-17 17:55 UTC (permalink / raw)
To: Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: kernel, devicetree, linux-arm-kernel, linux-rockchip,
linux-kernel
In-Reply-To: <2297365.1BCLMh4Saa@phil>
Hi Heiko,
On 4/17/26 2:34 PM, Heiko Stuebner wrote:
> Hi Cristan,
>
> Am Freitag, 17. April 2026, 11:24:34 Mitteleuropäische Sommerzeit schrieb Cristian Ciocaltea:
>
> [...]
>
>> Cristian Ciocaltea (40):
>> arm64: dts: rockchip: Add frl-enable-gpios to rk3576-100ask-dshanpi-a1
>> arm64: dts: rockchip: Add frl-enable-gpios to rk3576-armsom-sige5
>> arm64: dts: rockchip: Add frl-enable-gpios to rk3576-evb1-v10
>> arm64: dts: rockchip: Add frl-enable-gpios to rk3576-evb2-v10
>> arm64: dts: rockchip: Add frl-enable-gpios to rk3576-luckfox-core3576
>> arm64: dts: rockchip: Add frl-enable-gpios to rk3576-nanopi-m5
>> arm64: dts: rockchip: Add frl-enable-gpios to rk3576-nanopi-r76s
>> arm64: dts: rockchip: Add frl-enable-gpios to rk3576-roc-pc
>> arm64: dts: rockchip: Add frl-enable-gpios to rk3576-rock-4d
>
> I do think one patch per SoC (rk3576, rk3588, rk3588s) would make more
> sense, because these patches really are mostly identical :-)
Yeah, apologies for the large number of patches, I went this way to allow
per-board reviews. As previously noted, I tried to identify the GPIO pins from
multiple sources, so I'm not entirely sure about the accuracy in every case.
Would it be preferable to squash the patches per SoC and board vendor, instead?
Thanks,
Cristian
^ permalink raw reply
* [PATCH 2/3] dt-bindings: display: bridge: Document Renesas RZ/G3L LVDS encoder
From: Biju @ 2026-04-17 17:52 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm
Cc: Biju Das, Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Tommaso Merciai, dri-devel, devicetree, linux-kernel,
linux-renesas-soc, Prabhakar Mahadev Lad, Biju Das
In-Reply-To: <20260417175235.224809-1-biju.das.jz@bp.renesas.com>
From: Biju Das <biju.das.jz@bp.renesas.com>
Document the LVDS encoder IP found on the RZ/G3L SoC. It supports
single-link mode. LVDS and the DSI interface share a peripheral clock and
the MIPI_DSI_PRESET_N reset signal. However, the LVDS module cannot be
used at the same time as MIPI-DSI.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
.../bridge/renesas,r9a08g046-lvds.yaml | 128 ++++++++++++++++++
1 file changed, 128 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/bridge/renesas,r9a08g046-lvds.yaml
diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,r9a08g046-lvds.yaml b/Documentation/devicetree/bindings/display/bridge/renesas,r9a08g046-lvds.yaml
new file mode 100644
index 000000000000..b1f6d020ae7b
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/renesas,r9a08g046-lvds.yaml
@@ -0,0 +1,128 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/renesas,r9a08g046-lvds.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G3L LVDS Encoder
+
+maintainers:
+ - Biju Das <biju.das.jz@bp.renesas.com>
+ - Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
+
+description: |
+ This binding describe the LVDS encoder embedded in the Renesas RZ/G3L
+ SoC. The encoder can operate in LVDS Single-link mode with 4 lanes
+ (Data) + 1 lane (Clock).
+
+properties:
+ compatible:
+ const: renesas,r9a08g046-lvds
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Peripheral clock
+ - description: PHY clock
+ - description: Dot clock
+
+ clock-names:
+ items:
+ - const: pclk
+ - const: phyclk
+ - const: dotclk
+
+ resets:
+ items:
+ - description: LVDS_RESET_N
+ - description: MIPI_DSI_PRESET_N
+ - description: MIPI_DSI_CMN_RSTB
+ - description: MIPI_DSI_ARESET_N
+
+ reset-names:
+ items:
+ - const: lvdrst
+ - const: prst
+ - const: rst
+ - const: arst
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Input channel, directly connected to the Display Unit.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: |
+ Output channel, directly connected to the LVDS panel or bridge.
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - power-domains
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/renesas,r9a08g046-cpg.h>
+
+ lvds-cmn@108a0000 {
+ compatible = "renesas,r9a08g046-lvds-cmn",
+ "simple-mfd", "syscon";
+ reg = <0x108a0000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ lvds0: lvds@10 {
+ compatible = "renesas,r9a08g046-lvds";
+ reg = <0x10 0x8>;
+ clocks = <&cpg CPG_MOD R9A08G046_MIPI_DSI_PCLK>,
+ <&cpg CPG_MOD R9A08G046_LVDS_PLLCLK>,
+ <&cpg CPG_MOD R9A08G046_LVDS_CLK_DOT0>;
+ clock-names = "pclk", "phyclk", "dotclk";
+ resets = <&cpg R9A08G046_LVDS_RESET_N>,
+ <&cpg R9A08G046_MIPI_DSI_PRESET_N>,
+ <&cpg R9A08G046_MIPI_DSI_CMN_RSTB>,
+ <&cpg R9A08G046_MIPI_DSI_ARESET_N>;
+ reset-names = "lvdrst", "prst", "rst", "arst";
+ power-domains = <&cpg>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ lvds0_in: endpoint {
+ remote-endpoint = <&du_out_lvds0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+ };
+ };
+...
--
2.43.0
^ permalink raw reply related
* [PATCH 1/3] dt-bindings: mfd: syscon: Document the LVDS_CMN syscon for the RZ/G3L
From: Biju @ 2026-04-17 17:52 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm
Cc: Biju Das, devicetree, linux-kernel, linux-renesas-soc,
Prabhakar Mahadev Lad, Biju Das, Tommaso Merciai
In-Reply-To: <20260417175235.224809-1-biju.das.jz@bp.renesas.com>
From: Biju Das <biju.das.jz@bp.renesas.com>
The RZ/G3{E,L} SoCs have an LVDS Common (LVDS_CMN) region which is common
to all LVDS channels. The RZ/G3L has single-link, but the RZ/G3E has both
single and dual-link.
Use the syscon interface to access these registers for scalability.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
Documentation/devicetree/bindings/mfd/syscon.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
index e22867088063..9c81010d5a74 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
@@ -221,6 +221,7 @@ properties:
- nxp,s32g3-gpr
- qcom,apq8064-mmss-sfpb
- qcom,apq8064-sps-sic
+ - renesas,r9a08g046-lvds-cmn
- rockchip,px30-qos
- rockchip,rk3036-qos
- rockchip,rk3066-qos
--
2.43.0
^ permalink raw reply related
* [PATCH 0/3] Add support for Renesas RZ/G3L LVDS encoder
From: Biju @ 2026-04-17 17:52 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Philipp Zabel, Geert Uytterhoeven, Magnus Damm
Cc: Biju Das, Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Tommaso Merciai, dri-devel, devicetree, linux-kernel,
linux-renesas-soc, Prabhakar Mahadev Lad, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
Add support for the RZ/G3L LVDS encoder driver. It operates in single-link
mode with 4 lanes (Data) + 1 lane (Clock) and supports pixel clock rates
from 25 to 87 MHz. The LVDS module cannot be used at the same time as
MIPI-DSI. However, LVDS and the DSI interface share a peripheral clock and
the MIPI_DSI_PRESET_N reset signal. Also, the MIPI_DSI_CMN_RSTB and
MIPI_DSI_ARESET_N reset signals must be asserted before using the LVDS
module.
Biju Das (3):
dt-bindings: mfd: syscon: Document the LVDS_CMN syscon for the RZ/G3L
dt-bindings: display: bridge: Document Renesas RZ/G3L LVDS encoder
drm: renesas: rz-du: Add support for RZ/G3L LVDS encoder
.../bridge/renesas,r9a08g046-lvds.yaml | 128 +++++++
.../devicetree/bindings/mfd/syscon.yaml | 1 +
drivers/gpu/drm/renesas/rz-du/Kconfig | 13 +
drivers/gpu/drm/renesas/rz-du/Makefile | 1 +
drivers/gpu/drm/renesas/rz-du/rzg3l_lvds.c | 333 ++++++++++++++++++
drivers/gpu/drm/renesas/rz-du/rzg3l_lvds.h | 22 ++
.../gpu/drm/renesas/rz-du/rzg3l_lvds_regs.h | 26 ++
7 files changed, 524 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/bridge/renesas,r9a08g046-lvds.yaml
create mode 100644 drivers/gpu/drm/renesas/rz-du/rzg3l_lvds.c
create mode 100644 drivers/gpu/drm/renesas/rz-du/rzg3l_lvds.h
create mode 100644 drivers/gpu/drm/renesas/rz-du/rzg3l_lvds_regs.h
--
2.43.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox