Devicetree
 help / color / mirror / Atom feed
* [PATCH v2 1/3] dt-bindings: iio: health: add maxim,max86150
From: Md Shofiqul Islam @ 2026-06-23 15:55 UTC (permalink / raw)
  To: linux-iio
  Cc: jic23, dlechner, nuno.sa, robh, krzk+dt, conor+dt, devicetree,
	joshua.crofts1, Md Shofiqul Islam
In-Reply-To: <20260623155556.13701-1-shofiqtest@gmail.com>

Add YAML schema binding for the Maxim MAX86150 combined ECG and PPG
biosensor.  The device communicates over I2C at up to 400 kHz and
exposes an active-low interrupt when the 32-entry hardware FIFO
reaches its configurable almost-full threshold.

Signed-off-by: Md Shofiqul Islam <shofiqtest@gmail.com>
---
 .../bindings/iio/health/maxim,max86150.yaml   | 67 +++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100755 Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml

diff --git a/Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml b/Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml
new file mode 100755
index 000000000000..1bf10fd1a3d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/health/maxim,max86150.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim MAX86150 ECG and PPG Biosensor
+
+maintainers:
+  - Md Shofiqul Islam <shofiqtest@gmail.com>
+
+description: |
+  The MAX86150 is an integrated biosensor SoC that combines:
+    - Two PPG (photoplethysmography) channels: Red LED and IR LED,
+      for heart rate and blood-oxygen saturation (SpO2) measurement.
+    - One ECG (electrocardiogram) channel for biopotential recording.
+
+  The device communicates over I2C at up to 400 kHz and raises an
+  active-low interrupt when the 32-entry hardware FIFO reaches its
+  configurable almost-full threshold.
+
+  Datasheet:
+    https://www.analog.com/media/en/technical-documentation/data-sheets/MAX86150.pdf
+
+properties:
+  compatible:
+    const: maxim,max86150
+
+  reg:
+    maxItems: 1
+    description: I2C device address, always 0x5E.
+
+  interrupts:
+    maxItems: 1
+    description: |
+      Active-low interrupt line.  Asserted when the FIFO almost-full
+      threshold is reached or when a new PPG sample is ready.
+
+  vdd-supply:
+    description: Digital core supply, 1.71 V to 1.89 V.
+
+  leds-supply:
+    description: LED anode supply, 3.0 V to 5.5 V.
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        biosensor@5e {
+            compatible = "maxim,max86150";
+            reg = <0x5e>;
+            interrupt-parent = <&gpio1>;
+            interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+            vdd-supply = <&vdd_1v8>;
+            leds-supply = <&vdd_3v3>;
+        };
+    };
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 0/3] iio: health: add MAX86150 ECG and PPG biosensor driver
From: Md Shofiqul Islam @ 2026-06-23 15:55 UTC (permalink / raw)
  To: linux-iio
  Cc: jic23, dlechner, nuno.sa, robh, krzk+dt, conor+dt, devicetree,
	joshua.crofts1, Md Shofiqul Islam
In-Reply-To: <20260623140113.12574-1-shofiqtest@gmail.com>

The MAX86150 (Maxim/Analog Devices) combines two PPG optical channels
(Red/IR LED) and one ECG biopotential channel in a single I2C device.
Data is produced at up to 3200 Hz and buffered in a 32-entry hardware
FIFO with a configurable almost-full interrupt.

This series adds:
  1. DT binding YAML schema for maxim,max86150
  2. IIO driver with triggered buffer support
  3. MAINTAINERS entry

Changes in v2 (addressing Sashiko AI review, Joshua Crofts, Krzysztof Kozlowski):
  - Fix buffer overflow: expand scan buffer to s32 buf[6] to hold
    3 x s32 channels + 4-byte pad + s64 timestamp (24 bytes total)
  - Add iio_device_claim_direct() in read_raw to prevent concurrent
    sysfs reads from corrupting FIFO pointers during buffer capture
  - Fix FIFO-full detection: read OVF_COUNTER to distinguish a fully
    saturated FIFO (wr_ptr == rd_ptr after wrap) from an empty one
  - Fix active_scan_mask handling: pack only active channels at
    consecutive positions using test_bit(idx, active_scan_mask)
  - Remove IRQF_ONESHOT from IRQ request (not needed for edge-triggered;
    iio_trigger_generic_data_rdy_poll is a hard-IRQ handler)
  - Add set_trigger_state callback to enable/disable A_FULL interrupt
    only when the IIO buffer is active, preventing the interrupt line
    from asserting before the handler is registered
  - Fix endianness: change scan_type.endianness from IIO_LE to IIO_CPU
    to match native integers written directly into the buffer
  - Add max86150_powerdown() devm action to disable interrupts and
    assert SYS_SHDN on driver unload
  - Add devm_regulator_get_enable() for vdd-supply and leds-supply
    before any I2C access
  - Add devm action for iio_trigger_put() to balance the reference
    count increment from iio_trigger_get()
  - Split DT binding into a separate first patch (requested by Joshua Crofts)
  - Add MAINTAINERS entry (requested by Joshua Crofts)

Known limitations (to be addressed in v3):
  - IIO_CHAN_INFO_SCALE not yet implemented
  - Runtime PM (SYS_CTRL SHDN bit) not yet implemented
  - Not yet tested on physical hardware

Md Shofiqul Islam (3):
  dt-bindings: iio: health: add maxim,max86150
  iio: health: add MAX86150 ECG and PPG biosensor driver
  MAINTAINERS: add entry for MAX86150 IIO health driver

 .../bindings/iio/health/maxim,max86150.yaml   |  67 ++
 MAINTAINERS                                   |   7 +
 drivers/iio/health/Kconfig                    |  18 +
 drivers/iio/health/Makefile                   |   1 +
 drivers/iio/health/max86150.c                 | 612 ++++++++++++++++++
 5 files changed, 705 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/health/maxim,max86150.yaml
 create mode 100644 drivers/iio/health/max86150.c

-- 
2.51.1

^ permalink raw reply

* Re: [PATCH 1/8] clk: qcom: dispcc-sm8450: Fix mdss clocks
From: Konrad Dybcio @ 2026-06-23 15:50 UTC (permalink / raw)
  To: esteuwu, Bjorn Andersson, Michael Turquette, Stephen Boyd,
	Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
	Joerg Roedel (AMD), Vinod Koul, Neil Armstrong
  Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
	linux-arm-kernel, linux-phy
In-Reply-To: <20260622-sm8450-qol-v1-1-37e2ee8df9da@proton.me>

On 6/23/26 2:54 AM, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
> 
> Both of these changes allow the framebuffer to show upon boot and let
> the mdss driver take over afterwards.
> Before, none of these actions were possible. Only mdss takeover was
> possible, but screen had to be turned off first.
> 
> OLE configuration may have been a misinterpretation... that's not
> something that's done on the downstream driver.
> 
> Changing disp_cc_mdss_mdp_clk_src from clk_rcg2_shared_ops to
> clk_rcg2_shared_no_init_park_ops fixes this warning as well:

[...]

>  drivers/clk/qcom/dispcc-sm8450.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c
> index 2e91332dd92a..b99d3eb5e195 100644
> --- a/drivers/clk/qcom/dispcc-sm8450.c
> +++ b/drivers/clk/qcom/dispcc-sm8450.c
> @@ -614,7 +614,7 @@ static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
>  		.parent_data = disp_cc_parent_data_5,
>  		.num_parents = ARRAY_SIZE(disp_cc_parent_data_5),
>  		.flags = CLK_SET_RATE_PARENT,
> -		.ops = &clk_rcg2_shared_ops,
> +		.ops = &clk_rcg2_shared_no_init_park_ops,
>  	},
>  };
>  
> @@ -1824,8 +1824,8 @@ static int disp_cc_sm8450_probe(struct platform_device *pdev)
>  		disp_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE];
>  		disp_cc_pll1.clkr.hw.init = &sm8475_disp_cc_pll1_init;
>  
> -		clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &sm8475_disp_cc_pll0_config);
> -		clk_lucid_ole_pll_configure(&disp_cc_pll1, regmap, &sm8475_disp_cc_pll1_config);
> +		clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &sm8475_disp_cc_pll0_config);
> +		clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &sm8475_disp_cc_pll1_config);
>  	} else {
>  		clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
>  		clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config);

This can also be fixed by migrating to use qcom_cc_driver_data,
which takes a list of alpha PLLs to be configured, and thenthere's
a switch-statement in clk-alpha-pll.c that always assigns the 
correct function

Konrad

^ permalink raw reply

* Re: [PATCH 2/13] dt-bindings: sound: Add Qualcomm QAIF binding
From: Konrad Dybcio @ 2026-06-23 15:48 UTC (permalink / raw)
  To: Harendra Gautam
  Cc: Srinivas Kandagatla, Mark Brown, Liam Girdwood, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-sound, linux-arm-msm,
	devicetree, linux-kernel
In-Reply-To: <CAC-tS8CuhED2dvne=cuTBUcrL93WXPjNB-nDUYHWNtFF9oVVjQ@mail.gmail.com>

On 6/23/26 2:26 PM, Harendra Gautam wrote:
> On Tue, Jun 9, 2026 at 3:27 PM Konrad Dybcio
> <konrad.dybcio@oss.qualcomm.com> wrote:
>>
>> On 6/5/26 12:37 PM, Harendra Gautam wrote:
>>> Add a Devicetree binding for the Qualcomm Audio Interface (QAIF) CPU DAI
>>> controller used on the Shikra audio platform.
>>>
>>> QAIF moves PCM data between system memory and external serial audio
>>> interfaces through the AIF path, and between memory and the internal Bolero
>>> digital codec through the CIF path. The controller needs a binding so
>>> platform Devicetree files can describe its MMIO region, DMA IOMMU stream,
>>> clocks, interrupt, DAI cells and per-interface AIF configuration.
>>>
>>> Describe the single register region, one EE interrupt, the required GCC
>>> LPASS and audio core clocks, the DMA IOMMU mapping, and 'aif-interface@N'
>>> child nodes used for static PCM, TDM or MI2S configuration.
>>>
>>> Signed-off-by: Harendra Gautam <harendra.gautam@oss.qualcomm.com>
>>> ---
>>
>> [...]
>>
>>> +  clock-names:
>>> +    items:
>>> +      - const: lpass_config_clk
>>> +      - const: lpass_core_axim_clk
>>> +      - const: aud_dma_clk
>>> +      - const: aud_dma_mem_clk
>>> +      - const: bus_clk
>>> +      - const: aif_if0_ebit_clk
>>> +      - const: aif_if0_ibit_clk
>>> +      - const: aif_if1_ebit_clk
>>> +      - const: aif_if1_ibit_clk
>>> +      - const: aif_if2_ebit_clk
>>> +      - const: aif_if2_ibit_clk
>>> +      - const: aif_if3_ebit_clk
>>> +      - const: aif_if3_ibit_clk
>>> +      - const: ext_mclka_clk
>>> +      - const: ext_mclkb_clk
>>
>> Drop the _clk suffix, we already know they are clocks, as they are
>> listed under the clocks property
> Okay, will correct.
>>
>> [...]
>>
>>> +      qcom,qaif-aif-sync-mode:
>>> +        $ref: /schemas/types.yaml#/definitions/uint32
>>> +        description:
>>> +          Sync mode. Use QAIF_AIF_SYNC_MODE_SHORT (0) for short (pulse)
>>> +          sync or QAIF_AIF_SYNC_MODE_LONG (1) for long (level) sync.
>>> +      qcom,qaif-aif-sync-src:
>>> +        $ref: /schemas/types.yaml#/definitions/uint32
>>> +        description:
>>> +          Sync source. Use QAIF_AIF_SYNC_SRC_SLAVE (0) for slave mode
>>> +          or QAIF_AIF_SYNC_SRC_MASTER (1) for master mode.
>>
>> Should these be boolean flags then?
> It should not be, the intention is to define explicitly, for better
> readability I can rename these flags as EXTERNAL/INTERNAL, Please
> suggest.

Are all 4 combinations of them being present/absent valid on shikra?

Konrad

^ permalink raw reply

* Re: [PATCH 1/7] dt-bindings: rtc: sun6i: Add Allwinner A733 support
From: Chen-Yu Tsai @ 2026-06-23 15:42 UTC (permalink / raw)
  To: Jerome Brunet, Junhui Liu
  Cc: Michael Turquette, Stephen Boyd, Jernej Skrabec, Samuel Holland,
	Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Maxime Ripard, linux-clk, linux-arm-kernel, linux-sunxi,
	linux-kernel, linux-rtc, devicetree
In-Reply-To: <1j1pe7elxm.fsf@starbuckisacylon.baylibre.com>

On Tue, Jun 16, 2026 at 1:46 AM Jerome Brunet <jbrunet@baylibre.com> wrote:
>
> On sam. 28 mars 2026 at 20:37, Chen-Yu Tsai <wens@kernel.org> wrote:
>
> > On Wed, Jan 21, 2026 at 7:03 PM Junhui Liu <junhui.liu@pigmoral.tech> wrote:
> >>
> >> The RTC module in the Allwinner A733 SoC is functionally compatible with
> >> the sun6i RTC, but its internal Clock Control Unit (CCU) has significant
> >> changes.
> >>
> >> The A733 supports selecting the oscillator between three frequencies:
> >> 19.2MHz, 24MHz, and 26MHz. The RTC CCU relies on hardware to detect
> >> which frequency is actually used on the board. By defining all three
> >> frequencies as fixed-clocks in the device tree, the driver can identify
> >> the hardware-detected frequency and expose it to the rest of the system.
> >
> > No. The board device tree shall have the exact and correct frequency
> > defined in the external crystal device node. The operating system can
> > use the hardware-detected frequency to "fix" the in-system representation
> > if it is off.
> >
> >> Additionally, the A733 RTC CCU provides several new DCXO gate clocks for
> >> specific modules, including SerDes, HDMI, and UFS.
> >>
> >> Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
> >> ---
> >>  .../bindings/rtc/allwinner,sun6i-a31-rtc.yaml      | 38 ++++++++++++++++++++--
> >>  include/dt-bindings/clock/sun60i-a733-rtc.h        | 16 +++++++++
> >>  2 files changed, 52 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
> >> index 9df5cdb6f63f..b18431955783 100644
> >> --- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
> >> +++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
> >> @@ -26,6 +26,7 @@ properties:
> >>            - allwinner,sun50i-h6-rtc
> >>            - allwinner,sun50i-h616-rtc
> >>            - allwinner,sun50i-r329-rtc
> >> +          - allwinner,sun60i-a733-rtc
> >>        - items:
> >>            - const: allwinner,sun50i-a64-rtc
> >>            - const: allwinner,sun8i-h3-rtc
> >> @@ -46,11 +47,11 @@ properties:
> >>
> >>    clocks:
> >>      minItems: 1
> >> -    maxItems: 4
> >> +    maxItems: 6
> >>
> >>    clock-names:
> >>      minItems: 1
> >> -    maxItems: 4
> >> +    maxItems: 6
> >>
> >>    clock-output-names:
> >>      minItems: 1
> >> @@ -156,6 +157,38 @@ allOf:
> >>          - clocks
> >>          - clock-names
> >>
> >> +  - if:
> >> +      properties:
> >> +        compatible:
> >> +          contains:
> >> +            const: allwinner,sun60i-a733-rtc
> >> +
> >> +    then:
> >> +      properties:
> >> +        clocks:
> >> +          minItems: 5
> >> +          items:
> >> +            - description: Bus clock for register access
> >
> >> +            - description: 19.2 MHz oscillator
> >> +            - description: 24 MHz oscillator
> >> +            - description: 26 MHz oscillator
> >
> > No. There is only one input. As in there is only one set of pins for the
> > DCXO. The inputs are the same as on R329 / A523. Just use that list.
> >
> >> +            - description: AHB parent for internal SPI clock
> >> +            - description: External 32768 Hz oscillator
> >> +
> >> +        clock-names:
> >> +          minItems: 5
> >> +          items:
> >> +            - const: bus
> >> +            - const: osc19M
> >> +            - const: osc24M
> >> +            - const: osc26M
> >> +            - const: ahb
> >> +            - const: ext-osc32k
> >> +
> >> +      required:
> >> +        - clocks
> >> +        - clock-names
> >> +
> >>    - if:
> >>        properties:
> >>          compatible:
> >> @@ -164,6 +197,7 @@ allOf:
> >>                - allwinner,sun8i-r40-rtc
> >>                - allwinner,sun50i-h616-rtc
> >>                - allwinner,sun50i-r329-rtc
> >> +              - allwinner,sun60i-a733-rtc
> >>
> >>      then:
> >>        properties:
> >> diff --git a/include/dt-bindings/clock/sun60i-a733-rtc.h b/include/dt-bindings/clock/sun60i-a733-rtc.h
> >> new file mode 100644
> >> index 000000000000..8a2b5facad73
> >> --- /dev/null
> >> +++ b/include/dt-bindings/clock/sun60i-a733-rtc.h
> >> @@ -0,0 +1,16 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
> >> +
> >> +#ifndef _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_
> >> +#define _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_
> >> +
> >> +#define CLK_IOSC               0
> >> +#define CLK_OSC32K             1
> >> +#define CLK_HOSC               2
> >
> > The DCXO enable control has been present since at least the H6. We just
> > never added it, as we would never disable it anyway.
> >
> > If you compare the RTC clock trees of the A733 and A523, the only addition
> > besides the new gates seems to be the LOSC auto selection. But even that
> > is just an illusion, as the A523 has the same registers for that.
> >
> > One could say the A733 RTC is almost backward compatible to the A523, if
> > not for the two fastboot registers the A523 has at 0x120 and 0x124.
> >
> > So I ask that you try to integrate the differences into the existing
> > driver and bindings. You can tweak and export internal clks if you
> > need.
>
> I'd like to help with that. I think it is doable but I have a question
> regarding the binding of the existing driver, more precisely their usage
> here:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c?h=v7.1#n370
>
> Clock indexes are supposed to be stable in DT (AFAIK) but with the code
> linked the external 32k is at:
>
> * "ext-32k" - so index 3 - if "clock-names" is present
> * index 0 if clock names is not present
>
> ... but index 0 is supposed to be the bus clock according the binding
> doc, whether "clock-names" is there or not :/
>
> So what are those old r329 bindings ? is there a documentation defining
> them somewhere ?

You can look at

    8487614a8a8a dt-bindings: rtc: sun6i: Add H616, R329, and D1 support

In hindsight maybe the two bindings should be separate. The old SoCs
did not have all these clock inputs from the main clock controller.
The only input it could possibly take was the external 32k crystal.

> Cleaning that part would help with A733 addition in the existing driver
> I think

Yeah. Also, we can treat the bindings and drivers separately. We could
have two bindings but one common driver, or vice versa. As you pointed
out, the bindings are a bit messed up, so we could consider separating
them.

If we end up with separate binding header files, maybe we could use
a different prefix for the new ones so they don't collide? That way
the driver could maybe still be shared?

As for whether to share the headers, I think they should be treated
as part of the binding, so if the bindings are shared, then they can
be shared as well; if the bindings are separate, then they should be
completely separate files as well.


And sorry for the late reply.


Thanks
ChenYu

> >
> >> +#define CLK_RTC_32K            3
> >
> > AFAICT besides being an internal clock, this is also fed to GPIO for
> > debounce? We probably need to expose this on the A523 as well.
> >
> >
> > Thanks
> > ChenYu
> >
> >
> >> +#define CLK_OSC32K_FANOUT      4
> >> +#define CLK_HOSC_SERDES1       5
> >> +#define CLK_HOSC_SERDES0       6
> >> +#define CLK_HOSC_HDMI          7
> >> +#define CLK_HOSC_UFS           8
> >> +
> >> +#endif /* _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_ */
> >>
> >> --
> >> 2.52.0
> >>
> >>
>
> --
> Jerome
>

^ permalink raw reply

* Re: [PATCH 1/8] clk: qcom: dispcc-sm8450: Fix mdss clocks
From: Krzysztof Kozlowski @ 2026-06-23 15:39 UTC (permalink / raw)
  To: esteuwu, Bjorn Andersson, Michael Turquette, Stephen Boyd,
	Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
	Joerg Roedel (AMD), Vinod Koul, Neil Armstrong
  Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
	linux-arm-kernel, linux-phy
In-Reply-To: <20260622-sm8450-qol-v1-1-37e2ee8df9da@proton.me>

On 23/06/2026 02:54, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
> 
> Both of these changes allow the framebuffer to show upon boot and let
> the mdss driver take over afterwards.
> Before, none of these actions were possible. Only mdss takeover was
> possible, but screen had to be turned off first.
> 
> OLE configuration may have been a misinterpretation... that's not
> something that's done on the downstream driver.
> 
> Changing disp_cc_mdss_mdp_clk_src from clk_rcg2_shared_ops to
> clk_rcg2_shared_no_init_park_ops fixes this warning as well:


These should be two separate commits, if I understand correctly.

Please use also Fixes tag.

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH 1/1] iio: health: add MAX86150 ECG and PPG biosensor driver
From: Krzysztof Kozlowski @ 2026-06-23 15:38 UTC (permalink / raw)
  To: Md Shofiqul Islam, linux-iio
  Cc: jic23, dlechner, nuno.sa, robh, krzk+dt, devicetree
In-Reply-To: <20260623140113.12574-2-shofiqtest@gmail.com>

On 23/06/2026 16:01, Md Shofiqul Islam wrote:
> The MAX86150 (Maxim/Analog Devices) integrates two PPG optical channels
> (Red/IR LED) and one ECG biopotential channel in a single I2C device.
> Data is captured via a 32-entry hardware FIFO with a configurable
> almost-full interrupt.
> 
> The driver exposes three IIO channels:
>   - in_intensity_red_raw   (PPG Red, 19-bit unsigned)
>   - in_intensity_ir_raw    (PPG IR, 19-bit unsigned)
>   - in_voltage0_raw        (ECG, 18-bit signed)
> 
> A hardware trigger is registered when an interrupt GPIO is provided in
> the device tree, enabling the IIO triggered buffer path for continuous
> low-overhead capture.
> 
> FIFO reads use regmap_noinc_read() to burst-read 9 bytes (3 slots x
> 3 bytes) from the streaming FIFO_DATA register in a single I2C
> transaction.
> 
> Signed-off-by: Md Shofiqul Islam <shofiqtest@gmail.com>

Please run scripts/checkpatch.pl on the patches and fix reported
warnings. After that, run also 'scripts/checkpatch.pl --strict' on the
patches and (probably) fix more warnings. Some warnings can be ignored,
especially from --strict run, but the code here looks like it needs a
fix. Feel free to get in touch if the warning is not clear.

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH 3/4] arm64: dts: allwinner: add Allwinner A733 SoC
From: Jerome Brunet @ 2026-06-23 15:35 UTC (permalink / raw)
  To: Enzo Adriano via B4 Relay
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
	Jernej Skrabec, Samuel Holland, Maxime Ripard, Ulf Hansson,
	enzo.adriano.code, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, linux-mmc
In-Reply-To: <20260613-a733-dts-v1-public-ready-v1-3-7787c94681db@gmail.com>

On sam. 13 juin 2026 at 05:42, Enzo Adriano via B4 Relay <devnull+enzo.adriano.code.gmail.com@kernel.org> wrote:

> From: Enzo Adriano <enzo.adriano.code@gmail.com>
>
> Add the initial A733 SoC description with CPUs, timers, interrupt
> controller, clocks, pinctrl, UART0, and MMC0.
>
> Keep peripherals disabled by default. Board DTS files can enable only the
> devices that are proven on their hardware.
>
> Signed-off-by: Enzo Adriano <enzo.adriano.code@gmail.com>
> ---
>  arch/arm64/boot/dts/allwinner/sun60i-a733.dtsi | 198 +++++++++++++++++++++++++
>  1 file changed, 198 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/allwinner/sun60i-a733.dtsi b/arch/arm64/boot/dts/allwinner/sun60i-a733.dtsi
> new file mode 100644
> index 000000000000..3721aa9e8573
> --- /dev/null
> +++ b/arch/arm64/boot/dts/allwinner/sun60i-a733.dtsi
> @@ -0,0 +1,198 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/clock/sun60i-a733-ccu.h>
> +#include <dt-bindings/reset/sun60i-a733-ccu.h>
> +
> +/ {
> +	interrupt-parent = <&gic>;
> +	#address-cells = <2>;
> +	#size-cells = <2>;
> +
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		cpu0: cpu@0 {
> +			compatible = "arm,cortex-a55";
> +			device_type = "cpu";
> +			reg = <0x000>;
> +			enable-method = "psci";
> +			capacity-dmips-mhz = <530>;
> +		};
> +
> +		cpu1: cpu@100 {
> +			compatible = "arm,cortex-a55";
> +			device_type = "cpu";
> +			reg = <0x100>;
> +			enable-method = "psci";
> +			capacity-dmips-mhz = <530>;
> +		};
> +
> +		cpu2: cpu@200 {
> +			compatible = "arm,cortex-a55";
> +			device_type = "cpu";
> +			reg = <0x200>;
> +			enable-method = "psci";
> +			capacity-dmips-mhz = <530>;
> +		};
> +
> +		cpu3: cpu@300 {
> +			compatible = "arm,cortex-a55";
> +			device_type = "cpu";
> +			reg = <0x300>;
> +			enable-method = "psci";
> +			capacity-dmips-mhz = <530>;
> +		};
> +
> +		cpu4: cpu@400 {
> +			compatible = "arm,cortex-a55";
> +			device_type = "cpu";
> +			reg = <0x400>;
> +			enable-method = "psci";
> +			capacity-dmips-mhz = <530>;
> +		};
> +
> +		cpu5: cpu@500 {
> +			compatible = "arm,cortex-a55";
> +			device_type = "cpu";
> +			reg = <0x500>;
> +			enable-method = "psci";
> +			capacity-dmips-mhz = <530>;
> +		};
> +
> +		cpu6: cpu@600 {
> +			compatible = "arm,cortex-a76";
> +			device_type = "cpu";
> +			reg = <0x600>;
> +			enable-method = "psci";
> +			capacity-dmips-mhz = <1024>;
> +		};
> +
> +		cpu7: cpu@700 {
> +			compatible = "arm,cortex-a76";
> +			device_type = "cpu";
> +			reg = <0x700>;
> +			enable-method = "psci";
> +			capacity-dmips-mhz = <1024>;
> +		};
> +	};
> +
> +	osc24M: osc24M-clk {

Note A733 supports 19.2MHz, 24MHz and 26MHz xtals apparently.
The A7S and A7A do have a 26MHz xtal according to the schematics.

While this might be fine in the SoC dtsi, your are missing something in
your board dts to change the xtal rate, at least.

Also the node and clock name are a bit misleading now.

> +		#clock-cells = <0>;
> +		compatible = "fixed-clock";
> +		clock-frequency = <24000000>;
> +		clock-output-names = "osc24M";
> +	};
> +
> +	osc32k: osc32k-clk {
> +		#clock-cells = <0>;
> +		compatible = "fixed-clock";
> +		clock-frequency = <32768>;
> +		clock-output-names = "osc32k";

I think this is the ext32k supposed to feed the rtc ccu ...

> +	};
> +
> +	iosc: internal-osc-clk {
> +		#clock-cells = <0>;
> +		compatible = "fixed-clock";
> +		clock-frequency = <16000000>;
> +		clock-output-names = "iosc";
> +	};
> +
> +	psci {
> +		compatible = "arm,psci-1.0", "arm,psci-0.2";
> +		method = "smc";
> +	};
> +
> +	timer {
> +		compatible = "arm,armv8-timer";
> +		arm,no-tick-in-suspend;
> +		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>,
> +			     <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH>,
> +			     <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>,
> +			     <GIC_PPI 10 IRQ_TYPE_LEVEL_HIGH>;
> +	};
> +
> +	soc {
> +		compatible = "simple-bus";
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges = <0x0 0x0 0x0 0x40000000>;
> +
> +		pio: pinctrl@2000000 {
> +			compatible = "allwinner,sun60i-a733-pinctrl";
> +			reg = <0x02000000 0x600>;
> +			interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&ccu CLK_APB1>, <&osc24M>, <&osc32k>;
> +			clock-names = "apb", "hosc", "losc";
> +			gpio-controller;
> +			#gpio-cells = <3>;
> +			interrupt-controller;
> +			#interrupt-cells = <3>;
> +
> +			mmc0_pins: mmc0-pins {
> +				pins = "PF0", "PF1", "PF2",
> +				       "PF3", "PF4", "PF5";
> +				function = "mmc0";
> +				drive-strength = <30>;
> +				bias-pull-up;
> +			};
> +		};
> +
> +		ccu: clock-controller@2002000 {
> +			compatible = "allwinner,sun60i-a733-ccu";
> +			reg = <0x02002000 0x2000>;
> +			clocks = <&osc24M>, <&osc32k>, <&iosc>;
                                                ^
... not directly the main CCU.

> +			clock-names = "hosc", "losc", "iosc";
> +			#clock-cells = <1>;
> +			#reset-cells = <1>;
> +		};
> +
> +		uart0: serial@2500000 {
> +			compatible = "snps,dw-apb-uart";
> +			reg = <0x02500000 0x400>;
> +			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
> +			reg-shift = <2>;
> +			reg-io-width = <4>;
> +			clocks = <&ccu CLK_BUS_UART0>;
> +			resets = <&ccu RST_BUS_UART0>;
> +			status = "disabled";
> +		};
> +
> +		gic: interrupt-controller@3400000 {
> +			compatible = "arm,gic-v3";
> +			#interrupt-cells = <3>;
> +			interrupt-controller;
> +			reg = <0x03400000 0x10000>,
> +			      <0x03460000 0x100000>;
> +		};
> +
> +		mmc0: mmc@4020000 {
> +			compatible = "allwinner,sun60i-a733-mmc",
> +				     "allwinner,sun20i-d1-mmc";
> +			reg = <0x04020000 0x1000>;
> +			interrupts = <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
> +			clock-names = "ahb", "mmc";
> +			resets = <&ccu RST_BUS_MMC0>;
> +			reset-names = "ahb";
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&mmc0_pins>;
> +			max-frequency = <200000000>;
> +			cap-sd-highspeed;
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +	};
> +};

-- 
Jerome

^ permalink raw reply

* Re: [PATCH 7/7] clk: sunxi-ng: Add Allwinner A733 RTC CCU support
From: Chen-Yu Tsai @ 2026-06-23 15:23 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: Junhui Liu, Michael Turquette, Stephen Boyd, Jernej Skrabec,
	Samuel Holland, Alexandre Belloni, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Maxime Ripard, linux-clk,
	linux-arm-kernel, linux-sunxi, linux-kernel, linux-rtc,
	devicetree, André Przywara
In-Reply-To: <1jv7bjd6wi.fsf@starbuckisacylon.baylibre.com>

On Tue, Jun 16, 2026 at 1:56 AM Jerome Brunet <jbrunet@baylibre.com> wrote:
>
> On sam. 28 mars 2026 at 22:41, Chen-Yu Tsai <wens@kernel.org> wrote:
>
> > On Wed, Jan 21, 2026 at 7:04 PM Junhui Liu <junhui.liu@pigmoral.tech> wrote:
> >>
> >> Add support for the internal CCU found in the RTC module of the Allwinner
> >> A733 SoC. While the basic 16MHz (IOSC) and 32kHz logic remains compatible
> >> with older SoCs like the sun6i, the A733 introduces several new features.
> >>
> >> The A733 RTC CCU supports choosing one of three external crystal
> >> frequencies: 19.2MHz, 24MHz, and 26MHz. It features hardware detection
> >> logic to automatically identify the frequency used on the board and
> >> exports this DCXO signal as the "hosc" clock.
> >>
> >> Furthermore, the driver implements logic to derive a 32kHz reference
> >> from the HOSC. This is achieved through a muxed clock path using fixed
> >> pre-dividers to normalize the different crystal frequencies to ~32kHz.
> >
> > Have you tested whether the actually normalizes the frequency, i.e.
> > selects a different divider based on the DCXO frequency? Otherwise
> > we're just lying about the frequency.
> >
> >> This path reuses the same hardware mux registers as the HOSC clock.
> >>
> >> Additionally, this CCU provides several gate clocks for specific
> >> peripherals, including SerDes, HDMI, and UFS. The driver is implemented
> >> as an auxiliary driver to be bound to the sun6i-rtc driver.
> >>
> >> Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
> >> ---
>
> [...]
>
> >> +};
> >> +
> >> +static const struct clk_parent_data hosc_parents[] = {
> >> +       { .fw_name = "osc24M" },
> >> +       { .fw_name = "osc19M" },
> >> +       { .fw_name = "osc26M" },
> >> +       { .fw_name = "osc24M" },
> >> +};
> >
> > As mentioned in my reply to the binding, this is wrong. There is only
> > one input.
> >
> > The most you can do is check the rate of the parent clock against the
> > detected one, and _scream_ that the DT is wrong. And maybe override
> > the reported frequency.
> >
> > If you want to do the latter, you could add a new fixed rate gated
> > clock type to our library. You would fill in the rate before the
> > clocks get registered. I probably wouldn't go that far. We want people
> > to have correct hardware descriptions.
> >
> > Funnily enough Allwinner's BSP actually implements a fixed rate gate
> > for the next 24M-to-32k divider clock.
>
> What about implementing the register bellow as a read-only (and
> non-cached) divider using the factors provided by Junhui ? That would be
> an accurate description of the HW I think.
>
> The oscillator gets set in DT and if the output reported past the
> divider is not 32728Hz, you know you've got a problem (bad DT or HW gone
> bad)
>
> With a fixed-rate gate, you may actually end up lying about what
> actually happen, if the HW does not behave as expected.
>
> Do you prefer a fixed-rate gate still or should I try the RO divider
> approach ?

I think either one would work. The RO divider is probably more accurate.

Sorry for the late reply.


ChenYu

^ permalink raw reply

* Re: [PATCH V13 8/9] iio: imu: inv_icm42607: Add Gyroscope to icm42607
From: Jonathan Cameron @ 2026-06-23 15:15 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Chris Morgan, Chris Morgan, linux-iio, andy, nuno.sa, dlechner,
	jean-baptiste.maneyrol, linux-rockchip, devicetree, heiko,
	conor+dt, krzk+dt, robh
In-Reply-To: <ajotNPhg8fR3tLZp@ashevche-desk.local>

On Tue, 23 Jun 2026 09:52:36 +0300
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:

> On Wed, Jun 17, 2026 at 04:10:49PM -0500, Chris Morgan wrote:
> > On Tue, Jun 16, 2026 at 01:13:03PM +0300, Andy Shevchenko wrote:  
> > > On Mon, Jun 15, 2026 at 12:25:51PM -0500, Chris Morgan wrote:  
> 
> ...
> 
> > > Can be some of the code deduplicated between gyro and accel?  
> > 
> > Probably a fair amount, but the deduplication will likely need to be
> > undone somewhat if we get buffer, WoM or apex support added back
> > (I don't have any devices with such functionality, so if anyone will
> > do it then it won't be me). I can refactor more if you want, or we
> > can keep it split like this to make it easy if someone else wants to
> > tackle the buffers/IRQs stuff later? Your call.  
> 
> Just asking. Jonathan, David, Nuno, what's your opinion on this?
> Personal opinion is to avoid solving the issues that do not exist.
> If you are not committing into those features, let's not prepare
> driver for them right now.
> 
Agreed.  My only exception to this is normally when someone tells
me they have the code and plan to post a follow up set very shortly.
Then I get a bit more relaxed as they chances of 'preparing' for the
future being relevant become much higher!

Jonathan

^ permalink raw reply

* Re: [PATCH v3 1/2] dt-bindings: iio: dac: Add AD5529R
From: Jonathan Cameron @ 2026-06-23 15:08 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Nuno Sá, Rodrigo Alencar, Janani Sunil, Janani Sunil,
	Lars-Peter Clausen, Michael Hennerich, David Lechner,
	Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
	linux-iio, devicetree, linux-kernel, linux-doc, Mark Brown
In-Reply-To: <20260622-captive-tux-067efd31ceac@spud>

On Mon, 22 Jun 2026 19:39:43 +0100
Conor Dooley <conor@kernel.org> wrote:

> On Mon, Jun 22, 2026 at 05:29:11PM +0100, Jonathan Cameron wrote:
> > > > > Yeah. It's not clear to me how that works for the microchip devices
> > > > > (I suspect it doesn't!)
> > > > > 
> > > > > Just thinking as I type, but could we do something a bit nasty with
> > > > > a gpio mux that doesn't actually switch but represents the GPIO being
> > > > > shared?  Given this is all tied to the spi bus that should all happen
> > > > > under serializing locks. 
> > > > > 
> > > > > Agreed though that this would be nicer as an SPI thing that let
> > > > > us specify that a single CS is share by multiple devices and their
> > > > > is some other signal acting to select which one we are talking to.
> > > > >     
> > > > 
> > > > If the device-addressing on the same chip-select is to be handled
> > > > by the spi framework, wouldn't we lose device-specific features?
> > > > 
> > > > I understand that this multi-device feature is there mostly to extend the
> > > > channel count from 16 to 32, 48 or 64. I suppose the command:
> > > > 
> > > > 	"MULTI DEVICE SW LDAC MODE"
> > > > 
> > > > exists so that software can update channel values accross multiple devices.    
> > > 
> > > Right! You do have a point! I agree the main driver for a feature like
> > > this is likely to extend the channel count and effectively "aggregate"
> > > devices.
> > > 
> > > But I would say that even with the spi solution the MULTI DEVICE stuff
> > > should be doable (as we still need a sort of adi,pin-id property). 
> > > 
> > > But yes, I do feel that the whole feature is for aggregation so seeing
> > > one device with 32 channels is the expectation here? Rather than seeing
> > > two devices with 16 channels.  
> > 
> > Agreed - if we have messages that address both devices at once that needs
> > to be a unified driver and given they are about triggering simultaneous
> > update of all channels it needs to look like one big device.
> > This ends up similar to how we handle daisy chain devices.
> > 
> > The question of what to do on devices that don't have this feature
> > is rather different. Good thing you read the datasheet :)  
> 
> I'm not sure it really is, the intent for the microchip devices I think
> is pretty similar. The mcp3911 datasheet cites three-phase power
> metering using three devices as a typical use-case, for example.
> Probably creating an amalgamated device is a good fit there too?
> 
> I assume an amalgamated device for this ADI product means per-channel ID
> properties?

Per device as they are 8 channel each, but effectively the same.
(microchip devices are 2 channels each I think)

> If so, I think they should be made generic and the Microchip
> products retrofitted to use them, with a fallback to the proprietary
> property. Not going to ask for the support for multiple devices in those
> drivers, since the current way doesn't work and there'd be no loss of
> support. Someone from Microchip can do that. The proprietary property
> to generic conversion should be straightforward and provides weight to
> an argument for this being generic, since that'd be three devices that
> can all share?

I think the practical difference is that for the ADI part we have to support
it as a single device as some commands effectively don't use the address
bits in the message.  For the microchip ones we could register multiple
separate SPI devices and just provide one address for each.

Equally we could treat the microchip ones as a unified device in which case
the binding will be the same and there will be a property with a bunch
of addresses (one for each device present). I'm fine with this option given
as you say the datasheet calls out using this for channel expansion.

Jonathan




^ permalink raw reply

* Re: [PATCH v3 1/2] dt-bindings: iio: dac: Add AD5529R
From: Jonathan Cameron @ 2026-06-23 14:57 UTC (permalink / raw)
  To: Rodrigo Alencar
  Cc: Nuno Sá, Conor Dooley, Janani Sunil, Janani Sunil,
	Lars-Peter Clausen, Michael Hennerich, David Lechner,
	Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
	linux-iio, devicetree, linux-kernel, linux-doc, Mark Brown
In-Reply-To: <5guhkvoxhkzevjm4b45hhk3772akpnz3givr3gb56x5ywamzyf@oiycreun4y62>

On Tue, 23 Jun 2026 09:09:14 +0100
Rodrigo Alencar <455.rodrigo.alencar@gmail.com> wrote:

> On 22/06/26 13:20, Nuno Sá wrote:
> > On Mon, Jun 22, 2026 at 12:51:20PM +0100, Rodrigo Alencar wrote:  
> > > On 22/06/26 11:29, Nuno Sá wrote:  
> > > > On Mon, Jun 22, 2026 at 10:24:05AM +0100, Rodrigo Alencar wrote:  
> > > > > On 21/06/26 15:33, Jonathan Cameron wrote:  
> > > > > > On Fri, 19 Jun 2026 16:54:11 +0100
> > > > > > Nuno Sá <noname.nuno@gmail.com> wrote:
> > > > > >   
> > > > > > > On Fri, Jun 19, 2026 at 03:12:07PM +0100, Conor Dooley wrote:  
> > > > > > > > On Fri, Jun 19, 2026 at 02:01:08PM +0100, Nuno Sá wrote:    
> > > > > > > > > On Fri, Jun 19, 2026 at 12:40:54PM +0100, Conor Dooley wrote:    
> > > > > > > > > > On Fri, Jun 19, 2026 at 12:36:55PM +0100, Conor Dooley wrote:    
> > > > > > > > > > > On Fri, Jun 19, 2026 at 12:33:11PM +0200, Janani Sunil wrote:    
> > > > > > > > > > > > 
> > > > > > > > > > > > On 6/14/26 21:44, Jonathan Cameron wrote:    
> > > > > > > > > > > > > On Tue, 9 Jun 2026 16:47:23 +0200
> > > > > > > > > > > > > Janani Sunil <jan.sun97@gmail.com> wrote:
> > > > > > > > > > > > >     
> > > > > > > > > > > > > > On 5/26/26 15:11, Rodrigo Alencar wrote:    
> > > > > > > > > > > > > > > On 26/05/19 05:42PM, Janani Sunil wrote:    
> > > > > > > > > > > > > > > > Devicetree bindings for AD5529R 16 channel 12/16 bit high voltage,
> > > > > > > > > > > > > > > > buffered voltage output digital-to-analog converter (DAC) with an
> > > > > > > > > > > > > > > > integrated precision reference.    
> > > > > > > > > > > > > > > ...
> > > > > > > > > > > > > > > Probably others may comment on that, but...
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > This parent node may support device addressing for multi-device support through
> > > > > > > > > > > > > > > those ID pins. I suppose that each device may have its own power supplies or
> > > > > > > > > > > > > > > other resources like the toggle pins or reset and enable.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > That way I suppose that an example would look like...    
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +patternProperties:
> > > > > > > > > > > > > > > > +  "^channel@([0-9]|1[0-5])$":
> > > > > > > > > > > > > > > > +    type: object
> > > > > > > > > > > > > > > > +    description: Child nodes for individual channel configuration
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +    properties:
> > > > > > > > > > > > > > > > +      reg:
> > > > > > > > > > > > > > > > +        description: Channel number.
> > > > > > > > > > > > > > > > +        minimum: 0
> > > > > > > > > > > > > > > > +        maximum: 15
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +      adi,output-range-microvolt:
> > > > > > > > > > > > > > > > +        description: |
> > > > > > > > > > > > > > > > +          Output voltage range for this channel as [min, max] in microvolts.
> > > > > > > > > > > > > > > > +          If not specified, defaults to 0V to 5V range.
> > > > > > > > > > > > > > > > +        oneOf:
> > > > > > > > > > > > > > > > +          - items:
> > > > > > > > > > > > > > > > +              - const: 0
> > > > > > > > > > > > > > > > +              - enum: [5000000, 10000000, 20000000, 40000000]
> > > > > > > > > > > > > > > > +          - items:
> > > > > > > > > > > > > > > > +              - const: -5000000
> > > > > > > > > > > > > > > > +              - const: 5000000
> > > > > > > > > > > > > > > > +          - items:
> > > > > > > > > > > > > > > > +              - const: -10000000
> > > > > > > > > > > > > > > > +              - const: 10000000
> > > > > > > > > > > > > > > > +          - items:
> > > > > > > > > > > > > > > > +              - const: -15000000
> > > > > > > > > > > > > > > > +              - const: 15000000
> > > > > > > > > > > > > > > > +          - items:
> > > > > > > > > > > > > > > > +              - const: -20000000
> > > > > > > > > > > > > > > > +              - const: 20000000
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +    required:
> > > > > > > > > > > > > > > > +      - reg
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +    additionalProperties: false
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +required:
> > > > > > > > > > > > > > > > +  - compatible
> > > > > > > > > > > > > > > > +  - reg
> > > > > > > > > > > > > > > > +  - vdd-supply
> > > > > > > > > > > > > > > > +  - avdd-supply
> > > > > > > > > > > > > > > > +  - hvdd-supply
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +dependencies:
> > > > > > > > > > > > > > > > +  spi-cpha: [ spi-cpol ]
> > > > > > > > > > > > > > > > +  spi-cpol: [ spi-cpha ]
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +allOf:
> > > > > > > > > > > > > > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +unevaluatedProperties: false
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +examples:
> > > > > > > > > > > > > > > > +  - |
> > > > > > > > > > > > > > > > +    #include <dt-bindings/gpio/gpio.h>
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +    spi {
> > > > > > > > > > > > > > > > +        #address-cells = <1>;
> > > > > > > > > > > > > > > > +        #size-cells = <0>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +        dac@0 {
> > > > > > > > > > > > > > > > +            compatible = "adi,ad5529r-16";
> > > > > > > > > > > > > > > > +            reg = <0>;
> > > > > > > > > > > > > > > > +            spi-max-frequency = <25000000>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +            vdd-supply = <&vdd_regulator>;
> > > > > > > > > > > > > > > > +            avdd-supply = <&avdd_regulator>;
> > > > > > > > > > > > > > > > +            hvdd-supply = <&hvdd_regulator>;
> > > > > > > > > > > > > > > > +            hvss-supply = <&hvss_regulator>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +            reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +            #address-cells = <1>;
> > > > > > > > > > > > > > > > +            #size-cells = <0>;
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +            channel@0 {
> > > > > > > > > > > > > > > > +                reg = <0>;
> > > > > > > > > > > > > > > > +                adi,output-range-microvolt = <0 5000000>;
> > > > > > > > > > > > > > > > +            };
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +            channel@1 {
> > > > > > > > > > > > > > > > +                reg = <1>;
> > > > > > > > > > > > > > > > +                adi,output-range-microvolt = <(-10000000) 10000000>;
> > > > > > > > > > > > > > > > +            };
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +            channel@2 {
> > > > > > > > > > > > > > > > +                reg = <2>;
> > > > > > > > > > > > > > > > +                adi,output-range-microvolt = <0 40000000>;
> > > > > > > > > > > > > > > > +            };
> > > > > > > > > > > > > > > > +        };
> > > > > > > > > > > > > > > > +    };    
> > > > > > > > > > > > > > > ...
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 	spi {
> > > > > > > > > > > > > > > 		#address-cells = <1>;
> > > > > > > > > > > > > > > 		#size-cells = <0>;
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 		multi-dac@0 {
> > > > > > > > > > > > > > > 			compatible = "adi,ad5529r-16";
> > > > > > > > > > > > > > > 			reg = <0>;
> > > > > > > > > > > > > > > 			spi-max-frequency = <25000000>;
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 			#address-cells = <1>;
> > > > > > > > > > > > > > > 			#size-cells = <0>;
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 			dac@0 {
> > > > > > > > > > > > > > > 				reg = <0>;
> > > > > > > > > > > > > > > 				vdd-supply = <&vdd_regulator>;
> > > > > > > > > > > > > > > 				avdd-supply = <&avdd_regulator>;
> > > > > > > > > > > > > > > 				hvdd-supply = <&hvdd_regulator>;
> > > > > > > > > > > > > > > 				hvss-supply = <&hvss_regulator>;
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 				reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 				#address-cells = <1>;
> > > > > > > > > > > > > > > 				#size-cells = <0>;
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 				channel@0 {
> > > > > > > > > > > > > > > 					reg = <0>;
> > > > > > > > > > > > > > > 					adi,output-range-microvolt = <0 5000000>;
> > > > > > > > > > > > > > > 				};
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 				channel@1 {
> > > > > > > > > > > > > > > 					reg = <1>;
> > > > > > > > > > > > > > > 					adi,output-range-microvolt = <(-10000000) 10000000>;
> > > > > > > > > > > > > > > 				};
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 				channel@2 {
> > > > > > > > > > > > > > > 					reg = <2>;
> > > > > > > > > > > > > > > 					adi,output-range-microvolt = <0 40000000>;
> > > > > > > > > > > > > > > 				};
> > > > > > > > > > > > > > > 			}
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 			dac@1 {
> > > > > > > > > > > > > > > 				reg = <1>;
> > > > > > > > > > > > > > > 				vdd-supply = <&vdd_regulator>;
> > > > > > > > > > > > > > > 				avdd-supply = <&avdd_regulator>;
> > > > > > > > > > > > > > > 				hvdd-supply = <&hvdd_regulator>;
> > > > > > > > > > > > > > > 				hvss-supply = <&hvss_regulator>;
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 				reset-gpios = <&gpio0 88 GPIO_ACTIVE_LOW>;
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 				#address-cells = <1>;
> > > > > > > > > > > > > > > 				#size-cells = <0>;
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 				channel@0 {
> > > > > > > > > > > > > > > 					reg = <0>;
> > > > > > > > > > > > > > > 					adi,output-range-microvolt = <0 5000000>;
> > > > > > > > > > > > > > > 				};
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 				channel@1 {
> > > > > > > > > > > > > > > 					reg = <1>;
> > > > > > > > > > > > > > > 					adi,output-range-microvolt = <(-10000000) 10000000>;
> > > > > > > > > > > > > > > 				};
> > > > > > > > > > > > > > > 			}
> > > > > > > > > > > > > > > 		};
> > > > > > > > > > > > > > > 	};
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > then you might need something like:
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 	patternProperties:
> > > > > > > > > > > > > > > 		"^dac@[0-3]$":
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > and put most of the things under this node pattern.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > So the main driver that you're putting together might need to handle up to four instances.
> > > > > > > > > > > > > > > Even if your current driver cannot handle this, the dt-bindings might need cover that.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Need to double check if each dac node needs a separate compatible, so you would maybe populate
> > > > > > > > > > > > > > > a platform data to be shared with the child nodes, which would be a separate driver.
> > > > > > > > > > > > > > > (not sure if it would make sense to mix and match ad5529r-16 and ad5529r-12).    
> > > > > > > > > > > > > > Hi Rodrigo,
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Thank you for looking at this.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > For now, I would prefer to keep the binding scoped to a single AD5529R device instance. The current
> > > > > > > > > > > > > > hardware/use case we have only needs one device node and the driver is written around that model as well.
> > > > > > > > > > > > > > While the device addressing pins could allow multi-device topology, we do not have an actual platform using
> > > > > > > > > > > > > > that configuration at the moment, so I would prefer not to introduce an extra parent/child binding structure
> > > > > > > > > > > > > > speculatively without a validating use case.    
> > > > > > > > > > > > > Interesting feature - kind of similar to address control on a typical i2c bus device, or
> > > > > > > > > > > > > looking at it another way a kind of distributed SPI mux.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Challenge of a binding is we need to anticipate the future.  So I think we do need something
> > > > > > > > > > > > > like Rodrigo is suggesting even if we only (for now) support a single instance in the driver.
> > > > > > > > > > > > > That would leave the path open to supporting the addressing at a later date.
> > > > > > > > > > > > > An alternative might be to look at it like a chained device setup. In those we pretend there
> > > > > > > > > > > > > is just one device with a lot of channels etc.  The snag is that here things are more loosely
> > > > > > > > > > > > > coupled whereas for those devices it tends to be you have to read / write the same register
> > > > > > > > > > > > > in all devices in the chain as one big SPI message.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > +CC Mark Brown as he may know of some precedence for this feature. For his reference..
> > > > > > > > > > > > > - Each of these device has 2 ID pins.  The SPI transfers have to contain the 2 bit
> > > > > > > > > > > > > value that matches that or they are ignored.  Thus a single bus + 1 chip select can
> > > > > > > > > > > > > be used to talk to 4 devices.  Question is what that looks like in device tree + I guess
> > > > > > > > > > > > > longer term how to support it cleanly in SPI.    
> > > > > > > > > > > 
> > > > > > > > > > > I'd swear I have seen this before, from some Microchip devices. Let me
> > > > > > > > > > > see if I can find what I am thinking of...    
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > microchip,mcp3911 and microchip,mcp3564 both seem to do this with
> > > > > > > > > > slightly different properties.
> > > > > > > > > > 
> > > > > > > > > >   microchip,device-addr:
> > > > > > > > > >     description: Device address when multiple MCP3911 chips are present on the same SPI bus.
> > > > > > > > > >     $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > > >     enum: [0, 1, 2, 3]
> > > > > > > > > >     default: 0
> > > > > > > > > > 
> > > > > > > > > > and
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > >   microchip,hw-device-address:
> > > > > > > > > >     $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > > >     minimum: 0
> > > > > > > > > >     maximum: 3
> > > > > > > > > >     description:
> > > > > > > > > >       The address is set on a per-device basis by fuses in the factory,
> > > > > > > > > >       configured on request. If not requested, the fuses are set for 0x1.
> > > > > > > > > >       The device address is part of the device markings to avoid
> > > > > > > > > >       potential confusion. This address is coded on two bits, so four possible
> > > > > > > > > >       addresses are available when multiple devices are present on the same
> > > > > > > > > >       SPI bus with only one Chip Select line for all devices.
> > > > > > > > > >       Each device communication starts by a CS falling edge, followed by the
> > > > > > > > > >       clocking of the device address (BITS[7:6] - top two bits of COMMAND BYTE
> > > > > > > > > >       which is first one on the wire).
> > > > > > > > > > 
> > > > > > > > > > This sounds exactly like the sort of feature that you're dealing with
> > > > > > > > > > here?
> > > > > > > > > >     
> > > > > > > > > 
> > > > > > > > > The core idea yes but for this chip, things are a bit more annoying (but
> > > > > > > > > Janani can correct me if I'm wrong). Here, each device can, in theory,
> > > > > > > > > have it's own supplies, pins and at the very least, channels with maybe
> > > > > > > > > different scales. That is why Janani is proposing dac nodes. Given I
> > > > > > > > > honestly don't like much of that "adi,ad5529r-bus" compatible I wondered
> > > > > > > > > about solving this at the spi level.
> > > > > > > > > 
> > > > > > > > > Ah and to make it more annoying, we can also mix 12 and 16 bits variants
> > > > > > > > > together in the same bus.    
> > > > > > > > 
> > > > > > > > I'm definitely missing something, because that property for the
> > > > > > > > microchip devices is not impacted what else is on the bus. AFAICT, you
> > > > > > > > could have an mcp3911 and an mcp3564 on the same bus even though both
> > > > > > > > are completely different devices with different drivers. They have
> > > > > > > > individual device nodes and their own supplies etc etc. These aren't
> > > > > > > > per-channel properties on an adc or dac, they're per child device on a
> > > > > > > > spi bus.    
> > > > > > > 
> > > > > > > Maybe I'm the one missing something :). IIRC, spi would not allow two
> > > > > > > devices on the same CS right? Because for this chip we would need
> > > > > > > something like:
> > > > > > > 
> > > > > > > spi {
> > > > > > > 	dac@0 {
> > > > > > > 		reg = <0>;
> > > > > > > 		adi,pin-id = <0>;
> > > > > > > 	};
> > > > > > > 
> > > > > > > 	dac@1 {
> > > > > > > 		reg = <0>; // which seems already problematic?
> > > > > > > 		adi,pin-id <1>;
> > > > > > > 	};
> > > > > > > 
> > > > > > > 	...
> > > > > > > 
> > > > > > > 	//up to 4
> > > > > > > };  
> > > > > > Yeah. It's not clear to me how that works for the microchip devices
> > > > > > (I suspect it doesn't!)
> > > > > > 
> > > > > > Just thinking as I type, but could we do something a bit nasty with
> > > > > > a gpio mux that doesn't actually switch but represents the GPIO being
> > > > > > shared?  Given this is all tied to the spi bus that should all happen
> > > > > > under serializing locks. 
> > > > > > 
> > > > > > Agreed though that this would be nicer as an SPI thing that let
> > > > > > us specify that a single CS is share by multiple devices and their
> > > > > > is some other signal acting to select which one we are talking to.
> > > > > >   
> > > > > 
> > > > > If the device-addressing on the same chip-select is to be handled
> > > > > by the spi framework, wouldn't we lose device-specific features?
> > > > > 
> > > > > I understand that this multi-device feature is there mostly to extend the
> > > > > channel count from 16 to 32, 48 or 64. I suppose the command:
> > > > > 
> > > > > 	"MULTI DEVICE SW LDAC MODE"
> > > > > 
> > > > > exists so that software can update channel values accross multiple devices.  
> > > > 
> > > > Right! You do have a point! I agree the main driver for a feature like
> > > > this is likely to extend the channel count and effectively "aggregate"
> > > > devices.
> > > > 
> > > > But I would say that even with the spi solution the MULTI DEVICE stuff
> > > > should be doable (as we still need a sort of adi,pin-id property).   
> > > 
> > > I don't think we can have something like an IIO buffer shared by multiple
> > > devices. Synchronizing separate devices would be doable with proper hardware
> > > support for this (probably involving an FGPA).  
> > 
> > True!
> >   
> > >    
> > > > But yes, I do feel that the whole feature is for aggregation so seeing
> > > > one device with 32 channels is the expectation here? Rather than seeing
> > > > two devices with 16 channels.  
> > > 
> > > Yes, I think aggregation is the whole point there... so that the IIO driver
> > > is multi-device-aware.  
> > 
> > Which makes me feel that different pins per device might be possible
> > from an HW point of view but does not make much sense. For example, for
> > the buffer example I would expect LDAC to be shared between all the
> > devices.  
> 
> That is why I would still suggest the multi-dac node in the middle...
> the parent node can hold shared resources, while the dac children can
> have their own, overriding or inheriting stuff.
> 
Before going down that path I'd want confirmation this is something we
actually think anyone will build.

Jonathan



^ permalink raw reply

* Re: [PATCH v3 1/2] dt-bindings: iio: dac: Add AD5529R
From: Jonathan Cameron @ 2026-06-23 14:55 UTC (permalink / raw)
  To: Janani Sunil
  Cc: David Lechner, Nuno Sá, Rodrigo Alencar, Conor Dooley,
	Janani Sunil, Lars-Peter Clausen, Michael Hennerich, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Philipp Zabel, Jonathan Corbet, Shuah Khan, linux-iio, devicetree,
	linux-kernel, linux-doc, Mark Brown
In-Reply-To: <0f778d06-726f-4aec-ab3b-f6e091cc9421@gmail.com>

On Tue, 23 Jun 2026 12:07:52 +0200
Janani Sunil <jan.sun97@gmail.com> wrote:

> On 6/22/26 17:36, David Lechner wrote:
> > On 6/22/26 7:20 AM, Nuno Sá wrote:  
> >> On Mon, Jun 22, 2026 at 12:51:20PM +0100, Rodrigo Alencar wrote:  
> >>> On 22/06/26 11:29, Nuno Sá wrote:  
> >>>> On Mon, Jun 22, 2026 at 10:24:05AM +0100, Rodrigo Alencar wrote:  
> >>>>> On 21/06/26 15:33, Jonathan Cameron wrote:  
> >>>>>> On Fri, 19 Jun 2026 16:54:11 +0100
> >>>>>> Nuno Sá <noname.nuno@gmail.com> wrote:
> >>>>>>  
> >>>>>>> On Fri, Jun 19, 2026 at 03:12:07PM +0100, Conor Dooley wrote:  
> >>>>>>>> On Fri, Jun 19, 2026 at 02:01:08PM +0100, Nuno Sá wrote:  
> >>>>>>>>> On Fri, Jun 19, 2026 at 12:40:54PM +0100, Conor Dooley wrote:  
> >>>>>>>>>> On Fri, Jun 19, 2026 at 12:36:55PM +0100, Conor Dooley wrote:  
> >>>>>>>>>>> On Fri, Jun 19, 2026 at 12:33:11PM +0200, Janani Sunil wrote:  
> >>>>>>>>>>>> On 6/14/26 21:44, Jonathan Cameron wrote:  
> >>>>>>>>>>>>> On Tue, 9 Jun 2026 16:47:23 +0200
> >>>>>>>>>>>>> Janani Sunil <jan.sun97@gmail.com> wrote:
> >>>>>>>>>>>>>      
> >>>>>>>>>>>>>> On 5/26/26 15:11, Rodrigo Alencar wrote:  
> >>>>>>>>>>>>>>> On 26/05/19 05:42PM, Janani Sunil wrote:  
> >>>>>>>>>>>>>>>> Devicetree bindings for AD5529R 16 channel 12/16 bit high voltage,
> >>>>>>>>>>>>>>>> buffered voltage output digital-to-analog converter (DAC) with an
> >>>>>>>>>>>>>>>> integrated precision reference.  
> >>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>> Probably others may comment on that, but...
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> This parent node may support device addressing for multi-device support through
> >>>>>>>>>>>>>>> those ID pins. I suppose that each device may have its own power supplies or
> >>>>>>>>>>>>>>> other resources like the toggle pins or reset and enable.
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> That way I suppose that an example would look like...  
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +patternProperties:
> >>>>>>>>>>>>>>>> +  "^channel@([0-9]|1[0-5])$":
> >>>>>>>>>>>>>>>> +    type: object
> >>>>>>>>>>>>>>>> +    description: Child nodes for individual channel configuration
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +    properties:
> >>>>>>>>>>>>>>>> +      reg:
> >>>>>>>>>>>>>>>> +        description: Channel number.
> >>>>>>>>>>>>>>>> +        minimum: 0
> >>>>>>>>>>>>>>>> +        maximum: 15
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +      adi,output-range-microvolt:
> >>>>>>>>>>>>>>>> +        description: |
> >>>>>>>>>>>>>>>> +          Output voltage range for this channel as [min, max] in microvolts.
> >>>>>>>>>>>>>>>> +          If not specified, defaults to 0V to 5V range.
> >>>>>>>>>>>>>>>> +        oneOf:
> >>>>>>>>>>>>>>>> +          - items:
> >>>>>>>>>>>>>>>> +              - const: 0
> >>>>>>>>>>>>>>>> +              - enum: [5000000, 10000000, 20000000, 40000000]
> >>>>>>>>>>>>>>>> +          - items:
> >>>>>>>>>>>>>>>> +              - const: -5000000
> >>>>>>>>>>>>>>>> +              - const: 5000000
> >>>>>>>>>>>>>>>> +          - items:
> >>>>>>>>>>>>>>>> +              - const: -10000000
> >>>>>>>>>>>>>>>> +              - const: 10000000
> >>>>>>>>>>>>>>>> +          - items:
> >>>>>>>>>>>>>>>> +              - const: -15000000
> >>>>>>>>>>>>>>>> +              - const: 15000000
> >>>>>>>>>>>>>>>> +          - items:
> >>>>>>>>>>>>>>>> +              - const: -20000000
> >>>>>>>>>>>>>>>> +              - const: 20000000
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +    required:
> >>>>>>>>>>>>>>>> +      - reg
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +    additionalProperties: false
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +required:
> >>>>>>>>>>>>>>>> +  - compatible
> >>>>>>>>>>>>>>>> +  - reg
> >>>>>>>>>>>>>>>> +  - vdd-supply
> >>>>>>>>>>>>>>>> +  - avdd-supply
> >>>>>>>>>>>>>>>> +  - hvdd-supply
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +dependencies:
> >>>>>>>>>>>>>>>> +  spi-cpha: [ spi-cpol ]
> >>>>>>>>>>>>>>>> +  spi-cpol: [ spi-cpha ]
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +allOf:
> >>>>>>>>>>>>>>>> +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +unevaluatedProperties: false
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +examples:
> >>>>>>>>>>>>>>>> +  - |
> >>>>>>>>>>>>>>>> +    #include <dt-bindings/gpio/gpio.h>
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +    spi {
> >>>>>>>>>>>>>>>> +        #address-cells = <1>;
> >>>>>>>>>>>>>>>> +        #size-cells = <0>;
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +        dac@0 {
> >>>>>>>>>>>>>>>> +            compatible = "adi,ad5529r-16";
> >>>>>>>>>>>>>>>> +            reg = <0>;
> >>>>>>>>>>>>>>>> +            spi-max-frequency = <25000000>;
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +            vdd-supply = <&vdd_regulator>;
> >>>>>>>>>>>>>>>> +            avdd-supply = <&avdd_regulator>;
> >>>>>>>>>>>>>>>> +            hvdd-supply = <&hvdd_regulator>;
> >>>>>>>>>>>>>>>> +            hvss-supply = <&hvss_regulator>;
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +            reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +            #address-cells = <1>;
> >>>>>>>>>>>>>>>> +            #size-cells = <0>;
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +            channel@0 {
> >>>>>>>>>>>>>>>> +                reg = <0>;
> >>>>>>>>>>>>>>>> +                adi,output-range-microvolt = <0 5000000>;
> >>>>>>>>>>>>>>>> +            };
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +            channel@1 {
> >>>>>>>>>>>>>>>> +                reg = <1>;
> >>>>>>>>>>>>>>>> +                adi,output-range-microvolt = <(-10000000) 10000000>;
> >>>>>>>>>>>>>>>> +            };
> >>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>> +            channel@2 {
> >>>>>>>>>>>>>>>> +                reg = <2>;
> >>>>>>>>>>>>>>>> +                adi,output-range-microvolt = <0 40000000>;
> >>>>>>>>>>>>>>>> +            };
> >>>>>>>>>>>>>>>> +        };
> >>>>>>>>>>>>>>>> +    };  
> >>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 	spi {
> >>>>>>>>>>>>>>> 		#address-cells = <1>;
> >>>>>>>>>>>>>>> 		#size-cells = <0>;
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 		multi-dac@0 {
> >>>>>>>>>>>>>>> 			compatible = "adi,ad5529r-16";
> >>>>>>>>>>>>>>> 			reg = <0>;
> >>>>>>>>>>>>>>> 			spi-max-frequency = <25000000>;
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 			#address-cells = <1>;
> >>>>>>>>>>>>>>> 			#size-cells = <0>;
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 			dac@0 {
> >>>>>>>>>>>>>>> 				reg = <0>;
> >>>>>>>>>>>>>>> 				vdd-supply = <&vdd_regulator>;
> >>>>>>>>>>>>>>> 				avdd-supply = <&avdd_regulator>;
> >>>>>>>>>>>>>>> 				hvdd-supply = <&hvdd_regulator>;
> >>>>>>>>>>>>>>> 				hvss-supply = <&hvss_regulator>;
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 				reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 				#address-cells = <1>;
> >>>>>>>>>>>>>>> 				#size-cells = <0>;
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 				channel@0 {
> >>>>>>>>>>>>>>> 					reg = <0>;
> >>>>>>>>>>>>>>> 					adi,output-range-microvolt = <0 5000000>;
> >>>>>>>>>>>>>>> 				};
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 				channel@1 {
> >>>>>>>>>>>>>>> 					reg = <1>;
> >>>>>>>>>>>>>>> 					adi,output-range-microvolt = <(-10000000) 10000000>;
> >>>>>>>>>>>>>>> 				};
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 				channel@2 {
> >>>>>>>>>>>>>>> 					reg = <2>;
> >>>>>>>>>>>>>>> 					adi,output-range-microvolt = <0 40000000>;
> >>>>>>>>>>>>>>> 				};
> >>>>>>>>>>>>>>> 			}
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 			dac@1 {
> >>>>>>>>>>>>>>> 				reg = <1>;
> >>>>>>>>>>>>>>> 				vdd-supply = <&vdd_regulator>;
> >>>>>>>>>>>>>>> 				avdd-supply = <&avdd_regulator>;
> >>>>>>>>>>>>>>> 				hvdd-supply = <&hvdd_regulator>;
> >>>>>>>>>>>>>>> 				hvss-supply = <&hvss_regulator>;
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 				reset-gpios = <&gpio0 88 GPIO_ACTIVE_LOW>;
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 				#address-cells = <1>;
> >>>>>>>>>>>>>>> 				#size-cells = <0>;
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 				channel@0 {
> >>>>>>>>>>>>>>> 					reg = <0>;
> >>>>>>>>>>>>>>> 					adi,output-range-microvolt = <0 5000000>;
> >>>>>>>>>>>>>>> 				};
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 				channel@1 {
> >>>>>>>>>>>>>>> 					reg = <1>;
> >>>>>>>>>>>>>>> 					adi,output-range-microvolt = <(-10000000) 10000000>;
> >>>>>>>>>>>>>>> 				};
> >>>>>>>>>>>>>>> 			}
> >>>>>>>>>>>>>>> 		};
> >>>>>>>>>>>>>>> 	};
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> then you might need something like:
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> 	patternProperties:
> >>>>>>>>>>>>>>> 		"^dac@[0-3]$":
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> and put most of the things under this node pattern.
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> So the main driver that you're putting together might need to handle up to four instances.
> >>>>>>>>>>>>>>> Even if your current driver cannot handle this, the dt-bindings might need cover that.
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> Need to double check if each dac node needs a separate compatible, so you would maybe populate
> >>>>>>>>>>>>>>> a platform data to be shared with the child nodes, which would be a separate driver.
> >>>>>>>>>>>>>>> (not sure if it would make sense to mix and match ad5529r-16 and ad5529r-12).  
> >>>>>>>>>>>>>> Hi Rodrigo,
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> Thank you for looking at this.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> For now, I would prefer to keep the binding scoped to a single AD5529R device instance. The current
> >>>>>>>>>>>>>> hardware/use case we have only needs one device node and the driver is written around that model as well.
> >>>>>>>>>>>>>> While the device addressing pins could allow multi-device topology, we do not have an actual platform using
> >>>>>>>>>>>>>> that configuration at the moment, so I would prefer not to introduce an extra parent/child binding structure
> >>>>>>>>>>>>>> speculatively without a validating use case.  
> >>>>>>>>>>>>> Interesting feature - kind of similar to address control on a typical i2c bus device, or
> >>>>>>>>>>>>> looking at it another way a kind of distributed SPI mux.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> Challenge of a binding is we need to anticipate the future.  So I think we do need something
> >>>>>>>>>>>>> like Rodrigo is suggesting even if we only (for now) support a single instance in the driver.
> >>>>>>>>>>>>> That would leave the path open to supporting the addressing at a later date.
> >>>>>>>>>>>>> An alternative might be to look at it like a chained device setup. In those we pretend there
> >>>>>>>>>>>>> is just one device with a lot of channels etc.  The snag is that here things are more loosely
> >>>>>>>>>>>>> coupled whereas for those devices it tends to be you have to read / write the same register
> >>>>>>>>>>>>> in all devices in the chain as one big SPI message.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> +CC Mark Brown as he may know of some precedence for this feature. For his reference..
> >>>>>>>>>>>>> - Each of these device has 2 ID pins.  The SPI transfers have to contain the 2 bit
> >>>>>>>>>>>>> value that matches that or they are ignored.  Thus a single bus + 1 chip select can
> >>>>>>>>>>>>> be used to talk to 4 devices.  Question is what that looks like in device tree + I guess
> >>>>>>>>>>>>> longer term how to support it cleanly in SPI.  
> >>>>>>>>>>> I'd swear I have seen this before, from some Microchip devices. Let me
> >>>>>>>>>>> see if I can find what I am thinking of...  
> >>>>>>>>>>
> >>>>>>>>>> microchip,mcp3911 and microchip,mcp3564 both seem to do this with
> >>>>>>>>>> slightly different properties.
> >>>>>>>>>>
> >>>>>>>>>>    microchip,device-addr:
> >>>>>>>>>>      description: Device address when multiple MCP3911 chips are present on the same SPI bus.
> >>>>>>>>>>      $ref: /schemas/types.yaml#/definitions/uint32
> >>>>>>>>>>      enum: [0, 1, 2, 3]
> >>>>>>>>>>      default: 0
> >>>>>>>>>>
> >>>>>>>>>> and
> >>>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>>>    microchip,hw-device-address:
> >>>>>>>>>>      $ref: /schemas/types.yaml#/definitions/uint32
> >>>>>>>>>>      minimum: 0
> >>>>>>>>>>      maximum: 3
> >>>>>>>>>>      description:
> >>>>>>>>>>        The address is set on a per-device basis by fuses in the factory,
> >>>>>>>>>>        configured on request. If not requested, the fuses are set for 0x1.
> >>>>>>>>>>        The device address is part of the device markings to avoid
> >>>>>>>>>>        potential confusion. This address is coded on two bits, so four possible
> >>>>>>>>>>        addresses are available when multiple devices are present on the same
> >>>>>>>>>>        SPI bus with only one Chip Select line for all devices.
> >>>>>>>>>>        Each device communication starts by a CS falling edge, followed by the
> >>>>>>>>>>        clocking of the device address (BITS[7:6] - top two bits of COMMAND BYTE
> >>>>>>>>>>        which is first one on the wire).
> >>>>>>>>>>
> >>>>>>>>>> This sounds exactly like the sort of feature that you're dealing with
> >>>>>>>>>> here?
> >>>>>>>>>>      
> >>>>>>>>> The core idea yes but for this chip, things are a bit more annoying (but
> >>>>>>>>> Janani can correct me if I'm wrong). Here, each device can, in theory,
> >>>>>>>>> have it's own supplies, pins and at the very least, channels with maybe
> >>>>>>>>> different scales. That is why Janani is proposing dac nodes. Given I
> >>>>>>>>> honestly don't like much of that "adi,ad5529r-bus" compatible I wondered
> >>>>>>>>> about solving this at the spi level.
> >>>>>>>>>
> >>>>>>>>> Ah and to make it more annoying, we can also mix 12 and 16 bits variants
> >>>>>>>>> together in the same bus.  
> >>>>>>>> I'm definitely missing something, because that property for the
> >>>>>>>> microchip devices is not impacted what else is on the bus. AFAICT, you
> >>>>>>>> could have an mcp3911 and an mcp3564 on the same bus even though both
> >>>>>>>> are completely different devices with different drivers. They have
> >>>>>>>> individual device nodes and their own supplies etc etc. These aren't
> >>>>>>>> per-channel properties on an adc or dac, they're per child device on a
> >>>>>>>> spi bus.  
> >>>>>>> Maybe I'm the one missing something :). IIRC, spi would not allow two
> >>>>>>> devices on the same CS right? Because for this chip we would need
> >>>>>>> something like:
> >>>>>>>
> >>>>>>> spi {
> >>>>>>> 	dac@0 {
> >>>>>>> 		reg = <0>;
> >>>>>>> 		adi,pin-id = <0>;
> >>>>>>> 	};
> >>>>>>>
> >>>>>>> 	dac@1 {
> >>>>>>> 		reg = <0>; // which seems already problematic?
> >>>>>>> 		adi,pin-id <1>;
> >>>>>>> 	};
> >>>>>>>
> >>>>>>> 	...
> >>>>>>>
> >>>>>>> 	//up to 4
> >>>>>>> };  
> >>>>>> Yeah. It's not clear to me how that works for the microchip devices
> >>>>>> (I suspect it doesn't!)
> >>>>>>
> >>>>>> Just thinking as I type, but could we do something a bit nasty with
> >>>>>> a gpio mux that doesn't actually switch but represents the GPIO being
> >>>>>> shared?  Given this is all tied to the spi bus that should all happen
> >>>>>> under serializing locks.
> >>>>>>
> >>>>>> Agreed though that this would be nicer as an SPI thing that let
> >>>>>> us specify that a single CS is share by multiple devices and their
> >>>>>> is some other signal acting to select which one we are talking to.
> >>>>>>  
> >>>>> If the device-addressing on the same chip-select is to be handled
> >>>>> by the spi framework, wouldn't we lose device-specific features?
> >>>>>
> >>>>> I understand that this multi-device feature is there mostly to extend the
> >>>>> channel count from 16 to 32, 48 or 64. I suppose the command:
> >>>>>
> >>>>> 	"MULTI DEVICE SW LDAC MODE"
> >>>>>
> >>>>> exists so that software can update channel values accross multiple devices.  
> >>>> Right! You do have a point! I agree the main driver for a feature like
> >>>> this is likely to extend the channel count and effectively "aggregate"
> >>>> devices.
> >>>>
> >>>> But I would say that even with the spi solution the MULTI DEVICE stuff
> >>>> should be doable (as we still need a sort of adi,pin-id property).  
> >>> I don't think we can have something like an IIO buffer shared by multiple
> >>> devices. Synchronizing separate devices would be doable with proper hardware
> >>> support for this (probably involving an FGPA).  
> >> True!
> >>  
> >>>     
> >>>> But yes, I do feel that the whole feature is for aggregation so seeing
> >>>> one device with 32 channels is the expectation here? Rather than seeing
> >>>> two devices with 16 channels.  
> >>> Yes, I think aggregation is the whole point there... so that the IIO driver
> >>> is multi-device-aware.  
> >> Which makes me feel that different pins per device might be possible
> >> from an HW point of view but does not make much sense. For example, for
> >> the buffer example I would expect LDAC to be shared between all the
> >> devices.
> >>
> >> - Nuno Sá  
> > I think I mentioned this on a previous revision, but I still think the
> > simplest way to go about it would be to assume that all chips treated
> > as an aggregate device have everything wired in parallel and just add
> > support for per-chip wiring on an as-needed basis. This is how we have
> > handled daisy-chained devices so far.  
> 
> Hi David,
> 
> One thing about this approach is that is does not cover a combination  of 12 and 16 bit parts in the chain,
> since the compatible string would be at the top level and apply to all chips. To handle this without per chip child nodes or per-chip compatible,
> I propose an "adi, resolution" property as an integer array, indexed by the device position:
> 

To me mixed parts, smells like a case that we will probably never see.  If
a customer actually has a design doing that we can add optional dt
bindings at that time.

So I'd stick to separate compatibles. 

> 
> dac@0 {
>      compatible = "adi,ad5529r";
>      reg = <0>;
>      adi,device-addrs = <0 1>;
>      adi,resolution   = <16 12>;   /* per-chip, indexed by position */
>      reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
>      vdd-supply  = <&vdd_reg>;
>      hvdd-supply = <&hvdd_reg>;
> 
>      channel@0  { reg = <0>;  adi,output-range-microvolt = <0 5000000>; };
>      channel@16 { reg = <16>; adi,output-range-microvolt = <0 40000000>; };




> };
> 
> 
> 1) This follows the daisy-chain/aggregated model as you suggested, exposing N*16 channels as a single IIO device.
> 2) Keeps the binding flat- no phantom compatible at a parent bus node, no per-chip child nodes.
> 3) Enables a 12 bit + 16 bit device combination in the chain, without needing a per-chip compatible.
> 4) adi, device-addrs specifies the HW address, allowing the driver to encode it into the SPI frame.
> 5) Supplies and GPIOs remain simple- assuming parallel wiring across all chips.
> 
> Jonathan, you had earlier suggested using separate compatibles
>   (adi,ad5529r-16 and adi,ad5529r-12) to handle the
>   resolution difference.
> However, with the aggregated flat binding model,
>   separate per-chip compatibles would require child nodes which brings
> back the phantom compatible problem at the parent level. The
>   adi,resolution array is intended as an alternative that achieves the
> same goal-expressing per-chip resolution, without needing a per-chip
>   compatible or child node structure.
> 
> Does this look reasonable?
> 
> Best Regards,
> Janani Sunil
> 
> 


^ permalink raw reply

* [RFC 10/12] i2c: acpi: Also register ACPI i2c_clients for adapters with a secondary ACPI fwnode
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

In DT-ACPI hybrid mode the primary fwnode of an i2c_adapter will be a DT/of
node and the secondary fwnode may point to an ACPI fwnode.

i2c_acpi_register_devices() exits early if has_acpi_companion() returns
false and has_acpi_companion() only checks the primary fwnode. Switch to
is_acpi_device_node_any() to also check the secondary.

The rest of the code to register ACPI i2c_clients uses
device_match_acpi_handle() which already handles this correctly.

Also adjust i2c_acpi_find_bus_speed() to use to_acpi_device_node_any()
to als make it work in DT-ACPI hybrid mode.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 drivers/i2c/i2c-core-acpi.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index 28c0e4884a7f..995bd88ad09f 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -322,7 +322,7 @@ void i2c_acpi_register_devices(struct i2c_adapter *adap)
 	struct acpi_device *adev;
 	acpi_status status;
 
-	if (!has_acpi_companion(&adap->dev))
+	if (!is_acpi_device_node_any(adap->dev.fwnode))
 		return;
 
 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
@@ -413,13 +413,15 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
 {
 	struct i2c_acpi_lookup lookup;
 	struct i2c_board_info dummy;
+	struct acpi_device *adev;
 	acpi_status status;
 
-	if (!has_acpi_companion(dev))
+	adev = to_acpi_device_node_any(dev->fwnode);
+	if (!adev)
 		return 0;
 
 	memset(&lookup, 0, sizeof(lookup));
-	lookup.search_handle = ACPI_HANDLE(dev);
+	lookup.search_handle = adev->handle;
 	lookup.min_speed = UINT_MAX;
 	lookup.info = &dummy;
 	lookup.index = -1;
-- 
2.54.0


^ permalink raw reply related

* [RFC 12/12] arm64: dts: qcom: x1e78100-thinkpad-t14s: Move keyb and touchpad to ACPI enumeration
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

Add acpi-path properties for DT-ACPI hybrid mode and remove the keyboard
and touchpad description switching to relying on ACPI to enumerate these.

Also drop the clock-frequency this is also provided by ACPI now.

FIXME: Needs DT-bindings patch as pre-req

Note this depends on these 2 patch-series for working PDC support on Hamoa:
https://lore.kernel.org/linux-arm-msm/20260410184124.1068210-1-mukesh.ojha@oss.qualcomm.com/
https://lore.kernel.org/linux-arm-msm/20260616-hamoa_pdc_v3-v3-0-4d8e1504ea75@oss.qualcomm.com/

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 .../qcom/x1e78100-lenovo-thinkpad-t14s.dtsi   | 59 +------------------
 1 file changed, 3 insertions(+), 56 deletions(-)

diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
index 2fc01e8e8c04..a73576ec238d 100644
--- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
@@ -1017,57 +1017,8 @@ &gpu_zap_shader {
 };
 
 &i2c0 {
-	clock-frequency = <400000>;
-
-	pinctrl-0 = <&qup_i2c0_data_clk>, <&tpad_default>;
-	pinctrl-names = "default";
-
+	acpi-path = "\\_SB.I2C1";
 	status = "okay";
-
-	/* ELAN06E2 or ELAN06E3 */
-	touchpad@15 {
-		compatible = "hid-over-i2c";
-		reg = <0x15>;
-
-		hid-descr-addr = <0x1>;
-		interrupts-extended = <&tlmm 3 IRQ_TYPE_LEVEL_LOW>;
-
-		vdd-supply = <&vreg_misc_3p3>;
-		vddl-supply = <&vreg_l12b_1p2>;
-
-		wakeup-source;
-	};
-
-	/* SYNA8022 or SYNA8024 */
-	touchpad@2c {
-		compatible = "hid-over-i2c";
-		reg = <0x2c>;
-
-		hid-descr-addr = <0x20>;
-		interrupts-extended = <&tlmm 3 IRQ_TYPE_LEVEL_LOW>;
-
-		vdd-supply = <&vreg_misc_3p3>;
-		vddl-supply = <&vreg_l12b_1p2>;
-
-		wakeup-source;
-	};
-
-	/* ELAN06F1 or SYNA06F2 */
-	keyboard@3a {
-		compatible = "hid-over-i2c";
-		reg = <0x3a>;
-
-		hid-descr-addr = <0x1>;
-		interrupts-extended = <&tlmm 67 IRQ_TYPE_LEVEL_LOW>;
-
-		vdd-supply = <&vreg_misc_3p3>;
-		vddl-supply = <&vreg_l15b_1p8>;
-
-		pinctrl-0 = <&kybd_default>;
-		pinctrl-names = "default";
-
-		wakeup-source;
-	};
 };
 
 &i2c3 {
@@ -1598,6 +1549,8 @@ wcd_tx: codec@0,3 {
 };
 
 &tlmm {
+	acpi-path = "\\_SB.GIO0";
+
 	gpio-reserved-ranges = <34 2>, /* Unused */
 			       <44 4>, /* SPI (TPM) */
 			       <72 2>, /* Secure EC I2C connection (?) */
@@ -1655,12 +1608,6 @@ hdmi_hpd_default: hdmi-hpd-default-state {
 		bias-disable;
 	};
 
-	tpad_default: tpad-default-state {
-		pins = "gpio3";
-		function = "gpio";
-		bias-pull-up;
-	};
-
 	nvme_reg_en: nvme-reg-en-state {
 		pins = "gpio18";
 		function = "gpio";
-- 
2.54.0


^ permalink raw reply related

* [RFC 11/12] i2c: qcom-geni: Fall back to i2c_acpi_find_bus_speed()
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

Fall back to i2c_acpi_find_bus_speed() to get the bus-frequency if there
is no "clock-frequency" property to get the bus-frequency from ACPI if
available there.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-qcom-geni.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 2138fcffdaf3..97a538cd9455 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1024,8 +1024,14 @@ static int geni_i2c_probe(struct platform_device *pdev)
 	ret = device_property_read_u32(dev, "clock-frequency",
 				       &gi2c->clk_freq_out);
 	if (ret) {
-		dev_info(dev, "Bus frequency not specified, default to 100kHz.\n");
-		gi2c->clk_freq_out = I2C_MAX_STANDARD_MODE_FREQ;
+		ret = i2c_acpi_find_bus_speed(dev);
+		if (ret) {
+			dev_info(dev, "Using ACPI Bus frequency: %d\n", ret);
+			gi2c->clk_freq_out = ret;
+		} else {
+			dev_info(dev, "Bus frequency not specified, default to 100kHz.\n");
+			gi2c->clk_freq_out = I2C_MAX_STANDARD_MODE_FREQ;
+		}
 	}
 
 	gi2c->irq = platform_get_irq(pdev, 0);
-- 
2.54.0


^ permalink raw reply related

* [RFC 07/12] ACPI: Make device_match_acpi_handle() also check the secondary fwnode
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

In DT-ACPI hybrid mode the secondary fwnode of a device may point to
an ACPI fwnode instead of the primary.

device_match_acpi_handle() is used to find parent GPIO/I2C/SPI controllers
when resolving ACPI device resources from (_CRS) in this case we always
want to also check the secondary fwnode to help find the parent.

Modify the existing device_match_acpi_handle() function to also check
the secondary fwnode.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 drivers/base/core.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index bd2ddf2aab50..2573253f5815 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -5357,7 +5357,9 @@ EXPORT_SYMBOL(device_match_acpi_dev);
 
 int device_match_acpi_handle(struct device *dev, const void *handle)
 {
-	return handle && ACPI_HANDLE(dev) == handle;
+	struct acpi_device *adev = to_acpi_device_node_any(dev->fwnode);
+
+	return handle && adev && adev->handle == handle;
 }
 EXPORT_SYMBOL(device_match_acpi_handle);
 
-- 
2.54.0


^ permalink raw reply related

* [RFC 09/12] pinctrl: qcom: Add support for WoA ACPI tables virtual TLMM pin numbers
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

The ACPI tabled on Windows on ARM laptops use TLMM pin numbers outside of
the actual TLMM pin number range. These are a rather convoluted way to let
the Windows Qualcomm GPIO driver now to use the PDC for some pins because
these are wakeup sources.

This adds support for translating the magic Windows virtual GPIOs for these
back to a regular TLMM GPIO so that ACPI described devices using these
virtual GPIOs can work with Linux.

For now this code only tries to do this mapping when booting in DT-ACPI
hybrid mode which is only used on some WoA devices so this should not
impact any other use-cases.

The new functions use woa_acpi in their name to make clear that these
are for dealing with the ACPI tables found on WoA devices, rather then
ACPI tables found on other devices, like ARM system ready devices which
also use ACPI.

Note that simply mapping these virtual GPIOs back to TLMM pin numbers can
safely be done on Linux, because Linux always uses the PDC for GPIO IRQs
where possible.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 drivers/pinctrl/qcom/Makefile           |   4 +-
 drivers/pinctrl/qcom/pinctrl-msm-acpi.c | 196 ++++++++++++++++++++++++
 drivers/pinctrl/qcom/pinctrl-msm.c      |  47 +++++-
 drivers/pinctrl/qcom/pinctrl-msm.h      |  35 +++++
 4 files changed, 278 insertions(+), 4 deletions(-)
 create mode 100644 drivers/pinctrl/qcom/pinctrl-msm-acpi.c

diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 84bda3ada874..9029d99190d2 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -1,6 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 # Qualcomm pin control drivers
-obj-$(CONFIG_PINCTRL_MSM)	+= pinctrl-msm.o
+obj-$(CONFIG_PINCTRL_MSM)	+= pinctrl-msm-core.o
+pinctrl-msm-core-y		:= pinctrl-msm.o
+pinctrl-msm-core-$(CONFIG_ACPI)	+= pinctrl-msm-acpi.o
 obj-$(CONFIG_PINCTRL_APQ8064)	+= pinctrl-apq8064.o
 obj-$(CONFIG_PINCTRL_APQ8084)	+= pinctrl-apq8084.o
 obj-$(CONFIG_PINCTRL_ELIZA)	+= pinctrl-eliza.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm-acpi.c b/drivers/pinctrl/qcom/pinctrl-msm-acpi.c
new file mode 100644
index 000000000000..df180fd04749
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm-acpi.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ACPI GPIO lookup handling for WoA (Windows on ARM) laptop ACPI tables.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/gpio/driver.h>
+#include <linux/list.h>
+#include <linux/math.h>
+#include "pinctrl-msm.h"
+
+#define MSM_GPIO_WOA_ACPI_GPIOS_PER_BANK	64
+#define MSM_GPIO_WOA_ACPI_IRQ_OFFSET		32
+#define MSM_GPIO_WOA_ACPI_INVALID_GPIO		~0U
+#define MSM_GPIO_WOA_ACPI_MAX_PDC_RANGES	16
+
+#define PDC_RANGE_PIN_BASE			0
+#define PDC_RANGE_GIC_BASE			1
+#define PDC_RANGE_COUNT				2
+#define PDC_RANGE_ELEMENTS			3
+
+/**
+ * struct msm_gpio_woa_acpi_parse_data - Data for parsing WoA ACPI GPIO ctl resources
+ * @chip:		gpiochip handle
+ * @data:		Data for mapping virtual WoA ACPI PDC IRQ GPIOs
+ * @soc_data:		Reference to soc_data of platform specific data
+ * @pdc_range:		PDC GIC to PDC map ranges
+ * @pdc_range_count:	PDC GIC to PDC map range-count
+ */
+struct msm_gpio_woa_acpi_parse_data {
+	struct gpio_chip *chip;
+	struct msm_gpio_woa_acpi_data *data;
+	const struct msm_pinctrl_soc_data *soc_data;
+	u32 pdc_range[MSM_GPIO_WOA_ACPI_MAX_PDC_RANGES][PDC_RANGE_ELEMENTS];
+	unsigned int pdc_range_count;
+};
+
+/*
+ * Mapping does not need translating the acpi_resource in to a regular resoure
+ * and adding it to the resource list. Always return 1 to disable this.
+ */
+static int msm_gpio_woa_acpi_resource(struct acpi_resource *ares, void *_parse)
+{
+	struct msm_gpio_woa_acpi_parse_data *parse = _parse;
+	const struct msm_pinctrl_soc_data *soc_data = parse->soc_data;
+	struct msm_gpio_woa_acpi_data *data = parse->data;
+	struct gpio_chip *chip = parse->chip;
+	u32 gic_irq, pdc_pin;
+
+	if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ ||
+	    ares->data.extended_irq.interrupt_count != 1)
+		return 1;
+
+	if (data->nmap == MSM_GPIO_WOA_ACPI_MAX_VIRT_GPIOS) {
+		dev_err(chip->parent, "ACPI resources contain more than %d IRQs\n",
+			MSM_GPIO_WOA_ACPI_MAX_VIRT_GPIOS);
+		return 1;
+	}
+
+	/*
+	 * Windows ACPI tables divide GPIOs into banks of 64 pins with one IRQ
+	 * per bank. The resources start with listing the real TLMM IRQ for
+	 * as many banks as are necessary to cover the real GPIOs. The Windows
+	 * virtual GPIO indexes skip these banks, mark them as unavailable.
+	 */
+	if (data->nmap < DIV_ROUND_UP(chip->ngpio, MSM_GPIO_WOA_ACPI_GPIOS_PER_BANK)) {
+		data->map[data->nmap++] = MSM_GPIO_WOA_ACPI_INVALID_GPIO;
+		return 1;
+	}
+
+	/*
+	 * Use the "pdc-ranges" property on the PDC to translate the GIC IRQ
+	 * from the acpi_resource to a PDC pin.
+	 */
+	gic_irq = ares->data.extended_irq.interrupts[0] - MSM_GPIO_WOA_ACPI_IRQ_OFFSET;
+	pdc_pin = MSM_GPIO_WOA_ACPI_INVALID_GPIO;
+	for (unsigned int i = 0; i < parse->pdc_range_count; i++) {
+		u32 gic_base = parse->pdc_range[i][PDC_RANGE_GIC_BASE];
+		u32 count = parse->pdc_range[i][PDC_RANGE_COUNT];
+		if (gic_irq >= gic_base && gic_irq < (gic_base + count)) {
+			pdc_pin = parse->pdc_range[i][PDC_RANGE_PIN_BASE] +
+				  gic_irq - gic_base;
+			break;
+		}
+	}
+	if (pdc_pin == MSM_GPIO_WOA_ACPI_INVALID_GPIO)
+		goto no_map;
+
+	/* Use wakeirq-map to map PDC pin to TLMM pin */
+	for (unsigned int i = 0; i < soc_data->nwakeirq_map; i++) {
+		if (soc_data->wakeirq_map[i].wakeirq == pdc_pin) {
+			data->map[data->nmap++] = soc_data->wakeirq_map[i].gpio;
+			return 1;
+		}
+	}
+
+no_map:
+	dev_warn(chip->parent, "Cannot map GIC IRQ %u to TLMM pin\n", gic_irq);
+	data->map[data->nmap++] = MSM_GPIO_WOA_ACPI_INVALID_GPIO;
+	return 1;
+}
+
+int msm_gpio_woa_acpi_init(struct gpio_chip *chip, struct msm_gpio_woa_acpi_data *data,
+			   const struct msm_pinctrl_soc_data *soc_data)
+{
+	struct msm_gpio_woa_acpi_parse_data parse;
+	struct fwnode_handle *fwnode;
+	struct device_node *pdc_np;
+	LIST_HEAD(resources);
+	unsigned int ngpio;
+	int ret;
+
+	/* WoA ACPI tables are only used in DT-ACPI hybrid mode */
+	fwnode = chip->parent->fwnode;
+	if (!is_of_node(fwnode) || !is_acpi_device_node(fwnode->secondary))
+		return 0;
+
+	parse.chip = chip;
+	parse.data = data;
+	parse.soc_data = soc_data;
+
+	/* Get PDC ranges, the PDC is the TLMM's wakeup-parent. */
+	pdc_np = of_parse_phandle(chip->parent->of_node, "wakeup-parent", 0);
+	if (!pdc_np)
+		return 0;
+
+	ret = of_property_count_elems_of_size(pdc_np, "qcom,pdc-ranges", sizeof(u32));
+	if (ret <= 0 || ret % PDC_RANGE_ELEMENTS ||
+	    ret > (MSM_GPIO_WOA_ACPI_MAX_PDC_RANGES * PDC_RANGE_ELEMENTS))
+		goto err_pdc_ranges;
+
+	parse.pdc_range_count = ret / PDC_RANGE_ELEMENTS;
+	ret = of_property_read_u32_array(pdc_np, "qcom,pdc-ranges",
+					 &parse.pdc_range[0][0], ret);
+	if (ret)
+		goto err_pdc_ranges;
+
+	ret = acpi_dev_get_resources(to_acpi_device_node(fwnode->secondary), &resources,
+				     msm_gpio_woa_acpi_resource, &parse);
+	if (ret < 0)
+		return ret;
+
+	acpi_dev_free_resource_list(&resources);
+
+	ngpio = data->nmap * MSM_GPIO_WOA_ACPI_GPIOS_PER_BANK + 1;
+	chip->ngpio = max(chip->ngpio, ngpio);
+
+	for (unsigned int i = 0; i < data->nmap; i++) {
+		if (data->map[i] != MSM_GPIO_WOA_ACPI_INVALID_GPIO) {
+			/* TODO lower log level to dev_dbg() */
+			dev_info(chip->parent, "mapped GPIO 0x%03x to TLMM pin %u\n",
+				 i * MSM_GPIO_WOA_ACPI_GPIOS_PER_BANK, data->map[i]);
+		}
+	}
+
+	return 0;
+
+err_pdc_ranges:
+	dev_err(chip->parent, "Error invalid pdc-ranges\n");
+	return 0; /* Continue without mapping */
+}
+
+void msm_gpio_woa_acpi_valid_mask(struct gpio_chip *chip,
+				  struct msm_gpio_woa_acpi_data *data,
+				  unsigned long *valid_mask,
+				  unsigned int soc_ngpio)
+{
+	/* First mark all virtual ACPI PDC GPIOs (if any) as invalid */
+	bitmap_clear(valid_mask, soc_ngpio, chip->ngpio - soc_ngpio);
+
+	/*
+	 * WoA ACPI tables list 1 Interrupt resource per PDC pin and use
+	 * a 1 interrupt per bank model. So each PDC pin gets its own bank,
+	 * with only pin 0 of that bank used for that PDC pin.
+	 */
+	for (unsigned int i = 0; i < data->nmap; i++) {
+		if (data->map[i] != MSM_GPIO_WOA_ACPI_INVALID_GPIO)
+			set_bit(i * MSM_GPIO_WOA_ACPI_GPIOS_PER_BANK, valid_mask);
+	}
+}
+
+unsigned int msm_gpio_woa_acpi_map(struct msm_gpio_woa_acpi_data *data, unsigned int offset)
+{
+	unsigned int bank = offset / MSM_GPIO_WOA_ACPI_GPIOS_PER_BANK;
+
+	/* msm_gpio_woa_acpi_valid_mask() should ensure this never happens */
+	if (WARN_ON(offset % MSM_GPIO_WOA_ACPI_GPIOS_PER_BANK || bank >= data->nmap ||
+	    data->map[bank] == MSM_GPIO_WOA_ACPI_INVALID_GPIO))
+		return 0;
+
+	return data->map[bank];
+}
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index f780bab51d9c..60ba0da95634 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -45,6 +45,7 @@
  * @pctrl:          pinctrl handle.
  * @chip:           gpiochip handle.
  * @desc:           pin controller descriptor
+ * @woa_acpi:       data for mapping virtual WoA ACPI PDC IRQ GPIOs
  * @irq:            parent irq for the TLMM irq_chip.
  * @intr_target_use_scm: route irq to application cpu using scm calls
  * @lock:           Spinlock to protect register resources as well
@@ -64,6 +65,7 @@ struct msm_pinctrl {
 	struct pinctrl_dev *pctrl;
 	struct gpio_chip chip;
 	struct pinctrl_desc desc;
+	struct msm_gpio_woa_acpi_data woa_acpi;
 
 	int irq;
 
@@ -553,6 +555,16 @@ static const struct pinconf_ops msm_pinconf_ops = {
 	.pin_config_group_set	= msm_config_group_set,
 };
 
+static unsigned int msm_gpio_map(struct gpio_chip *chip, unsigned int offset)
+{
+	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
+
+	if (offset < pctrl->soc->ngpios)
+		return offset;
+
+	return msm_gpio_woa_acpi_map(&pctrl->woa_acpi, offset);
+}
+
 static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
 	const struct msm_pingroup *g;
@@ -560,6 +572,8 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 	unsigned long flags;
 	u32 val;
 
+	offset = msm_gpio_map(chip, offset);
+
 	g = &pctrl->soc->groups[offset];
 
 	raw_spin_lock_irqsave(&pctrl->lock, flags);
@@ -580,6 +594,8 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
 	unsigned long flags;
 	u32 val;
 
+	offset = msm_gpio_map(chip, offset);
+
 	g = &pctrl->soc->groups[offset];
 
 	raw_spin_lock_irqsave(&pctrl->lock, flags);
@@ -606,6 +622,8 @@ static int msm_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
 	const struct msm_pingroup *g;
 	u32 val;
 
+	offset = msm_gpio_map(chip, offset);
+
 	g = &pctrl->soc->groups[offset];
 
 	val = msm_readl_ctl(pctrl, g);
@@ -620,6 +638,8 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
 	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
 	u32 val;
 
+	offset = msm_gpio_map(chip, offset);
+
 	g = &pctrl->soc->groups[offset];
 
 	val = msm_readl_io(pctrl, g);
@@ -633,6 +653,8 @@ static int msm_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
 	unsigned long flags;
 	u32 val;
 
+	offset = msm_gpio_map(chip, offset);
+
 	g = &pctrl->soc->groups[offset];
 
 	raw_spin_lock_irqsave(&pctrl->lock, flags);
@@ -717,10 +739,11 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
 
 static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
+	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
 	unsigned gpio = chip->base;
 	unsigned i;
 
-	for (i = 0; i < chip->ngpio; i++, gpio++)
+	for (i = 0; i < pctrl->soc->ngpios; i++, gpio++)
 		msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
 }
 
@@ -738,6 +761,10 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *gc,
 	const int *reserved = pctrl->soc->reserved_gpios;
 	u16 *tmp;
 
+	/* WOA ACPI handles virtual PDC GPIO range, only handle real GPIOs here */
+	ngpios = pctrl->soc->ngpios;
+	msm_gpio_woa_acpi_valid_mask(gc, &pctrl->woa_acpi, valid_mask, ngpios);
+
 	/* Remove driver-provided reserved GPIOs from valid_mask */
 	if (reserved) {
 		for (i = 0; reserved[i] >= 0; i++) {
@@ -1046,6 +1073,10 @@ static void msm_gpio_irq_init_valid_mask(struct gpio_chip *gc,
 	const struct msm_pingroup *g;
 	int i;
 
+	/* WOA ACPI handles virtual PDC GPIO range, only handle real GPIOs here */
+	ngpios = pctrl->soc->ngpios;
+	msm_gpio_woa_acpi_valid_mask(gc, &pctrl->woa_acpi, valid_mask, ngpios);
+
 	for (i = 0; i < ngpios; i++) {
 		g = &pctrl->soc->groups[i];
 
@@ -1387,6 +1418,9 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
 	if (pctrl->soc->reserved_gpios)
 		return true;
 
+	if (pctrl->chip.ngpio != pctrl->soc->ngpios)
+		return true;
+
 	return device_property_count_u16(pctrl->dev, "gpios") > 0;
 }
 
@@ -1428,8 +1462,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 	chip->label = dev_name(pctrl->dev);
 	chip->parent = pctrl->dev;
 	chip->owner = THIS_MODULE;
-	if (msm_gpio_needs_valid_mask(pctrl))
-		chip->init_valid_mask = msm_gpio_init_valid_mask;
 
 	np = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0);
 	if (np) {
@@ -1450,6 +1482,13 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 		}
 	}
 
+	ret = msm_gpio_woa_acpi_init(chip, &pctrl->woa_acpi, pctrl->soc);
+	if (ret)
+		return ret;
+
+	if (msm_gpio_needs_valid_mask(pctrl))
+		chip->init_valid_mask = msm_gpio_init_valid_mask;
+
 	girq = &chip->irq;
 	gpio_irq_chip_set_chip(girq, &msm_gpio_irq_chip);
 	girq->parent_handler = msm_gpio_irq_handler;
@@ -1463,6 +1502,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 	girq->handler = handle_bad_irq;
 	girq->parents[0] = pctrl->irq;
 	girq->init_valid_mask = msm_gpio_irq_init_valid_mask;
+	if (pctrl->chip.ngpio != pctrl->soc->ngpios)
+		girq->child_offset_to_irq = msm_gpio_map;
 
 	ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
 	if (ret) {
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index 4fbff61de6bb..3a8a55a6d8c1 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -10,6 +10,7 @@
 
 #include <linux/pinctrl/pinctrl.h>
 
+struct gpio_chip;
 struct platform_device;
 
 struct pinctrl_pin_desc;
@@ -181,9 +182,43 @@ struct msm_pinctrl_soc_data {
 	unsigned int egpio_func;
 };
 
+#define MSM_GPIO_WOA_ACPI_MAX_VIRT_GPIOS	32
+
+/**
+ * struct msm_gpio_woa_acpi_data - Data for mapping virtual WoA ACPI PDC IRQ GPIOs
+ * @map:	Map to translate virtual ACPI GPIO offsets to TLMM pin offsets
+ * @nmap:	Number of valid entried in @map
+ */
+struct msm_gpio_woa_acpi_data {
+	unsigned int map[MSM_GPIO_WOA_ACPI_MAX_VIRT_GPIOS];
+	unsigned int nmap;
+};
+
 extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops;
 
 int msm_pinctrl_probe(struct platform_device *pdev,
 		      const struct msm_pinctrl_soc_data *soc_data);
 
+#ifdef CONFIG_ACPI
+int msm_gpio_woa_acpi_init(struct gpio_chip *chip, struct msm_gpio_woa_acpi_data *data,
+			   const struct msm_pinctrl_soc_data *soc_data);
+void msm_gpio_woa_acpi_valid_mask(struct gpio_chip *chip,
+				  struct msm_gpio_woa_acpi_data *data,
+				  unsigned long *valid_mask,
+				  unsigned int soc_ngpio);
+unsigned int msm_gpio_woa_acpi_map(struct msm_gpio_woa_acpi_data *data, unsigned int offset);
+#else
+static inline int
+msm_gpio_woa_acpi_init(struct gpio_chip *chip, struct msm_gpio_woa_acpi_data *data,
+		       const struct msm_pinctrl_soc_data *soc_data)
+{ return 0; }
+static inline void msm_gpio_woa_acpi_valid_mask(struct gpio_chip *chip,
+						struct msm_gpio_woa_acpi_data *data,
+						unsigned long *valid_mask,
+						unsigned int soc_ngpio) { }
+static inline unsigned int
+msm_gpio_woa_acpi_map(struct msm_gpio_woa_acpi_data *data, unsigned int offset)
+{ return 0; }
 #endif
+
+#endif /* ifndef __PINCTRL_MSM_H__ */
-- 
2.54.0


^ permalink raw reply related

* [RFC 08/12] irqchip/gic-v3: Always call acpi_set_irq_model()
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

The gic-v3 code used to only call acpi_set_irq_model() when the GIC is
enumerated through ACPI.

This causes problems for DT-ACPI hybrid mode, where the GIC might be
described in DT but then a driver using info from the ACPI tables might
call acpi_dev_get_irqresource(), which results in a NULL pointer deref
when acpi_set_irq_model() has not been called.

Always call acpi_set_irq_model() when CONFIG_ACPI is enabled to fix this.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 drivers/irqchip/irq-gic-v3.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 99444a1b2ffa..2ccd04689a04 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1974,6 +1974,23 @@ static void gic_enable_nmi_support(void)
 		gic_chip.flags |= IRQCHIP_SUPPORTS_NMI;
 }
 
+#ifdef CONFIG_ACPI
+static struct fwnode_handle *gsi_domain_handle;
+
+static struct fwnode_handle *gic_v3_get_gsi_domain_id(u32 gsi)
+{
+	return gsi_domain_handle;
+}
+
+static void gic_set_acpi_irq_model(struct fwnode_handle *handle)
+{
+	gsi_domain_handle = handle;
+	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id);
+}
+#else
+static void gic_set_acpi_irq_model(struct fwnode_handle *handle) { }
+#endif
+
 static int __init gic_init_bases(phys_addr_t dist_phys_base,
 				 void __iomem *dist_base,
 				 struct redist_region *rdist_regs,
@@ -2063,6 +2080,9 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base,
 			gicv2m_init(handle, gic_data.domain);
 	}
 
+	/* Also do this when enumerated through DT for DT-ACPI hybrid mode */
+	gic_set_acpi_irq_model(handle);
+
 	return 0;
 
 out_free:
@@ -2534,13 +2554,6 @@ static void __init gic_acpi_setup_kvm_info(void)
 	vgic_set_kvm_info(&gic_v3_kvm_info);
 }
 
-static struct fwnode_handle *gsi_domain_handle;
-
-static struct fwnode_handle *gic_v3_get_gsi_domain_id(u32 gsi)
-{
-	return gsi_domain_handle;
-}
-
 static int __init
 gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
 {
@@ -2588,8 +2601,6 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
 	if (err)
 		goto out_fwhandle_free;
 
-	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id);
-
 	if (static_branch_likely(&supports_deactivate_key))
 		gic_acpi_setup_kvm_info();
 
-- 
2.54.0


^ permalink raw reply related

* [RFC 06/12] ACPI: scan: Retry acpi_device_notify() in DT-ACPI hybrid mode
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

of_platform_default_populate_init creates DT platform devices from
an arch_initcall(), so before acpi_scan_init() runs this causing
acpi_device_notify() to be unable to honor "acpi-path" properties
in DT-ACPI hybrid mode.

Re-call acpi_device_notify() at the end of scanning ACPI devices to
fix this up.

Note this relies on the driver which may use the bound ACPI fwnode
to only register after subsys_initcall(acpi_init) has run.

TODO: It is probably better to add an acpi_platform_device_pre_probe()
function and call that from drivers/base/platform.c:platform_probe() and
dot the setting of the secondary fwnode for platform-devices with
an "acpi-path" property there. Basically moving the "if (acpi_dt_hybrid)"
block in acpi_device_notify() to a new acpi_platform_device_pre_probe().

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 drivers/acpi/scan.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 4836286968e8..b305c03e8504 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -21,6 +21,7 @@
 #include <linux/dmi.h>
 #include <linux/dma-map-ops.h>
 #include <linux/platform_data/x86/apple.h>
+#include <linux/platform_device.h>
 #include <linux/pgtable.h>
 #include <linux/crc32.h>
 #include <linux/dma-direct.h>
@@ -2818,6 +2819,22 @@ static void __init acpi_get_spcr_uart_addr(void)
 	acpi_put_table((struct acpi_table_header *)spcr_ptr);
 }
 
+static int acpi_scan_retry_of_acpi_binding(struct device *dev, void *data)
+{
+	struct fwnode_handle *fwnode = dev_fwnode(dev);
+	const char *acpi_path;
+
+	/* Check primary fwnode is OF and secondary fwnode is not yet ACPI */
+	if (!is_of_node(fwnode) || is_acpi_device_node(fwnode->secondary))
+		return 0;
+
+	/* If there is an "acpi-path" property retry binding ACPI fwnode */
+	if (of_property_read_string(dev->of_node, "acpi-path", &acpi_path) == 0)
+		acpi_device_notify(dev);
+
+	return 0;
+}
+
 static bool acpi_scan_initialized;
 
 void __init acpi_scan_init(void)
@@ -2881,6 +2898,18 @@ void __init acpi_scan_init(void)
 	if (!acpi_gbl_reduced_hardware)
 		acpi_bus_scan_fixed();
 
+	/*
+	 * of_platform_default_populate_init creates DT platform devices from
+	 * an arch_initcall(), so before acpi_scan_init() runs this causing
+	 * acpi_device_notify() to be unable to honor "acpi-path" properties
+	 * in DT-ACPI hybrid mode. Re-call acpi_device_notify() to fix this up.
+	 * Note this relies on the driver which may use the bound ACPI fwnode
+	 * to only register after subsys_initcall(acpi_init) has run.
+	 */
+	if (acpi_dt_hybrid)
+		bus_for_each_dev(&platform_bus_type, NULL, NULL,
+				 acpi_scan_retry_of_acpi_binding);
+
 	acpi_turn_off_unused_power_resources();
 
 	acpi_scan_initialized = true;
-- 
2.54.0


^ permalink raw reply related

* [RFC 05/12] ACPI: glue: Implement setting secondary-fwnode for DT-ACPI hybrid mode
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

In DT-ACPI hybrid mode devices are instantiated from device tree and
a device's primary firmware-node will normally be an of fwnode.

Add support to the ACPI glue code to check the new "acpi-path" DT property
and when this is set lookup the handle for the specified path and set
the secondary-fwnode of the device to point to the handle's ACPI fwnode.

Also create a firmware_node and physical_node links/entries as normal.

When e.g. an "acpi-path" property is specified for e.g. an i2c-adapter
then the normal ACPI i2c-client enumeration will happen for any ACPI
fwnodes with an I2CSerialBus resource pointing to the i2c-adapter, these
ACPI instantiated i2c_clients will have an ACPI fwnode as primary fwnode.
The normal acpi_device_notify[_remove]() paths will be used for these.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 drivers/acpi/glue.c | 70 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 60 insertions(+), 10 deletions(-)

diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index b1776809279d..fef450d5cb7d 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -225,6 +225,15 @@ static void acpi_physnode_link_name(char *buf, unsigned int node_id)
 		strcpy(buf, PHYSICAL_NODE_STRING);
 }
 
+/* Like ACPI_COMPANION_SET() but set secondary fwnode if primary is an of_node */
+static void acpi_companion_set_any(struct device *dev, struct acpi_device *adev)
+{
+	if (is_of_node(dev->fwnode))
+		set_secondary_fwnode(dev, adev ? acpi_fwnode_handle(adev) : NULL);
+	else
+		set_primary_fwnode(dev, adev ? acpi_fwnode_handle(adev) : NULL);
+}
+
 int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 {
 	struct acpi_device_physical_node *physical_node, *pn;
@@ -233,12 +242,12 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 	unsigned int node_id;
 	int retval = -EINVAL;
 
-	if (has_acpi_companion(dev)) {
+	if (is_acpi_device_node_any(dev->fwnode)) {
 		if (acpi_dev) {
 			dev_warn(dev, "ACPI companion already set\n");
 			return -EINVAL;
 		} else {
-			acpi_dev = ACPI_COMPANION(dev);
+			acpi_dev = to_acpi_device_node_any(dev->fwnode);
 		}
 	}
 	if (!acpi_dev)
@@ -267,7 +276,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 
 			dev_warn(dev, "Already associated with ACPI node\n");
 			kfree(physical_node);
-			if (ACPI_COMPANION(dev) != acpi_dev)
+			if (to_acpi_device_node_any(dev->fwnode) != acpi_dev)
 				goto err;
 
 			put_device(dev);
@@ -285,8 +294,8 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 	list_add(&physical_node->node, physnode_list);
 	acpi_dev->physical_node_count++;
 
-	if (!has_acpi_companion(dev))
-		ACPI_COMPANION_SET(dev, acpi_dev);
+	if (!is_acpi_device_node_any(dev->fwnode))
+		acpi_companion_set_any(dev, acpi_dev);
 
 	acpi_physnode_link_name(physical_node_name, node_id);
 	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
@@ -303,13 +312,14 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 
 	mutex_unlock(&acpi_dev->physical_node_lock);
 
-	if (acpi_dev->wakeup.flags.valid)
+	/* Don't set wakeup flag for devices where ACPI fwnode is secondary */
+	if (acpi_dev->wakeup.flags.valid && has_acpi_companion(dev))
 		device_set_wakeup_capable(dev, true);
 
 	return 0;
 
  err:
-	ACPI_COMPANION_SET(dev, NULL);
+	acpi_companion_set_any(dev, NULL);
 	put_device(dev);
 	acpi_dev_put(acpi_dev);
 	return retval;
@@ -318,7 +328,7 @@ EXPORT_SYMBOL_GPL(acpi_bind_one);
 
 int acpi_unbind_one(struct device *dev)
 {
-	struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
+	struct acpi_device *acpi_dev = to_acpi_device_node_any(dev->fwnode);
 	struct acpi_device_physical_node *entry;
 
 	if (!acpi_dev)
@@ -336,7 +346,7 @@ int acpi_unbind_one(struct device *dev)
 			acpi_physnode_link_name(physnode_name, entry->node_id);
 			sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
 			sysfs_remove_link(&dev->kobj, "firmware_node");
-			ACPI_COMPANION_SET(dev, NULL);
+			acpi_companion_set_any(dev, NULL);
 			/* Drop references taken by acpi_bind_one(). */
 			put_device(dev);
 			acpi_dev_put(acpi_dev);
@@ -354,6 +364,40 @@ void acpi_device_notify(struct device *dev)
 	struct acpi_device *adev;
 	int ret;
 
+	if (acpi_dt_hybrid && is_of_node(dev->fwnode)) {
+		const char *acpi_path;
+		acpi_status status;
+		acpi_handle handle;
+
+		ret = of_property_read_string(dev->of_node, "acpi-path", &acpi_path);
+		if (ret)
+			return;
+
+		status = acpi_get_handle(NULL, acpi_path, &handle);
+		if (ACPI_FAILURE(status))
+			goto err_hybrid;
+
+		adev = acpi_fetch_acpi_dev(handle);
+		if (!adev)
+			goto err_hybrid;
+
+		/*
+		 * set_secondary_fwnode() + pass NULL to make this work for
+		 * child devices which share the fwnode with their parent.
+		 */
+		set_secondary_fwnode(dev, acpi_fwnode_handle(adev));
+		ret = acpi_bind_one(dev, NULL);
+		if (ret)
+			goto err_hybrid;
+
+		/* TODO change to dev_dbg() when DT-ACPI hybrid support is stable */
+		dev_info(dev, "Set secondary fwnode to acpi-path '%s'\n", acpi_path);
+		return;
+err_hybrid:
+		dev_warn(dev, "Failed to set ACPI fwnode for acpi-path '%s'\n", acpi_path);
+		return;
+	}
+
 	ret = acpi_bind_one(dev, NULL);
 	if (ret) {
 		struct acpi_bus_type *type = acpi_get_bus_type(dev);
@@ -400,8 +444,14 @@ void acpi_device_notify(struct device *dev)
 
 void acpi_device_notify_remove(struct device *dev)
 {
-	struct acpi_device *adev = ACPI_COMPANION(dev);
+	struct acpi_device *adev;
 
+	if (acpi_dt_hybrid && is_of_node(dev->fwnode)) {
+		acpi_unbind_one(dev);
+		return;
+	}
+
+	adev = ACPI_COMPANION(dev);
 	if (!adev)
 		return;
 
-- 
2.54.0


^ permalink raw reply related

* [RFC 04/12] ACPI: Add helpers for dealing with ACPI fwnode as secondary fwnode
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

In DT-ACPI hybrid mode in some cases code calling is_acpi_device_node() or
to_acpi_device_node() may also want the secondary fwnode to be used.

DT-ACPI hybrid mode is something which subsystems / drivers should opt-in
to, so it is undesirable to make existing helpers use the secondary fwnode.

Add new is_acpi_device_node_any() and to_acpi_device_node_any() helpers
which also use the secondary fwnode.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 drivers/acpi/property.c | 13 +++++++++++++
 include/acpi/acpi_bus.h | 16 ++++++++++++++++
 include/linux/acpi.h    | 10 ++++++++++
 3 files changed, 39 insertions(+)

diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 8ee5a1f0eb48..fb555e50ce83 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -1775,6 +1775,19 @@ bool is_acpi_device_node(const struct fwnode_handle *fwnode)
 }
 EXPORT_SYMBOL(is_acpi_device_node);
 
+/* Like is_acpi_device_node() but also check the secondary fwnode */
+bool is_acpi_device_node_any(const struct fwnode_handle *fwnode)
+{
+	if (IS_ERR_OR_NULL(fwnode))
+		return false;
+
+	if (fwnode->ops == &acpi_device_fwnode_ops)
+		return true;
+
+	return is_acpi_device_node(fwnode->secondary);
+}
+EXPORT_SYMBOL(is_acpi_device_node_any);
+
 bool is_acpi_data_node(const struct fwnode_handle *fwnode)
 {
 	return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &acpi_data_fwnode_ops;
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c41d9a7565cf..bfc3883765f1 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -515,6 +515,7 @@ extern const struct fwnode_operations acpi_data_fwnode_ops;
 extern const struct fwnode_operations acpi_static_fwnode_ops;
 
 bool is_acpi_device_node(const struct fwnode_handle *fwnode);
+bool is_acpi_device_node_any(const struct fwnode_handle *fwnode);
 bool is_acpi_data_node(const struct fwnode_handle *fwnode);
 
 static inline bool is_acpi_node(const struct fwnode_handle *fwnode)
@@ -532,6 +533,21 @@ static inline bool is_acpi_node(const struct fwnode_handle *fwnode)
 			NULL;						\
 	})
 
+/* Like to_acpi_device_node() but also check the secondary fwnode */
+#define to_acpi_device_node_any(__fwnode)				\
+	({								\
+		typeof(__fwnode) __to_acpi_device_node_fwnode = __fwnode; \
+									\
+		IS_ERR_OR_NULL(__to_acpi_device_node_fwnode) ? NULL :	\
+		is_acpi_device_node(__to_acpi_device_node_fwnode) ?	\
+			container_of(__to_acpi_device_node_fwnode,	\
+				     struct acpi_device, fwnode) :	\
+		is_acpi_device_node(__to_acpi_device_node_fwnode->secondary) ? \
+			container_of(__to_acpi_device_node_fwnode->secondary, \
+				     struct acpi_device, fwnode) :	\
+			NULL;						\
+	})
+
 #define to_acpi_data_node(__fwnode)					\
 	({								\
 		typeof(__fwnode) __to_acpi_data_node_fwnode = __fwnode;	\
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 67effb91fa98..bb84774f61df 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -865,11 +865,21 @@ static inline bool is_acpi_device_node(const struct fwnode_handle *fwnode)
 	return false;
 }
 
+static inline bool is_acpi_device_node_any(const struct fwnode_handle *fwnode)
+{
+	return false;
+}
+
 static inline struct acpi_device *to_acpi_device_node(const struct fwnode_handle *fwnode)
 {
 	return NULL;
 }
 
+static inline struct acpi_device *to_acpi_device_node_any(const struct fwnode_handle *fwnode)
+{
+	return NULL;
+}
+
 static inline bool is_acpi_data_node(const struct fwnode_handle *fwnode)
 {
 	return false;
-- 
2.54.0


^ permalink raw reply related

* [RFC 03/12] arm64: acpi: add acpi=hybrid support
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

By default when a non stub DT is given to the kernel when booting, ACPI
gets fully disabled.

Add support for selecting a new APCI-DT hybrid mode where the kernel
booting in DT mode still loads and parses the ACPI tables, without taking
any further actions like creating devices.

This will parse ACPI tables and populate /sys/firmware/acpi and
/sys/bus/acpi/devices, which can be useful to e.g. get an acpidump .

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 arch/arm64/include/asm/acpi.h |  2 +-
 arch/arm64/kernel/acpi.c      | 16 ++++++++++++----
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 3116bb872f47..8f8a0b9e49c3 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -76,10 +76,10 @@ typedef u64 phys_cpuid_t;
 #define PHYS_CPUID_INVALID INVALID_HWID
 
 #define acpi_strict 1	/* No out-of-spec workarounds on ARM64 */
-#define acpi_dt_hybrid 0	/* No DT-ACPI hybrid mode on ARM64 */
 extern int acpi_disabled;
 extern int acpi_noirq;
 extern int acpi_pci_disabled;
+extern int acpi_dt_hybrid;
 
 static inline void disable_acpi(void)
 {
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 06ab3a9da64b..9d2c42375afe 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -43,11 +43,14 @@ EXPORT_SYMBOL(acpi_disabled);
 int acpi_pci_disabled = 1;	/* skip ACPI PCI scan and IRQ initialization */
 EXPORT_SYMBOL(acpi_pci_disabled);
 
+int acpi_dt_hybrid;		/* disable ACPI-DT hybrid mode */
+
 enum acpi_mode_t {
 	acpi_mode_unset,
 	acpi_mode_off,
 	acpi_mode_on,
 	acpi_mode_force,
+	acpi_mode_hybrid,
 };
 
 static enum acpi_mode_t param_acpi_mode __initdata;
@@ -65,6 +68,8 @@ static int __init parse_acpi(char *arg)
 		param_acpi_mode = acpi_mode_on;
 	else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
 		param_acpi_mode = acpi_mode_force;
+	else if (strcmp(arg, "hybrid") == 0) /* ACPI-DT hybrid mode */
+		param_acpi_mode = acpi_mode_hybrid;
 	else if (strcmp(arg, "nospcr") == 0) /* disable SPCR as default console */
 		param_acpi_nospcr = true;
 	else
@@ -203,7 +208,7 @@ static int __init acpi_fadt_sanity_check(void)
 void __init acpi_boot_table_init(void)
 {
 	/*
-	 * When no ACPI mode (acpi=off|on|force) has been specified,
+	 * When no ACPI mode (acpi=off|on|force|hybrid) has been specified,
 	 * enable ACPI if the device tree is empty (it only has a /chosen
 	 * node, and a /hypervisor node when running on Xen).
 	 */
@@ -230,6 +235,9 @@ void __init acpi_boot_table_init(void)
 		pr_err("Failed to init ACPI tables\n");
 		if (param_acpi_mode != acpi_mode_force)
 			disable_acpi();
+	} else if (param_acpi_mode == acpi_mode_hybrid) {
+		acpi_dt_hybrid = 1;
+		disable_acpi();
 	}
 
 done:
@@ -257,10 +265,10 @@ void __init acpi_boot_table_init(void)
 		 */
 		acpi_parse_spcr(earlycon_acpi_spcr_enable,
 			!param_acpi_nospcr);
-
-		if (IS_ENABLED(CONFIG_ACPI_BGRT))
-			acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
 	}
+
+	if ((!acpi_disabled || acpi_dt_hybrid) && IS_ENABLED(CONFIG_ACPI_BGRT))
+		acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
 }
 
 static pgprot_t __acpi_get_writethrough_mem_attribute(void)
-- 
2.54.0


^ permalink raw reply related

* [RFC 02/12] arm64: acpi: Cleanup acpi=[on|off|force] handling
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

acpi=[on|off|force] are 3 values of a single "should ACPI be enabled"
setting. Instead of storing these in 3 separate booleans, introduce a new
acpi_mode_t enum for this and store these in a single param varialable.

This is a preparation patch for adding acpi=hybrid support to enable the
new DT-ACPI hybrid mode, which makes the kernel booting in DT mode still
load and parse the ACPI tables, without taking any further actions.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 arch/arm64/kernel/acpi.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 5891f92c2035..06ab3a9da64b 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -43,9 +43,14 @@ EXPORT_SYMBOL(acpi_disabled);
 int acpi_pci_disabled = 1;	/* skip ACPI PCI scan and IRQ initialization */
 EXPORT_SYMBOL(acpi_pci_disabled);
 
-static bool param_acpi_off __initdata;
-static bool param_acpi_on __initdata;
-static bool param_acpi_force __initdata;
+enum acpi_mode_t {
+	acpi_mode_unset,
+	acpi_mode_off,
+	acpi_mode_on,
+	acpi_mode_force,
+};
+
+static enum acpi_mode_t param_acpi_mode __initdata;
 static bool param_acpi_nospcr __initdata;
 
 static int __init parse_acpi(char *arg)
@@ -55,11 +60,11 @@ static int __init parse_acpi(char *arg)
 
 	/* "acpi=off" disables both ACPI table parsing and interpreter */
 	if (strcmp(arg, "off") == 0)
-		param_acpi_off = true;
+		param_acpi_mode = acpi_mode_off;
 	else if (strcmp(arg, "on") == 0) /* prefer ACPI over DT */
-		param_acpi_on = true;
+		param_acpi_mode = acpi_mode_on;
 	else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
-		param_acpi_force = true;
+		param_acpi_mode = acpi_mode_force;
 	else if (strcmp(arg, "nospcr") == 0) /* disable SPCR as default console */
 		param_acpi_nospcr = true;
 	else
@@ -198,14 +203,14 @@ static int __init acpi_fadt_sanity_check(void)
 void __init acpi_boot_table_init(void)
 {
 	/*
-	 * Enable ACPI instead of device tree unless
-	 * - ACPI has been disabled explicitly (acpi=off), or
-	 * - the device tree is not empty (it has more than just a /chosen node,
-	 *   and a /hypervisor node when running on Xen)
-	 *   and ACPI has not been [force] enabled (acpi=on|force)
+	 * When no ACPI mode (acpi=off|on|force) has been specified,
+	 * enable ACPI if the device tree is empty (it only has a /chosen
+	 * node, and a /hypervisor node when running on Xen).
 	 */
-	if (param_acpi_off ||
-	    (!param_acpi_on && !param_acpi_force && !dt_is_stub()))
+	if (!param_acpi_mode)
+		param_acpi_mode = dt_is_stub() ? acpi_mode_on : acpi_mode_off;
+
+	if (param_acpi_mode == acpi_mode_off)
 		goto done;
 
 	/*
@@ -223,7 +228,7 @@ void __init acpi_boot_table_init(void)
 	 */
 	if (acpi_table_init() || acpi_fadt_sanity_check()) {
 		pr_err("Failed to init ACPI tables\n");
-		if (!param_acpi_force)
+		if (param_acpi_mode != acpi_mode_force)
 			disable_acpi();
 	}
 
-- 
2.54.0


^ permalink raw reply related

* [RFC 01/12] ACPI: Introduce DT-ACPI hybrid mode
From: Hans de Goede @ 2026-06-23 14:52 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Andersson, Konrad Dybcio
  Cc: Hans de Goede, Srinivas Kandagatla, Krzysztof Kozlowski,
	Dmitry Baryshkov, Bartosz Golaszewski, Abel Vesa, linux-arm-msm,
	devicetree, linux-acpi
In-Reply-To: <20260623145225.143218-1-johannes.goede@oss.qualcomm.com>

ATM on platforms which support DT or ACPI as firmware interfaces ACPI gets
fully disabled when DT is in use.

In some cases it is interesting to at least parse the ACPI tables and
possibly also use parts of them.

One specific example of this is Windows on Arm laptops with Qualcomm
Snapdragon processors where Windows boots using information from the ACPI
tables but Linux uses a device-tree description of the hardware instead.

Since Windows is the factory OS, these DT descriptions need to be created
by hand.

Having the ACPI tables available at runtime allows the kernel to use some
information from these ACPI tables while still using device-tree as its
main information source.

Having the tables available at runtime can also help with creating and
improving these DT descriptions.

This patch prepares for a new DT-ACPI hybrid mode controlled by a new
acpi_dt_hybrid flag. When enabled this makes the kernel booting in DT
mode still load and parse the ACPI tables, without taking any further
actions like creating devices.

In this case the ACPI subsys will still parse ACPI tables and populate
/sys/firmware/acpi and /sys/bus/acpi/devices.

Note this patch itself is a no-op, since all the arch/*/include/asm/acpi.h
files define the new acpi_dt_hybrid variable to 0. All the added extra
"if (acpi_disabled)" checks are in paths which already check for this
earlier in the code-path. The new checks only come into play when
acpi_dt_hybrid is set to 1.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 arch/arm64/include/asm/acpi.h     | 1 +
 arch/loongarch/include/asm/acpi.h | 1 +
 arch/riscv/include/asm/acpi.h     | 3 ++-
 arch/x86/include/asm/acpi.h       | 1 +
 drivers/acpi/acpi_apd.c           | 3 +++
 drivers/acpi/acpi_memhotplug.c    | 3 +++
 drivers/acpi/acpi_processor.c     | 3 +++
 drivers/acpi/arm64/init.c         | 2 ++
 drivers/acpi/bus.c                | 6 +++---
 drivers/acpi/scan.c               | 4 ++++
 drivers/acpi/tables.c             | 4 ++--
 drivers/firmware/efi/efi-bgrt.c   | 2 +-
 12 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 8a54ca6ba602..3116bb872f47 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -76,6 +76,7 @@ typedef u64 phys_cpuid_t;
 #define PHYS_CPUID_INVALID INVALID_HWID
 
 #define acpi_strict 1	/* No out-of-spec workarounds on ARM64 */
+#define acpi_dt_hybrid 0	/* No DT-ACPI hybrid mode on ARM64 */
 extern int acpi_disabled;
 extern int acpi_noirq;
 extern int acpi_pci_disabled;
diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
index eda9d4d0a493..5f725bba6e87 100644
--- a/arch/loongarch/include/asm/acpi.h
+++ b/arch/loongarch/include/asm/acpi.h
@@ -12,6 +12,7 @@
 #include <asm/suspend.h>
 
 #ifdef CONFIG_ACPI
+#define acpi_dt_hybrid 0	/* No DT-ACPI hybrid mode on loongarch */
 extern int acpi_strict;
 extern int acpi_disabled;
 extern int acpi_pci_disabled;
diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index 26ab37c171bc..b72586fe650e 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -22,7 +22,8 @@ typedef u64 phys_cpuid_t;
 void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size);
 #define acpi_os_ioremap acpi_os_ioremap
 
-#define acpi_strict 1	/* No out-of-spec workarounds on RISC-V */
+#define acpi_strict 1		/* No out-of-spec workarounds on RISC-V */
+#define acpi_dt_hybrid 0	/* No DT-ACPI hybrid mode on RISC-V */
 extern int acpi_disabled;
 extern int acpi_noirq;
 extern int acpi_pci_disabled;
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index a03aa6f999d1..ae1d3d588c06 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -25,6 +25,7 @@
 #endif
 
 #ifdef CONFIG_ACPI
+#define acpi_dt_hybrid 0	/* No DT-ACPI hybrid mode on x86 */
 extern int acpi_lapic;
 extern int acpi_ioapic;
 extern int acpi_noirq;
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
index bed0791c17fc..0f9e22046e0a 100644
--- a/drivers/acpi/acpi_apd.c
+++ b/drivers/acpi/acpi_apd.c
@@ -263,5 +263,8 @@ static struct acpi_scan_handler apd_handler = {
 
 void __init acpi_apd_init(void)
 {
+	if (acpi_disabled)
+		return;
+
 	acpi_scan_add_handler(&apd_handler);
 }
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 1d7dfe4ee9a6..00469a4b8897 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -361,6 +361,9 @@ static struct acpi_scan_handler memory_device_handler = {
 
 void __init acpi_memory_hotplug_init(void)
 {
+	if (acpi_disabled)
+		return;
+
 	acpi_scan_add_handler(&memory_device_handler);
 }
 
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 00775b91bd41..f4ddd5e126e3 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -785,6 +785,9 @@ bool acpi_duplicate_processor_id(int proc_id)
 
 void __init acpi_processor_init(void)
 {
+	if (acpi_disabled)
+		return;
+
 	acpi_processor_check_duplicates();
 	acpi_scan_add_handler_with_hotplug(&processor_handler, "processor");
 	acpi_scan_add_handler(&processor_container_handler);
diff --git a/drivers/acpi/arm64/init.c b/drivers/acpi/arm64/init.c
index 7a47d8095a7d..9826c0b35715 100644
--- a/drivers/acpi/arm64/init.c
+++ b/drivers/acpi/arm64/init.c
@@ -4,6 +4,8 @@
 
 void __init acpi_arch_init(void)
 {
+	if (acpi_disabled)
+		return;
 	if (IS_ENABLED(CONFIG_ACPI_AGDI))
 		acpi_agdi_init();
 	if (IS_ENABLED(CONFIG_ACPI_APMT))
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 2ec095e2009e..1d5ea66cb99e 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1290,7 +1290,7 @@ void __init acpi_early_init(void)
 {
 	acpi_status status;
 
-	if (acpi_disabled)
+	if (acpi_disabled && !acpi_dt_hybrid)
 		return;
 
 	pr_info("Core revision %08x\n", ACPI_CA_VERSION);
@@ -1361,7 +1361,7 @@ void __init acpi_subsystem_init(void)
 {
 	acpi_status status;
 
-	if (acpi_disabled)
+	if (acpi_disabled && !acpi_dt_hybrid)
 		return;
 
 	status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE);
@@ -1494,7 +1494,7 @@ static int __init acpi_init(void)
 {
 	int result;
 
-	if (acpi_disabled) {
+	if (acpi_disabled && !acpi_dt_hybrid) {
 		pr_info("Interpreter disabled.\n");
 		return -ENODEV;
 	}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 530547cda8b2..4836286968e8 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2253,6 +2253,10 @@ static void acpi_default_enumeration(struct acpi_device *device)
 					     ACPI_RECONFIG_DEVICE_ADD, device);
 		return;
 	}
+
+	if (acpi_dt_hybrid)
+		return;
+
 	if (match_string(acpi_system_dev_ids, -1, acpi_device_hid(device)) >= 0) {
 		struct acpi_scan_system_dev *sd;
 
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 4286e4af1092..6aec547c0872 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -247,7 +247,7 @@ int __init_or_acpilib acpi_table_parse_entries_array(
 	int count;
 	u32 instance = 0;
 
-	if (acpi_disabled)
+	if (acpi_disabled && !acpi_dt_hybrid)
 		return -ENODEV;
 
 	if (!id)
@@ -330,7 +330,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
 {
 	struct acpi_table_header *table = NULL;
 
-	if (acpi_disabled)
+	if (acpi_disabled && !acpi_dt_hybrid)
 		return -ENODEV;
 
 	if (!id || !handler)
diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c
index 1da451582812..dc69342cdb38 100644
--- a/drivers/firmware/efi/efi-bgrt.c
+++ b/drivers/firmware/efi/efi-bgrt.c
@@ -31,7 +31,7 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
 	struct acpi_table_bgrt *bgrt = &bgrt_tab;
 	int mem_type;
 
-	if (acpi_disabled)
+	if (acpi_disabled && !acpi_dt_hybrid)
 		return;
 
 	if (!efi_enabled(EFI_MEMMAP) && !efi_enabled(EFI_PARAVIRT))
-- 
2.54.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox