* Re: [PATCH v2 1/3] dt-bindings: power: Add MediaTek MT6858 power domain controller
From: Nikolai Burov @ 2026-07-20 19:09 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Ulf Hansson, Matthias Brugger,
devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
linux-pm, Nikolai Burov
In-Reply-To: <20260720-vigorous-groovy-cassowary-9912d9@quoll>
On 7/20/26 8:05 AM, Krzysztof Kozlowski wrote:
> On Wed, Jul 15, 2026 at 04:54:05PM +0300, Nikolai Burov wrote:
>> Add a new compatible and document bindings for the power domain
>> controller of the MT6858 SoC.
>>
>> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>
> To provide review, please open and read the entire file.
>
>> Signed-off-by: Nikolai Burov <nikolai.burov@jolla.com>
>> ---
>> .../bindings/power/mediatek,power-controller.yaml | 21 +++++++++++++++++++-
>> include/dt-bindings/power/mediatek,mt6858-power.h | 23 ++++++++++++++++++++++
>> 2 files changed, 43 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
>> index 070c6e5666dc..d03e4a925163 100644
>> --- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
>> +++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
>> @@ -25,6 +25,7 @@ properties:
>> enum:
>> - mediatek,mt6735-power-controller
>> - mediatek,mt6795-power-controller
>> + - mediatek,mt6858-power-controller
>> - mediatek,mt6893-power-controller
>> - mediatek,mt8167-power-controller
>> - mediatek,mt8173-power-controller
>> @@ -56,7 +57,7 @@ properties:
>> faults while enabling or disabling a power domain.
>> For example, this may hold phandles to INFRACFG and SMI.
>> minItems: 1
>> - maxItems: 3
>> + maxItems: 6
>
> And the rest? Why does this device have flexible number of access
> controllers?
For mt6858, the "items" list I provided already overrides both minItems
and maxItems, so it has a fixed number (6) of access controllers.
The top-level constraints are intentionally broad so that the
SoC-specific constraints below, which all have minItems == maxItems,
don't contradict them. Those are missing for some SoCs, but isn't that
an existing weakness in the bindings?
Looking at the driver, apparently those missing SoCs are the ones that
only need infracfg. That's a single access controller. So they would
never have 3 or 2 items, only 1. This is not specified in the bindings
though.
If you mean that it can't stay like this, I could change the bindings to
add such a constraint for the remaining SoCs, provided that this is
allowed - theoretically it could break some hypothetical device trees
with excess items in access-controllers.
Alternatively, I guess one solution would be to add a minItems: 1 and
maxItems: 3 constraint for the remaining SoCs to keep their bindings
unaffected, even though that seems wrong from a HW point of view. But
I'm not sure if that is what you mean.
--
Best regards,
Nikolai
^ permalink raw reply
* Re: [PATCH v3] docs: dt: maintainer: Add Devicetree and OF maintainer profile document
From: Jonathan Corbet @ 2026-07-20 19:19 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Shuah Khan, devicetree, workflows, linux-doc,
linux-kernel
Cc: Krzysztof Kozlowski, Saravana Kannan
In-Reply-To: <20260720184040.9870-2-krzysztof.kozlowski@oss.qualcomm.com>
Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> writes:
> Document how Devicetree and Open Firmware maintainers handle their
> subsystem, especially focusing on two caveats:
>
> Devicetree subsystem handles patches with a minor difference comparing
> to other subsystems: while DT maintainers pick up OF code, they only
> provide review of DT bindings without applying these.
>
> All three DT bindings maintainers rely currently on Patchwork and due to
> enormous amount of emails per day, regardless how much DT maintainers
> try, they cannot read all the emails.
>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Conor Dooley <conor+dt@kernel.org>
> Cc: Saravana Kannan <saravanak@kernel.org>
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>
> ---
>
> I expect patch to be picked up by Rob, after review.
>
> Changes in v3:
> 1. Add also F: entry
>
> Changes in v2:
> 1. Correct typos and trailing white spaces.
> 2. Fix order of P: after C: in maintainers.
> ---
> .../process/maintainer-devicetree.rst | 70 +++++++++++++++++++
> MAINTAINERS | 3 +
> 2 files changed, 73 insertions(+)
> create mode 100644 Documentation/process/maintainer-devicetree.rst
You'll need to add this new file to index.rst as well.
Thanks,
jon
^ permalink raw reply
* Re: [PATCH 10/16] clk: Add support for clock nexus dt bindings
From: Frank Li @ 2026-07-20 19:53 UTC (permalink / raw)
To: Miquel Raynal
Cc: Stephen Boyd, Brian Masney, Michael Turquette, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thomas Gleixner,
Olivia Mackall, Herbert Xu, Jayesh Choudhary, David S. Miller,
Christian Marangi, Antoine Tenart, Geert Uytterhoeven,
Magnus Damm, Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang,
linux-clk, devicetree, linux-kernel, linux-crypto,
linux-renesas-soc, Herve Codina
In-Reply-To: <87jyr3gjbe.fsf@bootlin.com>
On Fri, Jul 10, 2026 at 01:44:53PM +0200, Miquel Raynal wrote:
> Hello,
>
> >> > Before I left my Reviewed-by, I should have double checked Sashiko. It
> >> > has several questions about this patch. The first is:
> >> >
> >> > Are there other places in the clock framework that need to transition to the
> >> > new map API to ensure assigned clocks work?
> >> >
> >> > For instance, assigned-clocks and assigned-clock-parents are parsed in
> >> > drivers/clk/clk-conf.c using of_parse_phandle_with_args(). If a device
> >> > specifies an assigned clock that routes through a nexus node, will it fail
> >> > to configure because the map is not traversed?
> >>
> >> The goal of the nexus node is to isolate what is behind. Are
> >> assigned-clocks et al. supposed to traverse a nexus node? I am tempted
> >> to say "no", but I'm open to discussing this ofc.
> >
> > Why would assigned-clocks not traverse the nexus node? If I'm a DT
> > author I would think any clock specifier should be routed properly
> > through the nexus node.
>
> Ok, giving this another thought, it may indeed be relevant to apply a
> default frequency which needs to traverse the nexus to be active. I've
> done the same change in the clk-conf.c file and tested with a dummy
> example, it just works.
Any progress about this? we are trying to use it at
https://lore.kernel.org/imx/20260629074734.3643227-2-chancel.liu@oss.nxp.com/
This is quite useful. Is it possible to split clock part to make it
progress?
Frank
>
> Thanks,
> Miquèl
^ permalink raw reply
* Re: [PATCH v2 3/4] dt-bindings: arm: qcom-soc: Validate nodes with fallbacks
From: Krzysztof Kozlowski @ 2026-07-20 20:03 UTC (permalink / raw)
To: Rob Herring
Cc: Bjorn Andersson, Konrad Dybcio, Krzysztof Kozlowski, Conor Dooley,
linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20260716211439.GA1290290-robh@kernel.org>
On 16/07/2026 23:14, Rob Herring wrote:
>> + - qcom,smmu-500
>> + - qcom,smmu-v2
>> + - qcom,snps-dwc3
>> + - qcom,ssc-block-bus
>> + - qcom,tcsr-mutex
>> + - qcom,trng
>> + - qcom,tsens-v0_1
>> + - qcom,tsens-v1
>> + - qcom,tsens-v2
>> + - qcom,ufshc
>> + - qcom,usb-hs-phy
>> + - qcom,usb-hsic-phy
>> + - qcom,usb-snps-hs-5nm-phy
>> + - qcom,usb-snps-hs-7nm-phy
>> + - simple-mfd
>> + - snps,dwmac
>> + - syscon
>
> You lost me here...
>
> This all looks pretty unmaintainable. Perhaps you should give up on old
> SoCs and only do something on new(er) ones:
Yeah, I think I over complicated this.
>
> select:
> properties:
> compatible:
> contains:
> pattern: '^qcom,'
>
> allOf:
> - if:
> properties:
> compatible:
> contains:
> pattern: '^qcom,.+foosoc'
> then:
> properties:
> compatible:
> contains:
> pattern: '^qcom,foosoc'
This seems to work well, I'll try more, thanks!
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3] docs: dt: maintainer: Add Devicetree and OF maintainer profile document
From: Krzysztof Kozlowski @ 2026-07-20 20:07 UTC (permalink / raw)
To: Jonathan Corbet, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Shuah Khan, devicetree, workflows, linux-doc, linux-kernel
Cc: Saravana Kannan
In-Reply-To: <87y0f531uz.fsf@trenco.lwn.net>
On 20/07/2026 21:19, Jonathan Corbet wrote:
>> I expect patch to be picked up by Rob, after review.
>>
>> Changes in v3:
>> 1. Add also F: entry
>>
>> Changes in v2:
>> 1. Correct typos and trailing white spaces.
>> 2. Fix order of P: after C: in maintainers.
>> ---
>> .../process/maintainer-devicetree.rst | 70 +++++++++++++++++++
>> MAINTAINERS | 3 +
>> 2 files changed, 73 insertions(+)
>> create mode 100644 Documentation/process/maintainer-devicetree.rst
>
> You'll need to add this new file to index.rst as well.
Hm, where? In docs/process/index.rst? None of the other maintainer
profiles are mentioned there.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v2 1/3] dt-bindings: power: Add MediaTek MT6858 power domain controller
From: Krzysztof Kozlowski @ 2026-07-20 20:09 UTC (permalink / raw)
To: nikolai.burov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Ulf Hansson
Cc: Matthias Brugger, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-pm, Nikolai Burov
In-Reply-To: <20260715-mt6858-pmdomain-v2-1-6293e87fc093@jolla.com>
On 15/07/2026 15:54, Nikolai Burov via B4 Relay wrote:
> From: Nikolai Burov <nikolai.burov@jolla.com>
>
> Add a new compatible and document bindings for the power domain
> controller of the MT6858 SoC.
>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> Signed-off-by: Nikolai Burov <nikolai.burov@jolla.com>
> ---
> .../bindings/power/mediatek,power-controller.yaml | 21 +++++++++++++++++++-
> include/dt-bindings/power/mediatek,mt6858-power.h | 23 ++++++++++++++++++++++
> 2 files changed, 43 insertions(+), 1 deletion(-)
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v2 1/3] dt-bindings: power: Add MediaTek MT6858 power domain controller
From: Krzysztof Kozlowski @ 2026-07-20 20:09 UTC (permalink / raw)
To: Nikolai Burov
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Ulf Hansson, Matthias Brugger,
devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
linux-pm, Nikolai Burov
In-Reply-To: <db76f500-0db5-4c5f-b4cb-60818702787e@abscue.de>
On 20/07/2026 21:09, Nikolai Burov wrote:
> On 7/20/26 8:05 AM, Krzysztof Kozlowski wrote:
>> On Wed, Jul 15, 2026 at 04:54:05PM +0300, Nikolai Burov wrote:
>>> Add a new compatible and document bindings for the power domain
>>> controller of the MT6858 SoC.
>>>
>>> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>>
>> To provide review, please open and read the entire file.
>>
>>> Signed-off-by: Nikolai Burov <nikolai.burov@jolla.com>
>>> ---
>>> .../bindings/power/mediatek,power-controller.yaml | 21 +++++++++++++++++++-
>>> include/dt-bindings/power/mediatek,mt6858-power.h | 23 ++++++++++++++++++++++
>>> 2 files changed, 43 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
>>> index 070c6e5666dc..d03e4a925163 100644
>>> --- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
>>> +++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
>>> @@ -25,6 +25,7 @@ properties:
>>> enum:
>>> - mediatek,mt6735-power-controller
>>> - mediatek,mt6795-power-controller
>>> + - mediatek,mt6858-power-controller
>>> - mediatek,mt6893-power-controller
>>> - mediatek,mt8167-power-controller
>>> - mediatek,mt8173-power-controller
>>> @@ -56,7 +57,7 @@ properties:
>>> faults while enabling or disabling a power domain.
>>> For example, this may hold phandles to INFRACFG and SMI.
>>> minItems: 1
>>> - maxItems: 3
>>> + maxItems: 6
>>
>> And the rest? Why does this device have flexible number of access
>> controllers?
>
> For mt6858, the "items" list I provided already overrides both minItems
> and maxItems, so it has a fixed number (6) of access controllers.
Correct, somehow I missed that part of the diff for this file.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3 phy-next 8/8] phy: lynx-10g: use RCW override procedure for dynamic protocol change
From: Vladimir Oltean @ 2026-07-20 20:12 UTC (permalink / raw)
To: Vinod Koul
Cc: linux-phy, devicetree, linuxppc-dev, linux-arm-kernel,
Ioana Ciornei, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel
In-Reply-To: <al5ODzYhpE-wHSSN@vaman>
Hi Vinod,
On Mon, Jul 20, 2026 at 10:04:23PM +0530, Vinod Koul wrote:
> On 20-07-26, 16:36, Vladimir Oltean wrote:
> > Up until this patch, the only protocol change supported was between
> > 1000Base-X/SGMII and 2500Base-X. The others require an RCW override
> > procedure which was lacking.
> >
> > Since now the guts driver provides the means of applying this procedure,
> > make use of it and remove any comment which mentioned the limitation.
>
> lgtm, is there any dependency. If not I can pick it
>
> --
> ~Vinod
There is no other direct dependency, but I need to send a v4 tomorrow
due to some valid Sashiko comments.
There is also this patch which seems to have been forgotten:
https://patchwork.kernel.org/project/linux-phy/patch/20260612125731.133330-1-vladimir.oltean@nxp.com/
Thanks,
Vladimir
^ permalink raw reply
* Re: [PATCH v3] docs: dt: maintainer: Add Devicetree and OF maintainer profile document
From: Rob Herring @ 2026-07-20 20:12 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet, Shuah Khan,
devicetree, workflows, linux-doc, linux-kernel, Saravana Kannan
In-Reply-To: <20260720184040.9870-2-krzysztof.kozlowski@oss.qualcomm.com>
On Mon, Jul 20, 2026 at 1:40 PM Krzysztof Kozlowski
<krzysztof.kozlowski@oss.qualcomm.com> wrote:
>
> Document how Devicetree and Open Firmware maintainers handle their
> subsystem, especially focusing on two caveats:
>
> Devicetree subsystem handles patches with a minor difference comparing
> to other subsystems: while DT maintainers pick up OF code, they only
> provide review of DT bindings without applying these.
>
> All three DT bindings maintainers rely currently on Patchwork and due to
> enormous amount of emails per day, regardless how much DT maintainers
> try, they cannot read all the emails.
>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Conor Dooley <conor+dt@kernel.org>
> Cc: Saravana Kannan <saravanak@kernel.org>
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>
> ---
>
> I expect patch to be picked up by Rob, after review.
>
> Changes in v3:
> 1. Add also F: entry
>
> Changes in v2:
> 1. Correct typos and trailing white spaces.
> 2. Fix order of P: after C: in maintainers.
> ---
> .../process/maintainer-devicetree.rst | 70 +++++++++++++++++++
> MAINTAINERS | 3 +
> 2 files changed, 73 insertions(+)
> create mode 100644 Documentation/process/maintainer-devicetree.rst
>
> diff --git a/Documentation/process/maintainer-devicetree.rst b/Documentation/process/maintainer-devicetree.rst
> new file mode 100644
> index 000000000000..d8ffe752bf5d
> --- /dev/null
> +++ b/Documentation/process/maintainer-devicetree.rst
> @@ -0,0 +1,70 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +======================================
> +Devicetree and Open Firmware Subsystem
> +======================================
> +
> +Other Process Documents
> +-----------------------
> +
> +Please see the documents in Documentation/devicetree/bindings/ for information
> +on how to write proper Devicetree bindings and how to submit patches.
> +
> +Patch Review and Handling
> +-------------------------
> +
> +Patches handled by Devicetree maintainers are processed differently depending
> +on the patch type:
> +
> +1. Core OF driver code, e.g. drivers/of/:
> + patches are reviewed and applied by DT maintainers.
> +
> +2. Devicetree bindings:
> + patches are reviewed by DT maintainers but, except in certain cases, should
> + be applied by subsystem maintainers. See also *For kernel maintainers* in
> + Documentation/devicetree/bindings/submitting-patches.rst.
I would reword:
patches are reviewed by DT maintainers, but should be applied by
subsystem maintainers except in certain cases.
> +
> +3. DTS and drivers:
> + DT maintainers might provide comments, but review is generally not expected.
For DTS, we expect to pass schema checks or at least not add new warnings.
I can address these 2 when applying.
Rob
^ permalink raw reply
* [PATCH 0/4] EDAC/altera: Add support for Agilex5 platform
From: Dinh Nguyen @ 2026-07-20 20:14 UTC (permalink / raw)
To: bp, tony.luck
Cc: dinguyen, rounakdas2025, niravkumar.l.rabara, linux-edac,
linux-kernel, robh, krzk+dt, conor+dt, devicetree
This series add preliminary EDAC support for the Agilex5 platform. The
EDAC module on the Agilex5 is a bit different from the previous Arria10
and Stratix10 platforms in that it has the full 7 interrupts.
global_sbe - aggregate single-bit error (chained, drives IRQ domain)
global_dbe - aggregate double-bit error (chained; DBE is no longer
delivered exclusively through Asynchronous SError)
io96b0 - IO96B0 DRAM controller ECC
io96b1 - IO96B1 DRAM controller ECC
sdm_qspi_sbe - SDM QSPI single-bit error
sdm_qspi_dbe - SDM QSPI double-bit error
sdm_seu - SDM single-event-upset
patch 1/4 : dt-bindings: edac: altera: agilex5: document new edac support
Introduce a new dt binding "altr,socfpga-agilex5-ecc-manager" that is
specific to the Agilex5 platform. Document the 7 interrupts.
Patch 2/4 : EDAC/altera: use flag to differentiate 64-bit platforms
Use match data to provide a method to differentiate different platforms.
Patch 3/4 : EDAC/altera: Add support for Agilex5 ECC manager
Modifies the Altera EDAC driver to support the Agilex5 platform.
Patch 4/4 : arm64: dts: socfpga: agilex5: add support for the ECC manager
Populates the base Agilex5 DTSI wit the EDAC IP.
Dinh Nguyen (4):
dt-bindings: edac: altera: agilex5: document new edac support
EDAC/altera: use flag to differentiate 64-bit platforms
EDAC/altera: Add support for Agilex5 ECC manager
arm64: dts: socfpga: agilex5: add support for the ECC manager
.../edac/altr,socfpga-ecc-manager.yaml | 23 +++-
.../arm64/boot/dts/intel/socfpga_agilex5.dtsi | 68 ++++++++++++
drivers/edac/altera_edac.c | 100 ++++++++++++++++--
drivers/edac/altera_edac.h | 34 +++++-
4 files changed, 212 insertions(+), 13 deletions(-)
--
2.42.0.411.g813d9a9188
^ permalink raw reply
* [PATCH 1/4] dt-bindings: edac: altera: agilex5: document new edac support
From: Dinh Nguyen @ 2026-07-20 20:14 UTC (permalink / raw)
To: bp, tony.luck
Cc: dinguyen, rounakdas2025, niravkumar.l.rabara, linux-edac,
linux-kernel, robh, krzk+dt, conor+dt, devicetree
In-Reply-To: <20260720201425.1538771-1-dinguyen@kernel.org>
The Agilex5 EDAC module supports ECC on a few additional peripherals. Along
with support for ocram, ethernet and USB, the Agilex5 EDAC adds support for
SDM QSPI, CRAM SEU and IO96B.
The Agilex5 EDAC also exposes up to 7 named interrupts on the manager
node. global_sbe and global_dbe are aggregate single/double-bit error
interrupts that fan-out through the manager's IRQ domain to the child
peripheral ECCs. The remaining named interrupts are routed directly from
dedicated controllers (IO96B memory controllers and Secure Device Manager)
to the GIC.
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
---
.../edac/altr,socfpga-ecc-manager.yaml | 23 ++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/edac/altr,socfpga-ecc-manager.yaml b/Documentation/devicetree/bindings/edac/altr,socfpga-ecc-manager.yaml
index 136e8fccd429a..2ccb0f2163185 100644
--- a/Documentation/devicetree/bindings/edac/altr,socfpga-ecc-manager.yaml
+++ b/Documentation/devicetree/bindings/edac/altr,socfpga-ecc-manager.yaml
@@ -22,6 +22,9 @@ properties:
- items:
- const: altr,socfpga-s10-ecc-manager
- const: altr,socfpga-a10-ecc-manager
+ - items:
+ - const: altr,socfpga-agilex5-ecc-manager
+ - const: altr,socfpga-a10-ecc-manager
- const: altr,socfpga-a10-ecc-manager
- const: altr,socfpga-ecc-manager
@@ -33,7 +36,25 @@ properties:
interrupts:
minItems: 1
- maxItems: 2
+ items:
+ - description: Global single-bit error
+ - description: Global double-bit error
+ - description: IO96B0 DRAM controller error
+ - description: IO96B1 DRAM controller error
+ - description: SDM QSPI single-bit error
+ - description: SDM QSPI double-bit error
+ - description: SDM single-event
+
+ interrupt-names:
+ minItems: 1
+ items:
+ - const: global_sbe
+ - const: global_dbe
+ - const: io96b0
+ - const: io96b1
+ - const: sdm_qspi_sbe
+ - const: sdm_qspi_dbe
+ - const: sdm_seu
interrupt-controller: true
--
2.42.0.411.g813d9a9188
^ permalink raw reply related
* [PATCH 2/4] EDAC/altera: use flag to differentiate 64-bit platforms
From: Dinh Nguyen @ 2026-07-20 20:14 UTC (permalink / raw)
To: bp, tony.luck
Cc: dinguyen, rounakdas2025, niravkumar.l.rabara, linux-edac,
linux-kernel, robh, krzk+dt, conor+dt, devicetree
In-Reply-To: <20260720201425.1538771-1-dinguyen@kernel.org>
In commit (d4486fc3098e "EDAC/altera: Use ECC manager compatible to select
A10/S10 IRQ layout"), it added a way to only differentiate Stratix10 from a
32-bit platform. In preparation to add support for Agilex5, it needs a way to
make a further differentiation.
Make use of the driver match data to hold a flag for different platforms,
specifically Stratix10 and Agilex5.
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
---
drivers/edac/altera_edac.c | 17 +++++++++--------
drivers/edac/altera_edac.h | 5 ++++-
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 777ba6efcc542..8a5b08e0d0583 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1507,7 +1507,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
int edac_idx, rc;
struct device_node *np;
const struct edac_device_prv_data *prv = &a10_sdmmceccb_data;
- bool is_s10 = device->edac->is_s10;
+ unsigned long flag = {unsigned long)device->edac->flag;
rc = altr_check_ecc_deps(device);
if (rc)
@@ -1555,7 +1555,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
*/
/* Using compatibles to determine the IRQ Index */
- if (is_s10)
+ if (flag == SOCFPGA_S10)
altdev->sb_irq = irq_of_parse_and_map(np, 1);
else
altdev->sb_irq = irq_of_parse_and_map(np, 2);
@@ -1573,7 +1573,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
goto err_release_group_1;
}
- if (is_s10) {
+ if (flag == SOCFPGA_S10) {
/* Use IRQ to determine SError origin instead of assigning IRQ */
rc = of_property_read_u32_index(np, "interrupts", 1, &altdev->db_irq);
if (rc) {
@@ -1979,7 +1979,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
goto err_release_group1;
}
- if (edac->is_s10) {
+ if (edac->flag == SOCFPGA_S10) {
/* Use IRQ to determine SError origin instead of assigning IRQ */
rc = of_property_read_u32_index(np, "interrupts", 0, &altdev->db_irq);
if (rc) {
@@ -2125,7 +2125,7 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, edac);
INIT_LIST_HEAD(&edac->a10_ecc_devices);
- edac->is_s10 = !!device_get_match_data(&pdev->dev);
+ edac->flag = (unsigned long)device_get_match_data(&pdev->dev);
edac->ecc_mgr_map =
altr_sysmgr_regmap_lookup_by_phandle(pdev->dev.of_node,
@@ -2158,8 +2158,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
irq_set_chained_handler_and_data(edac->sb_irq,
altr_edac_a10_irq_handler,
edac);
- if (edac->is_s10)
- {
+
+ if (edac->flag == SOCFPGA_S10) {
int dberror, err_addr;
edac->panic_notifier.notifier_call = s10_edac_dberr_handler;
@@ -2210,7 +2210,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
static const struct of_device_id altr_edac_a10_of_match[] = {
{ .compatible = "altr,socfpga-a10-ecc-manager" },
- { .compatible = "altr,socfpga-s10-ecc-manager", .data = (void *)1 },
+ { .compatible = "altr,socfpga-s10-ecc-manager",
+ .data = (void *)SOCFPGA_S10 },
{},
};
MODULE_DEVICE_TABLE(of, altr_edac_a10_of_match);
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index 9387056fd65e3..74ab7bfc3e748 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -351,6 +351,9 @@ struct altr_sdram_mc_data {
#define ECC_READ_EOVR 0x2
#define ECC_READ_EDOVR 0x3
+#define SOCFPGA_S10 0x1
+#define SOCFPGA_AGILEX5 0x2
+
struct altr_edac_device_dev;
struct edac_device_prv_data {
@@ -394,7 +397,7 @@ struct altr_arria10_edac {
struct irq_chip irq_chip;
struct list_head a10_ecc_devices;
struct notifier_block panic_notifier;
- bool is_s10;
+ unsigned long flag;
};
#endif /* #ifndef _ALTERA_EDAC_H */
--
2.42.0.411.g813d9a9188
^ permalink raw reply related
* [PATCH 3/4] EDAC/altera: Add support for Agilex5 ECC manager
From: Dinh Nguyen @ 2026-07-20 20:14 UTC (permalink / raw)
To: bp, tony.luck
Cc: dinguyen, rounakdas2025, niravkumar.l.rabara, linux-edac,
linux-kernel, robh, krzk+dt, conor+dt, devicetree
In-Reply-To: <20260720201425.1538771-1-dinguyen@kernel.org>
Add a new compatible "altr,socfpga-agilex5-ecc-manager" to the Arria10
EDAC manager driver. Unlike Stratix10/Agilex7, the Agilex5 ECC manager
exposes up to 7 named interrupts on its DT node:
global_sbe - aggregate single-bit error (chained, drives IRQ domain)
global_dbe - aggregate double-bit error (chained; DBE is no longer
delivered exclusively through Asynchronous SError)
io96b0 - IO96B0 DRAM controller ECC
io96b1 - IO96B1 DRAM controller ECC
sdm_qspi_sbe - SDM QSPI single-bit error
sdm_qspi_dbe - SDM QSPI double-bit error
sdm_seu - SDM single-event-upset
On Agilex5, retrieve all seven interrupts by name via
platform_get_irq_byname_optional() and stash them in a new
agilex5_irqs[] array on struct altr_arria10_edac so subsequent
peripheral support (IO96B, SDM QSPI, CRAM SEU) can consume them without
re-parsing the DT. Only global_sbe is mandatory; the rest are optional.
global_sbe is wired up as the chained SBE handler (replacing the legacy
index-0 lookup). When present, global_dbe is hooked into the same
altr_edac_a10_irq_handler() so that the existing sb_irq/db_irq demux
routes DBE events through the manager's IRQ domain. The SError-based
panic notifier path is preserved as a fall-back.
Legacy A10/S10 probe paths are unchanged.
Assisted-by: Cursor:claude-sonnet-4.7
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
---
drivers/edac/altera_edac.c | 85 ++++++++++++++++++++++++++++++++++++--
drivers/edac/altera_edac.h | 29 +++++++++++++
2 files changed, 110 insertions(+), 4 deletions(-)
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 8a5b08e0d0583..44da63ef5d71e 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1507,7 +1507,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
int edac_idx, rc;
struct device_node *np;
const struct edac_device_prv_data *prv = &a10_sdmmceccb_data;
- unsigned long flag = {unsigned long)device->edac->flag;
+ unsigned long flag = (unsigned long)device->edac->flag;
rc = altr_check_ecc_deps(device);
if (rc)
@@ -2111,11 +2111,63 @@ static int s10_edac_dberr_handler(struct notifier_block *this,
return NOTIFY_DONE;
}
+/*
+ * Ordered table of named interrupts published by an
+ * "altr,socfpga-agilex5-ecc-manager" device tree node. Indices match
+ * enum altr_agilex5_irq_idx. Only "global_sbe" is mandatory; the rest are
+ * optional so platforms can omit interrupts for unused subsystems.
+ */
+static const char * const altr_agilex5_irq_names[ALTR_AGILEX5_NUM_IRQS] = {
+ [ALTR_AGILEX5_IRQ_GLOBAL_SBE] = "global_sbe",
+ [ALTR_AGILEX5_IRQ_GLOBAL_DBE] = "global_dbe",
+ [ALTR_AGILEX5_IRQ_IO96B0] = "io96b0",
+ [ALTR_AGILEX5_IRQ_IO96B1] = "io96b1",
+ [ALTR_AGILEX5_IRQ_SDM_QSPI_SBE] = "sdm_qspi_sbe",
+ [ALTR_AGILEX5_IRQ_SDM_QSPI_DBE] = "sdm_qspi_dbe",
+ [ALTR_AGILEX5_IRQ_SDM_SEU] = "sdm_seu",
+};
+
+/*
+ * Populate edac->agilex5_irqs[] from the named interrupts on the manager
+ * platform device. Missing optional interrupts are stored as a negative
+ * errno (-ENXIO) so that subsequent feature code can probe whether the
+ * resource exists. global_sbe is required because it drives the manager's
+ * IRQ domain dispatch path.
+ *
+ * platform_get_irq_byname_optional() can return -EPROBE_DEFER when the
+ * parent irqchip (e.g. the GIC) is not yet probed. Propagate that error
+ * up so the kernel re-tries the probe later instead of permanently
+ * disabling the named interrupt.
+ */
+static int altr_agilex5_get_named_irqs(struct platform_device *pdev,
+ struct altr_arria10_edac *edac)
+{
+ int i, irq;
+
+ for (i = 0; i < ALTR_AGILEX5_NUM_IRQS; i++) {
+ irq = platform_get_irq_byname_optional(pdev,
+ altr_agilex5_irq_names[i]);
+ if (irq == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ edac->agilex5_irqs[i] = irq > 0 ? irq : -ENXIO;
+ }
+
+ if (edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_SBE] < 0) {
+ dev_err(&pdev->dev,
+ "Agilex5 ECC manager missing required 'global_sbe' interrupt\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
/****************** Arria 10 EDAC Probe Function *********************/
static int altr_edac_a10_probe(struct platform_device *pdev)
{
struct altr_arria10_edac *edac;
struct device_node *child;
+ int rc;
edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL);
if (!edac)
@@ -2151,14 +2203,31 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
return -ENOMEM;
}
- edac->sb_irq = platform_get_irq(pdev, 0);
- if (edac->sb_irq < 0)
- return edac->sb_irq;
+ if (edac->flag == SOCFPGA_AGILEX5) {
+ rc = altr_agilex5_get_named_irqs(pdev, edac);
+ if (rc)
+ return rc;
+
+ edac->sb_irq = edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_SBE];
+ } else {
+ edac->sb_irq = platform_get_irq(pdev, 0);
+ if (edac->sb_irq < 0)
+ return edac->sb_irq;
+ }
irq_set_chained_handler_and_data(edac->sb_irq,
altr_edac_a10_irq_handler,
edac);
+ /*
+ * Unlike Stratix10/Agilex7 (which deliver uncorrectable errors as
+ * Asynchronous SError), Agilex5 routes the global double-bit error
+ * through a dedicated SPI ("global_dbe"). Hook it into the same
+ * chained handler so the existing sb_irq/db_irq demux in
+ * altr_edac_a10_irq_handler() routes DBE events through the manager's
+ * IRQ domain. The panic notifier below is still registered as a
+ * fall-back for any DBEs that escape to SError.
+ */
if (edac->flag == SOCFPGA_S10) {
int dberror, err_addr;
@@ -2181,6 +2250,12 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
regmap_write(edac->ecc_mgr_map,
S10_SYSMGR_UE_ADDR_OFST, 0);
}
+ } else if (edac->flag == SOCFPGA_AGILEX5 &&
+ edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_DBE] >= 0) {
+ edac->db_irq = edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_DBE];
+ irq_set_chained_handler_and_data(edac->db_irq,
+ altr_edac_a10_irq_handler,
+ edac);
} else {
edac->db_irq = platform_get_irq(pdev, 1);
if (edac->db_irq < 0)
@@ -2212,6 +2287,8 @@ static const struct of_device_id altr_edac_a10_of_match[] = {
{ .compatible = "altr,socfpga-a10-ecc-manager" },
{ .compatible = "altr,socfpga-s10-ecc-manager",
.data = (void *)SOCFPGA_S10 },
+ { .compatible = "altr,socfpga-agilex5-ecc-manager",
+ .data = (void *)SOCFPGA_AGILEX5 },
{},
};
MODULE_DEVICE_TABLE(of, altr_edac_a10_of_match);
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index 74ab7bfc3e748..30e35da7eb6a1 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -326,6 +326,27 @@ struct altr_sdram_mc_data {
#define S10_DDR0_IRQ_MASK BIT(16)
#define S10_DBE_IRQ_MASK 0x3FFFE
+/************* Agilex5 Defines **************/
+/*
+ * The Agilex5 ECC manager exposes up to 7 named interrupts on the manager
+ * node. global_sbe and global_dbe are aggregate single/double-bit error
+ * interrupts that fan-out through the manager's IRQ domain to the child
+ * peripheral ECCs. The remaining named interrupts are routed directly from
+ * dedicated controllers (IO96B memory controllers and Secure Device Manager)
+ * to the GIC.
+ */
+#define ALTR_AGILEX5_NUM_IRQS 7
+
+enum altr_agilex5_irq_idx {
+ ALTR_AGILEX5_IRQ_GLOBAL_SBE,
+ ALTR_AGILEX5_IRQ_GLOBAL_DBE,
+ ALTR_AGILEX5_IRQ_IO96B0,
+ ALTR_AGILEX5_IRQ_IO96B1,
+ ALTR_AGILEX5_IRQ_SDM_QSPI_SBE,
+ ALTR_AGILEX5_IRQ_SDM_QSPI_DBE,
+ ALTR_AGILEX5_IRQ_SDM_SEU,
+};
+
/* Define ECC Block Offsets for peripherals */
#define ECC_BLK_ADDRESS_OFST 0x40
#define ECC_BLK_RDATA0_OFST 0x44
@@ -398,6 +419,14 @@ struct altr_arria10_edac {
struct list_head a10_ecc_devices;
struct notifier_block panic_notifier;
unsigned long flag;
+
+ /*
+ * Agilex5 ECC manager supports up to ALTR_AGILEX5_NUM_IRQS named
+ * interrupts. Entries are indexed by enum altr_agilex5_irq_idx and
+ * hold the Linux virtual IRQ number, or a negative errno when the
+ * corresponding interrupt was not provided in the device tree.
+ */
+ int agilex5_irqs[ALTR_AGILEX5_NUM_IRQS];
};
#endif /* #ifndef _ALTERA_EDAC_H */
--
2.42.0.411.g813d9a9188
^ permalink raw reply related
* [PATCH 4/4] arm64: dts: socfpga: agilex5: add support for the ECC manager
From: Dinh Nguyen @ 2026-07-20 20:14 UTC (permalink / raw)
To: bp, tony.luck
Cc: dinguyen, rounakdas2025, niravkumar.l.rabara, linux-edac,
linux-kernel, robh, krzk+dt, conor+dt, devicetree
In-Reply-To: <20260720201425.1538771-1-dinguyen@kernel.org>
Add the EDAC device to the base Agilex5 platform. Add OCRAM and Ethernet ECC
device support to the Agilex5 platform.
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
---
.../arm64/boot/dts/intel/socfpga_agilex5.dtsi | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi
index b06c6d5d60eed..f30d476683b4a 100644
--- a/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi
+++ b/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi
@@ -370,6 +370,74 @@ dmac1: dma-controller@10000 {
};
};
+ eccmgr {
+ compatible = "altr,socfpga-agilex5-ecc-manager",
+ "altr,socfpga-a10-ecc-manager";
+ altr,sysmgr-syscon = <&sysmgr>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 95 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 120 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "global_sbe", "global_dbe", "io96b0" , "io96b1",
+ "sdm_qspi_sbe", "sdm_qspi_dbe", "sdm_seu";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ ranges;
+
+ ocram-ecc@108cc000 {
+ compatible = "altr,socfpga-a10-ocram-ecc";
+ reg = <0x108cc000 0x100>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH>, <33 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ emac0-rx-ecc@108c0000 {
+ compatible = "altr,socfpga-eth-mac-ecc";
+ reg = <0x108c0000 0x100>;
+ altr,ecc-parent = <&gmac0>;
+ interrupts = <4 IRQ_TYPE_LEVEL_HIGH>, <38 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ emac0-tx-ecc@108c0400 {
+ compatible = "altr,socfpga-eth-mac-ecc";
+ reg = <0x108c0400 0x100>;
+ altr,ecc-parent = <&gmac0>;
+ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, <37 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ emac1-rx-ecc@108c0800 {
+ compatible = "altr,socfpga-eth-mac-ecc";
+ reg = <0x108c0800 0x100>;
+ altr,ecc-parent = <&gmac1>;
+ interrupts = <6 IRQ_TYPE_LEVEL_HIGH>, <38 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ emac1-tx-ecc@108c0c00 {
+ compatible = "altr,socfpga-eth-mac-ecc";
+ reg = <0x108c0c00 0x100>;
+ altr,ecc-parent = <&gmac1>;
+ interrupts = <7 IRQ_TYPE_LEVEL_HIGH>, <39 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ emac2-rx-ecc@108c1000 {
+ compatible = "altr,socfpga-eth-mac-ecc";
+ reg = <0x108c1000 0x100>;
+ altr,ecc-parent = <&gmac2>;
+ interrupts = <8 IRQ_TYPE_LEVEL_HIGH>, <40 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ emac2-tx-ecc@108c1400 {
+ compatible = "altr,socfpga-eth-mac-ecc";
+ reg = <0x108c1400 0x100>;
+ altr,ecc-parent = <&gmac2>;
+ interrupts = <9 IRQ_TYPE_LEVEL_HIGH>, <41 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
rst: rstmgr@10d11000 {
compatible = "altr,stratix10-rst-mgr", "altr,rst-mgr";
reg = <0x10d11000 0x1000>;
--
2.42.0.411.g813d9a9188
^ permalink raw reply related
* Re: [PATCH v3] docs: dt: maintainer: Add Devicetree and OF maintainer profile document
From: Jonathan Corbet @ 2026-07-20 20:20 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Shuah Khan, devicetree, workflows, linux-doc,
linux-kernel
Cc: Saravana Kannan
In-Reply-To: <3e797ffc-8cf6-437c-81f2-9f82d946d042@oss.qualcomm.com>
Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> writes:
> On 20/07/2026 21:19, Jonathan Corbet wrote:
>>> I expect patch to be picked up by Rob, after review.
>>>
>>> Changes in v3:
>>> 1. Add also F: entry
>>>
>>> Changes in v2:
>>> 1. Correct typos and trailing white spaces.
>>> 2. Fix order of P: after C: in maintainers.
>>> ---
>>> .../process/maintainer-devicetree.rst | 70 +++++++++++++++++++
>>> MAINTAINERS | 3 +
>>> 2 files changed, 73 insertions(+)
>>> create mode 100644 Documentation/process/maintainer-devicetree.rst
>>
>> You'll need to add this new file to index.rst as well.
>
> Hm, where? In docs/process/index.rst? None of the other maintainer
> profiles are mentioned there.
Sigh...I stand corrected. I'd forgotten that we merged the
maintainers-profile-toc Sphinx magic that picks them all up from the
MAINTAINERS file entries.
Sorry for the noise,
jon
^ permalink raw reply
* Re: [PATCH] Documentation/devicetree/bindings: update Sudeep Holla's email address
From: Sudeep Holla @ 2026-07-20 20:21 UTC (permalink / raw)
To: Laszlo Ersek
Cc: Conor Dooley, Cristian Marussi, Jassi Brar, Krzysztof Kozlowski,
Linus Walleij, Liviu Dudau, Lorenzo Pieralisi, Rob Herring,
arm-scmi, devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <20260720160235.36592-1-laszlo.ersek@arm.com>
On Mon, Jul 20, 2026 at 06:02:30PM +0200, Laszlo Ersek wrote:
> MAINTAINERS disagrees with Documentation/devicetree/bindings on Sudeep's
> email address; fix the latter.
>
$subject is bit of a deviation from normal practice. Otherwise looks
good to me and thanks for updating it.
Acked-by: Sudeep Holla <sudeep.holla@kernel.org>
--
Regards,
Sudeep
^ permalink raw reply
* Re: [PATCH 1/4] dt-bindings: edac: altera: agilex5: document new edac support
From: sashiko-bot @ 2026-07-20 20:21 UTC (permalink / raw)
To: Dinh Nguyen; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260720201425.1538771-2-dinguyen@kernel.org>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Removing `maxItems: 2` from the global `interrupts` property to allow up to 7 items relaxes constraints for older hardware generations, allowing them to improperly specify up to 7 interrupts and bypass schema validation.
- [Medium] The `interrupt-names` property is introduced for the new `altr,socfpga-agilex5-ecc-manager` variant, but it is not conditionally enforced as a required property for Agilex5.
--
--- Patch [1]: [PATCH 1/4] dt-bindings: edac: altera: agilex5: document new edac support ---
commit d266055949125966c496511b166440e55892f101
Author: Dinh Nguyen <dinguyen@kernel.org>
dt-bindings: edac: altera: agilex5: document new edac support
This commit adds EDAC support for Agilex5 peripherals, including SDM QSPI,
CRAM SEU, and IO96B. It updates the device tree bindings to include the new
compatible string and expands the interrupts and interrupt-names properties
to accommodate up to 7 interrupts for the new hardware variant.
> diff --git a/Documentation/devicetree/bindings/edac/altr,socfpga-ecc-manager.yaml b/Documentation/devicetree/bindings/edac/altr,socfpga-ecc-manager.yaml
> index 136e8fccd429a..2ccb0f2163185 100644
> --- a/Documentation/devicetree/bindings/edac/altr,socfpga-ecc-manager.yaml
> +++ b/Documentation/devicetree/bindings/edac/altr,socfpga-ecc-manager.yaml
[ ... ]
> @@ -33,7 +36,25 @@ properties:
>
> interrupts:
> minItems: 1
> - maxItems: 2
> + items:
> + - description: Global single-bit error
> + - description: Global double-bit error
> + - description: IO96B0 DRAM controller error
> + - description: IO96B1 DRAM controller error
> + - description: SDM QSPI single-bit error
> + - description: SDM QSPI double-bit error
> + - description: SDM single-event
[Severity: Medium]
Does removing the maxItems: 2 constraint here allow older hardware generations
(like S10 or A10) to mistakenly define up to 7 interrupts and silently pass
schema validation?
Should the binding use an allOf / if-then block to enforce maxItems: 2
specifically for the older compatibles?
> +
> + interrupt-names:
> + minItems: 1
> + items:
> + - const: global_sbe
> + - const: global_dbe
> + - const: io96b0
> + - const: io96b1
> + - const: sdm_qspi_sbe
> + - const: sdm_qspi_dbe
> + - const: sdm_seu
[Severity: Medium]
Will this allow device trees for Agilex5 to silently pass schema validation
even if they omit the interrupt-names entirely?
Should there be a conditional block enforcing interrupt-names as a required
property specifically for the altr,socfpga-agilex5-ecc-manager variant?
>
> interrupt-controller: true
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720201425.1538771-1-dinguyen@kernel.org?part=1
^ permalink raw reply
* [PATCH] dt-bindings: extcon: ti,extcon-palmas: Convert to DT schema
From: Bhargav Joshi @ 2026-07-20 20:21 UTC (permalink / raw)
To: MyungJoo Ham, Chanwoo Choi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Roger Quadros
Cc: linux-kernel, devicetree, goledhruva, m-chawdhry, daniel.baluta,
simona.toaca, j.bhargav.u
Convert Texas Instruments Palmas USB Comparator from legacy text to DT
schema.
Signed-off-by: Bhargav Joshi <j.bhargav.u@gmail.com>
---
.../devicetree/bindings/extcon/extcon-palmas.txt | 22 -------
.../bindings/extcon/ti,extcon-palmas.yaml | 74 ++++++++++++++++++++++
2 files changed, 74 insertions(+), 22 deletions(-)
diff --git a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
deleted file mode 100644
index f61d5af44a27..000000000000
--- a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-EXTCON FOR PALMAS/TWL CHIPS
-
-PALMAS USB COMPARATOR
-Required Properties:
- - compatible: should contain one of:
- * "ti,palmas-usb-vid".
- * "ti,twl6035-usb-vid".
- * "ti,palmas-usb" (DEPRECATED - use "ti,palmas-usb-vid").
- * "ti,twl6035-usb" (DEPRECATED - use "ti,twl6035-usb-vid").
-
-Optional Properties:
- - ti,wakeup : To enable the wakeup comparator in probe
- - ti,enable-id-detection: Perform ID detection. If id-gpio is specified
- it performs id-detection using GPIO else using OTG core.
- - ti,enable-vbus-detection: Perform VBUS detection.
- - id-gpio: gpio for GPIO ID detection. See gpio binding.
- - debounce-delay-ms: debounce delay for GPIO ID pin in milliseconds.
-
-palmas-usb {
- compatible = "ti,twl6035-usb", "ti,palmas-usb";
- ti,wakeup;
-};
diff --git a/Documentation/devicetree/bindings/extcon/ti,extcon-palmas.yaml b/Documentation/devicetree/bindings/extcon/ti,extcon-palmas.yaml
new file mode 100644
index 000000000000..0bcd8df79414
--- /dev/null
+++ b/Documentation/devicetree/bindings/extcon/ti,extcon-palmas.yaml
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/extcon/ti,extcon-palmas.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments PALMAS USB COMPARATOR
+
+maintainers:
+ - Roger Quadros <rogerq@ti.com>
+ - Bhargav Joshi <j.bhargav.u@gmail.com>
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - ti,palmas-usb-vid
+ - ti,twl6035-usb-vid
+ - enum:
+ - ti,palmas-usb
+ - ti,twl6035-usb
+ deprecated: true
+
+ ti,wakeup:
+ type: boolean
+ description:
+ To enable the wakeup comparator in probe.
+
+ ti,enable-id-detection:
+ type: boolean
+ description:
+ Perform ID detection. If id-gpios is specified it performs ID detection
+ using GPIO, otherwise using the OTG core.
+
+ ti,enable-vbus-detection:
+ type: boolean
+ description:
+ Perform VBUS detection.
+
+ id-gpios:
+ maxItems: 1
+
+ id-gpio:
+ maxItems: 1
+ deprecated: true
+
+ vbus-gpios:
+ maxItems: 1
+
+ vbus-gpio:
+ maxItems: 1
+ deprecated: true
+
+ debounce-delay-ms:
+ description:
+ Debounce delay for GPIO ID pin in milliseconds.
+ default: 20
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ palmas_usb {
+ compatible = "ti,palmas-usb-vid";
+ ti,wakeup;
+ ti,enable-id-detection;
+ ti,enable-vbus-detection;
+ id-gpios = <&palmas_gpio 0 GPIO_ACTIVE_HIGH>;
+ };
---
base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
change-id: 20260721-ti-extcon-palmas-2eeed9a6ddb3
Best regards,
--
Bhargav
^ permalink raw reply related
* Re: [PATCH 3/4] EDAC/altera: Add support for Agilex5 ECC manager
From: sashiko-bot @ 2026-07-20 20:25 UTC (permalink / raw)
To: Dinh Nguyen; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260720201425.1538771-4-dinguyen@kernel.org>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] A flawed if/else chain causes Agilex5 to incorrectly fall through to legacy A10 logic if the optional `global_dbe` interrupt is missing, leading to probe failure or interrupt hijacking, and prevents registration of the intended panic notifier fallback.
Pre-existing issues:
- [High] Probe error paths fail to unregister the IRQ domain and chained handlers, leading to Resource Leaks and Use-After-Free.
- [High] The platform driver lacks a .remove callback, causing severe Use-After-Frees on module unbind.
--
--- Patch [3]: [PATCH 3/4] EDAC/altera: Add support for Agilex5 ECC manager ---
commit fe27bbb114924237edb349c2779f0fc2899da926
Author: Dinh Nguyen <dinguyen@kernel.org>
EDAC/altera: Add support for Agilex5 ECC manager
This commit adds support for the Agilex5 ECC manager to the Arria10 EDAC
driver. It introduces parsing for up to seven named interrupts, routing the
mandatory global_sbe and optional global_dbe through the chained interrupt
handler.
> diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
> index e833869236914..13abce089ef1c 100644
> --- a/drivers/edac/altera_edac.c
> +++ b/drivers/edac/altera_edac.c
[ ... ]
> @@ -2145,14 +2197,31 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
> return -ENOMEM;
> }
>
> - edac->sb_irq = platform_get_irq(pdev, 0);
> - if (edac->sb_irq < 0)
> - return edac->sb_irq;
> + if (edac->flag == SOCFPGA_AGILEX5) {
> + rc = altr_agilex5_get_named_irqs(pdev, edac);
> + if (rc)
> + return rc;
[Severity: High]
This is a pre-existing issue, but if altr_agilex5_get_named_irqs() returns
an error like -EPROBE_DEFER, does this return path leak the IRQ domain
created earlier in altr_edac_a10_probe()?
Because edac is allocated with devres, the memory will be freed, but the
IRQ domain might remain registered and point to the freed edac structure.
Could this lead to a use-after-free if the IRQ subsystem attempts to access
the domain's host_data?
> +
> + edac->sb_irq = edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_SBE];
> + } else {
> + edac->sb_irq = platform_get_irq(pdev, 0);
> + if (edac->sb_irq < 0)
> + return edac->sb_irq;
> + }
>
> irq_set_chained_handler_and_data(edac->sb_irq,
> altr_edac_a10_irq_handler,
> edac);
>
> + /*
> + * Unlike Stratix10/Agilex7 (which deliver uncorrectable errors as
> + * Asynchronous SError), Agilex5 routes the global double-bit error
> + * through a dedicated SPI ("global_dbe"). Hook it into the same
> + * chained handler so the existing sb_irq/db_irq demux in
> + * altr_edac_a10_irq_handler() routes DBE events through the manager's
> + * IRQ domain. The panic notifier below is still registered as a
> + * fall-back for any DBEs that escape to SError.
> + */
> if (edac->flag == SOCFPGA_S10) {
[Severity: High]
The comment above states the panic notifier is registered as a fallback
for Agilex5. However, this check only matches SOCFPGA_S10. Does this mean
the panic notifier is inadvertently skipped for Agilex5 devices?
> int dberror, err_addr;
>
[ ... ]
> @@ -2175,6 +2244,12 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
> regmap_write(edac->ecc_mgr_map,
> S10_SYSMGR_UE_ADDR_OFST, 0);
> }
> + } else if (edac->flag == SOCFPGA_AGILEX5 &&
> + edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_DBE] >= 0) {
> + edac->db_irq = edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_DBE];
> + irq_set_chained_handler_and_data(edac->db_irq,
> + altr_edac_a10_irq_handler,
> + edac);
> } else {
> edac->db_irq = platform_get_irq(pdev, 1);
> if (edac->db_irq < 0)
> return edac->db_irq;
[Severity: High]
If an Agilex5 device omits the optional GLOBAL_DBE interrupt, will it
incorrectly fall through to this else branch?
This would cause it to call platform_get_irq(pdev, 1). If the device has
other optional interrupts, this might incorrectly hijack one of them (like
io96b0) as the chained DBE handler. If it doesn't have other interrupts,
it might fail and abort the probe with -ENXIO.
Also, this is a pre-existing issue, but if platform_get_irq(pdev, 1) fails,
does returning an error here leave the sb_irq chained handler dangling?
Since it was registered earlier in altr_edac_a10_probe(), it could cause a
use-after-free when the interrupt fires and dereferences the devres-freed
edac pointer.
[ ... ]
> @@ -2206,6 +2281,8 @@ static const struct of_device_id altr_edac_a10_of_match[] = {
> { .compatible = "altr,socfpga-a10-ecc-manager" },
> { .compatible = "altr,socfpga-s10-ecc-manager",
> .data = (void *)SOCFPGA_S10 },
> + { .compatible = "altr,socfpga-agilex5-ecc-manager",
> + .data = (void *)SOCFPGA_AGILEX5 },
> {},
> };
> MODULE_DEVICE_TABLE(of, altr_edac_a10_of_match);
[Severity: High]
This is a pre-existing issue, but does the platform driver lack a .remove
callback?
drivers/edac/altera_edac.c:
static struct platform_driver altr_edac_a10_driver = {
.probe = altr_edac_a10_probe,
.driver = {
.name = "socfpga_a10_ecc_manager",
.of_match_table = altr_edac_a10_of_match,
},
};
If the driver is unbound via sysfs, devres will automatically free the
edac struct and unmap MMIO regions. However, the chained IRQ handlers,
IRQ domain, and panic notifier remain registered.
Could this cause a use-after-free if a hardware interrupt or kernel panic
occurs after the module is unbound?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720201425.1538771-1-dinguyen@kernel.org?part=3
^ permalink raw reply
* [PATCH V18 0/9] Add Invensense ICM42607
From: Chris Morgan @ 2026-07-20 20:23 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
From: Chris Morgan <macromorgan@hotmail.com>
Add support for the ICM42607 IMU. This sensor shares the same
functionality but a different register layout with the existing
ICM42600.
This driver should work with the ICM42607 and ICM42607P over both I2C
and SPI, however only the ICM42607P over I2C could be tested.
Changes Since V1:
- Instead of creating a new driver, merged with the existing inv_icm42600
driver. This necessitated adding some code to the existing driver to
permit using a different register layout for the same functionality.
- Split changes up a bit more to decrease the size of the individual
patches. Note that patch 0004 is still pretty hefty; if I need to split
further I may need to create some temporary stub functions.
- Used guard() and PM_RUNTIME_ACQUIRE_AUTOSUSPEND() on the new functions
per Jonathan's recommendations.
Changes Since V2:
- Went back to using a new driver on advice from Invensense engineer.
- Further split changes up into smaller chunks of functionality. Note
still that the largest patch is approximately 900 lines, and that while
the driver compiles cleanly at each commit it is not able to drive the
hardware until the commit that adds the Interrupt (as it also adds the
Makefile).
- Change the error to a warning when the devicetree binding does not match
the hardware ID.
- Dropped the ack on the devicetree bindings, as I am creating a new file
(for a new driver) instead of modifying the existing one.
Changes Since V3:
- Numerous small fixes (too many to list here). Thank you to everyone who
provided feedback.
- Split power management additions into an additional commit to break
things up further.
- Consolidated devicetree documentation in existing
invensense,icm42600.yaml file.
- Removed most of the FIELD_PREP from header file to c files to make code
easier to read.
- Changed scale values to 2D arrays for Gyro and Accelerometer.
- Removed IIO_CHAN_INFO_CALIBBIAS attribute.
Changes Since V4:
- Additional numerous small fixes, thank you again for all the feedback.
- Dropped power control API and instead run device in low noise mode.
- Split devicetree bindings into two distinct changes.
- Reordered adding of enums and structs to main header file so that they
are only brought in when needed.
- Stopped using enum for driver data and instead am using pointer to
device specific driver data.
Changes Since V5:
- Corrected use of "dev_warn_probe" to just "dev_warn".
- Fixed some return scenarios which would unconditionally return 0
when an error was present.
- Corrected use of max() to min() for bounds checking. max() was
incorrect.
- Fixed using "st->conf.accel.odr" in the gyroscope function. It
should have been "st->conf.gyro.odr" which it now is.
- Additional small fixes suggested by "sashiko.dev".
- Added a regmap cache. I used the datasheet to try and determine
which registers might change without explicit writes.
Changes Since V6:
- Corrected additional errors identified by sashiko.dev, mostly
fixing potential deadlocks, missing calls for pm runtime, and
potential overflow issues.
Changes Since V7:
- Dropped Wake on Movement patches, since some of the functionality
was only available for a device on which I cannot test.
- Dropped support for SPI 3-Wire mode, since it complicated the
bus setup (and I lack the hardware to test such features anyway).
- Fixed a few additional bugs identified by sashiko.dev bot.
Changes Since V8:
- Added back IRQ dropped accidentally when dropping wake on movement
patches.
- Dropped "Reviewed-By" tag on patch 2 because of substantial changes
made to devicetree binding documentation.
- Additional small fixes as suggested.
Changes Since V9:
- Removed interrupts (and buffers) from the driver. I previously was
unable to detect deadlocks because it turns out my IRQ was not even
wired correctly in my device.
- Updated devicetree binding commits to make interrupts optional for
users of the icm42607 driver.
Changes Since V10:
- Explicitly specified enum values in header file.
- Removed additional dead code for buffer handling.
- Cleaned up headers.
- Added additional locks as requested by sashiko.dev bot.
Changes Since V11:
- Since driver has shrunk in size considerably, moved i2c bits into
first code commit. This ensures that the very first commit with code
can now be compiled. The commit after that adds SPI support as it
was in the previous versions.
- Used pahole to optimize inv_icm42607_state. Reordering elements
reduced size in memory from 384 bytes to 256 bytes.
- Added a map of all readable registers and all writeable registers
according to the datasheet.
- Added back some missing headers pointed out by the maintainers.
- Added FIELD_PREP in a few more places to make the code more
obvious on what it's doing.
- Added a comment to the power management code to note that
temperature sensor being enabled doesn't matter as the clocks
are off by default when the gyro and accel channels are off.
- Removed iio_device_claim_direct() calls since it was no longer
needed.
- Fixed shared_by_all attributes for temperature sensor.
- Additional miscellanous fixes as requested.
Changes Since V12:
- Removed aligned buffer from inv_icm42607_state struct as we do not
currently have the need for it.
- Corrected the order of the odr values in the accel and gyro files
as the values were out of order (the place in the array corresponds
to the register value).
- Stopped setting the clock value depending upon the temp config. The
datasheet advised to keep using the default value.
- Corrected logic when changing between states. We only need to pause
when a sensor changes from off to an on state or when the gyro
changes from an on state to off.
- Added missing includes for several files.
Changes Since V13:
- Refactored inv_icm42607_set_accel_conf() and
inv_icm42607_set_gyro_conf() into a single function.
- Refactored inv_icm42607_accel_read_sensor() and
inv_icm42607_gyro_read_sensor() into a single function.
- Merged inv_icm42607_set_temp_conf() into initial init function
since it only really needs to be called once.
- Saved adding temp sensor for last and updated
inv_icm42607_temp_read() to either confirm other sensors are already
enabled or enable the accelerometer so it can get a reading.
- Updated inv_icm42607_set_pwr_mgmt0() so that it does not update the
sensor mode and forcibly keep the sensor enabled.
- Added inv_icm42607_temp_filter_bw enums since it appears to use
different values than the accel or gyro sensor.
- Set the temp startup time from 77ms to 77us, as I previously misread
the datasheet.
- Additional minor fixes.
Changes Since V14:
- Added IIO_BE for temp sensor.
- Switched from ktime_get_real() to ktime_get().
Changes Since V15:
- Removed interrupts from required property per note from Jonathan.
As a result of this change I've also removed one of Krzysztof's
Reviewed-By tags as this change probably requires further review
from them.
- Corrected a comment about reserved values from 0-5 to 0-4.
- Reordered some operations so that only runtime power management
turns off the sensors now. This removes the "ping-pong" effect
when switching between the accel and gyro sensor, at the expense
of leaving either the accel or gyro sensor enabled until runtime
power management turns it off.
- Fixed the shared frequency value not being available for the temp
sensor.
Changes Since V16:
- Reverted devicetree changes back to removing interrupts only for
icm42607. Added back "Reviewed-By" tag, hope that's okay since it's
what was initally agreed upon.
- Removed PM runtime resume code, as there is currently no need to
resume; instead the raw read/write calls will enable sensors as
needed. This also allows us to remove storing the sensor state
prior to runtime suspend and instead we just use runtime suspend
to disable sensors while not being used.
- Additional formatting and minor fixes.
Changes Since V17:
- Added remove routine to ensure device is properly powered down when
driver removed.
- Corrected issue with reading scale and offset values for temp
sensor.
- Set regcache as dirty and re-sync when resuming from suspend.
- Added back driver data to of_device_id table for I2C driver. While
Uwe told me to remove this in a prior commit Jonathan requested it
back and it is consistent with other drivers to be there.
- Removed linux/mod_devicetable.h header for SPI driver.
Chris Morgan (9):
dt-bindings: iio: imu: icm42600: Add mount-matrix
dt-bindings: iio: imu: icm42600: Add icm42607
iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
iio: imu: inv_icm42607: Add SPI For icm42607
iio: imu: inv_icm42607: Add PM support for icm42607
iio: imu: inv_icm42607: Add Accelerometer for icm42607
iio: imu: inv_icm42607: Add Gyroscope to icm42607
iio: imu: inv_icm42607: Add Temp Support in icm42607
arm64: dts: rockchip: Add icm42607p IMU for RG-DS
.../bindings/iio/imu/invensense,icm42600.yaml | 20 +-
.../dts/rockchip/rk3568-anbernic-rg-ds.dts | 8 +-
drivers/iio/imu/Kconfig | 1 +
drivers/iio/imu/Makefile | 1 +
drivers/iio/imu/inv_icm42607/Kconfig | 30 +
drivers/iio/imu/inv_icm42607/Makefile | 13 +
drivers/iio/imu/inv_icm42607/inv_icm42607.h | 421 ++++++++++++
.../iio/imu/inv_icm42607/inv_icm42607_accel.c | 312 +++++++++
.../iio/imu/inv_icm42607/inv_icm42607_core.c | 641 ++++++++++++++++++
.../iio/imu/inv_icm42607/inv_icm42607_gyro.c | 309 +++++++++
.../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 104 +++
.../iio/imu/inv_icm42607/inv_icm42607_spi.c | 114 ++++
.../iio/imu/inv_icm42607/inv_icm42607_temp.c | 98 +++
.../iio/imu/inv_icm42607/inv_icm42607_temp.h | 38 ++
14 files changed, 2108 insertions(+), 2 deletions(-)
create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
--
2.43.0
^ permalink raw reply
* [PATCH V18 1/9] dt-bindings: iio: imu: icm42600: Add mount-matrix
From: Chris Morgan @ 2026-07-20 20:23 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan, Krzysztof Kozlowski
In-Reply-To: <20260720202343.70138-1-macroalpha82@gmail.com>
From: Chris Morgan <macromorgan@hotmail.com>
Add mount-matrix attribute to schema. This attribute has been supported
since the first revision of this driver, but was not documented.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../devicetree/bindings/iio/imu/invensense,icm42600.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 119e28a833fd..9b2af104f186 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -53,6 +53,8 @@ properties:
drive-open-drain:
type: boolean
+ mount-matrix: true
+
vdd-supply:
description: Regulator that provides power to the sensor
--
2.43.0
^ permalink raw reply related
* [PATCH V18 2/9] dt-bindings: iio: imu: icm42600: Add icm42607
From: Chris Morgan @ 2026-07-20 20:23 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan, Krzysztof Kozlowski
In-Reply-To: <20260720202343.70138-1-macroalpha82@gmail.com>
From: Chris Morgan <macromorgan@hotmail.com>
Add the ICM42607 and ICM42607P inertial measurement unit.
This device is functionally very similar to the icm42600 series with a
very different register layout. The icm42607 currently does not use an
interrupt because wake on movement and buffers are not supported, and
cannot be implemented on my test device which lacks an interrupt line.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../bindings/iio/imu/invensense,icm42600.yaml | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 9b2af104f186..81b6e85decd5 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -30,6 +30,8 @@ properties:
- invensense,icm42600
- invensense,icm42602
- invensense,icm42605
+ - invensense,icm42607
+ - invensense,icm42607p
- invensense,icm42622
- invensense,icm42631
- invensense,icm42686
@@ -67,10 +69,24 @@ properties:
required:
- compatible
- reg
- - interrupts
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - invensense,icm42600
+ - invensense,icm42602
+ - invensense,icm42605
+ - invensense,icm42622
+ - invensense,icm42631
+ - invensense,icm42686
+ - invensense,icm42688
+ then:
+ required:
+ - interrupts
unevaluatedProperties: false
--
2.43.0
^ permalink raw reply related
* [PATCH V18 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
From: Chris Morgan @ 2026-07-20 20:23 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
In-Reply-To: <20260720202343.70138-1-macroalpha82@gmail.com>
From: Chris Morgan <macromorgan@hotmail.com>
Add the core component of a new inv_icm42607 driver. This includes
a few setup functions and the full register definition in the
header file, as well as the bits necessary to compile and probe the
device when used on an i2c bus.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/iio/imu/Kconfig | 1 +
drivers/iio/imu/Makefile | 1 +
drivers/iio/imu/inv_icm42607/Kconfig | 18 +
drivers/iio/imu/inv_icm42607/Makefile | 7 +
drivers/iio/imu/inv_icm42607/inv_icm42607.h | 365 ++++++++++++++++++
.../iio/imu/inv_icm42607/inv_icm42607_core.c | 284 ++++++++++++++
.../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 96 +++++
7 files changed, 772 insertions(+)
create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 7e0181c27bb6..8bab4616be20 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -109,6 +109,7 @@ config KMX61
be called kmx61.
source "drivers/iio/imu/inv_icm42600/Kconfig"
+source "drivers/iio/imu/inv_icm42607/Kconfig"
source "drivers/iio/imu/inv_icm45600/Kconfig"
source "drivers/iio/imu/inv_mpu6050/Kconfig"
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 13fb7846e9c9..3268dc2371ae 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
obj-y += inv_icm42600/
+obj-y += inv_icm42607/
obj-y += inv_icm45600/
obj-y += inv_mpu6050/
diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig
new file mode 100644
index 000000000000..083c212087ab
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config INV_ICM42607
+ tristate
+ select IIO_BUFFER
+ select IIO_INV_SENSORS_TIMESTAMP
+
+config INV_ICM42607_I2C
+ tristate "InvenSense ICM-42607 I2C driver"
+ depends on I2C
+ select INV_ICM42607
+ select REGMAP_I2C
+ help
+ This driver supports the InvenSense ICM-42607 motion tracking
+ device over I2C.
+
+ This driver can be built as a module. The module will be called
+ inv-icm42607-i2c.
diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
new file mode 100644
index 000000000000..32046e2727d7
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
+inv-icm42607-y += inv_icm42607_core.o
+
+obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
+inv-icm42607-i2c-y += inv_icm42607_i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
new file mode 100644
index 000000000000..169e848caf2e
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -0,0 +1,365 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_H_
+#define INV_ICM42607_H_
+
+#include <linux/bits.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+
+/*
+ * Serial bus slew rates. Rates are expressed as range between the two
+ * values with the midpoint as the typical rate. For the final value of
+ * 2ns, 2ns is considered the max value with no expressed minimum or
+ * typical value.
+ */
+enum inv_icm42607_slew_rate {
+ INV_ICM42607_SLEW_RATE_20_60NS = 0,
+ INV_ICM42607_SLEW_RATE_12_36NS = 1,
+ INV_ICM42607_SLEW_RATE_6_19NS = 2,
+ INV_ICM42607_SLEW_RATE_4_14NS = 3,
+ INV_ICM42607_SLEW_RATE_2_6NS = 4,
+ INV_ICM42607_SLEW_RATE_2NS = 5,
+ INV_ICM42607_SLEW_RATE_NB
+};
+
+enum inv_icm42607_sensor_mode {
+ INV_ICM42607_SENSOR_MODE_OFF = 0,
+ INV_ICM42607_SENSOR_MODE_STANDBY = 1,
+ INV_ICM42607_SENSOR_MODE_LOW_POWER = 2,
+ INV_ICM42607_SENSOR_MODE_LOW_NOISE = 3,
+ INV_ICM42607_SENSOR_MODE_NB
+};
+
+/* gyroscope fullscale values */
+enum inv_icm42607_gyro_fs {
+ INV_ICM42607_GYRO_FS_2000DPS = 0,
+ INV_ICM42607_GYRO_FS_1000DPS = 1,
+ INV_ICM42607_GYRO_FS_500DPS = 2,
+ INV_ICM42607_GYRO_FS_250DPS = 3,
+ INV_ICM42607_GYRO_FS_NB
+};
+
+/* accelerometer fullscale values */
+enum inv_icm42607_accel_fs {
+ INV_ICM42607_ACCEL_FS_16G = 0,
+ INV_ICM42607_ACCEL_FS_8G = 1,
+ INV_ICM42607_ACCEL_FS_4G = 2,
+ INV_ICM42607_ACCEL_FS_2G = 3,
+ INV_ICM42607_ACCEL_FS_NB
+};
+
+/* ODR values - Note Gyro does not support ODR less than 12.5Hz */
+enum inv_icm42607_odr {
+ INV_ICM42607_ODR_1600HZ = 5,
+ INV_ICM42607_ODR_800HZ = 6,
+ INV_ICM42607_ODR_400HZ = 7,
+ INV_ICM42607_ODR_200HZ = 8,
+ INV_ICM42607_ODR_100HZ = 9,
+ INV_ICM42607_ODR_50HZ = 10,
+ INV_ICM42607_ODR_25HZ = 11,
+ INV_ICM42607_ODR_12_5HZ = 12,
+ INV_ICM42607_ODR_6_25HZ_LP = 13,
+ INV_ICM42607_ODR_3_125HZ_LP = 14,
+ INV_ICM42607_ODR_1_5625HZ_LP = 15,
+ INV_ICM42607_ODR_NB
+};
+
+/* Low-Noise mode sensor data filter (bandwidth) */
+enum inv_icm42607_filter_bw {
+ INV_ICM42607_FILTER_BYPASS = 0,
+ INV_ICM42607_FILTER_BW_180HZ = 1,
+ INV_ICM42607_FILTER_BW_121HZ = 2,
+ INV_ICM42607_FILTER_BW_73HZ = 3,
+ INV_ICM42607_FILTER_BW_53HZ = 4,
+ INV_ICM42607_FILTER_BW_34HZ = 5,
+ INV_ICM42607_FILTER_BW_25HZ = 6,
+ INV_ICM42607_FILTER_BW_16HZ = 7,
+ INV_ICM42607_FILTER_BW_NB
+};
+
+/* Temperature sensor data filter (bandwidth) */
+enum inv_icm42607_temp_filter_bw {
+ INV_ICM42607_TEMP_FILTER_BYPASS = 0,
+ INV_ICM42607_TEMP_FILTER_BW_180HZ = 1,
+ INV_ICM42607_TEMP_FILTER_BW_72HZ = 2,
+ INV_ICM42607_TEMP_FILTER_BW_34HZ = 3,
+ INV_ICM42607_TEMP_FILTER_BW_16HZ = 4,
+ INV_ICM42607_TEMP_FILTER_BW_8HZ = 5,
+ INV_ICM42607_TEMP_FILTER_BW_4HZ = 6,
+ /* value 7 also corresponds to 4Hz */
+};
+
+/* Signed so that negative values can signify an invalid condition. */
+struct inv_icm42607_sensor_conf {
+ int mode;
+ int fs;
+ int odr;
+ int filter;
+};
+
+struct inv_icm42607_conf {
+ struct inv_icm42607_sensor_conf gyro;
+ struct inv_icm42607_sensor_conf accel;
+ ktime_t gyro_stop; /* earliest time to stop the gyro */
+};
+
+struct inv_icm42607_hw {
+ const char *name;
+ const struct inv_icm42607_conf *conf;
+ u8 whoami;
+};
+
+/**
+ * struct inv_icm42607_state - driver state variables
+ * @hw: Hardware specific data.
+ * @lock: lock for serializing multiple registers access.
+ * @map: regmap pointer.
+ * @vddio_supply: I/O voltage regulator for the chip.
+ * @conf: chip sensors configurations.
+ * @orientation: sensor chip orientation relative to main hardware.
+ */
+struct inv_icm42607_state {
+ const struct inv_icm42607_hw *hw;
+ struct mutex lock;
+ struct regmap *map;
+ struct regulator *vddio_supply;
+ struct inv_icm42607_conf conf;
+ struct iio_mount_matrix orientation;
+};
+
+/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
+
+/* Register Map for User Bank 0 */
+#define INV_ICM42607_REG_MCLK_RDY 0x00
+
+#define INV_ICM42607_REG_DEVICE_CONFIG 0x01
+#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE BIT(2)
+#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE BIT(0)
+
+#define INV_ICM42607_REG_SIGNAL_PATH_RESET 0x02
+#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET BIT(4)
+#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH BIT(2)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG1 0x03
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG2 0x04
+#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG3 0x05
+#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_CONFIG 0x06
+#define INV_ICM42607_INT_CONFIG_INT2_LATCHED BIT(5)
+#define INV_ICM42607_INT_CONFIG_INT2_PUSH_PULL BIT(4)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_HIGH BIT(3)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_LOW 0x00
+#define INV_ICM42607_INT_CONFIG_INT1_LATCHED BIT(2)
+#define INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL BIT(1)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH BIT(0)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW 0x00
+
+/* all sensor data are 16 bits (2 registers wide) in big-endian */
+#define INV_ICM42607_REG_TEMP_DATA1 0x09
+#define INV_ICM42607_REG_TEMP_DATA0 0x0A
+#define INV_ICM42607_REG_ACCEL_DATA_X1 0x0B
+#define INV_ICM42607_REG_ACCEL_DATA_X0 0x0C
+#define INV_ICM42607_REG_ACCEL_DATA_Y1 0x0D
+#define INV_ICM42607_REG_ACCEL_DATA_Y0 0x0E
+#define INV_ICM42607_REG_ACCEL_DATA_Z1 0x0F
+#define INV_ICM42607_REG_ACCEL_DATA_Z0 0x10
+#define INV_ICM42607_REG_GYRO_DATA_X1 0x11
+#define INV_ICM42607_REG_GYRO_DATA_X0 0x12
+#define INV_ICM42607_REG_GYRO_DATA_Y1 0x13
+#define INV_ICM42607_REG_GYRO_DATA_Y0 0x14
+#define INV_ICM42607_REG_GYRO_DATA_Z1 0x15
+#define INV_ICM42607_REG_GYRO_DATA_Z0 0x16
+#define INV_ICM42607_DATA_INVALID -32768
+
+#define INV_ICM42607_REG_TMST_FSYNCH 0x17
+#define INV_ICM42607_REG_TMST_FSYNCL 0x18
+
+/* APEX Data Registers */
+#define INV_ICM42607_REG_APEX_DATA0 0x31
+#define INV_ICM42607_REG_APEX_DATA1 0x32
+#define INV_ICM42607_REG_APEX_DATA2 0x33
+#define INV_ICM42607_REG_APEX_DATA3 0x34
+#define INV_ICM42607_REG_APEX_DATA4 0x1D
+#define INV_ICM42607_REG_APEX_DATA5 0x1E
+
+#define INV_ICM42607_REG_PWR_MGMT0 0x1F
+#define INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL BIT(7)
+#define INV_ICM42607_PWR_MGMT0_IDLE BIT(4)
+#define INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK GENMASK(3, 2)
+#define INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK GENMASK(1, 0)
+
+#define INV_ICM42607_REG_GYRO_CONFIG0 0x20
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK GENMASK(6, 5)
+#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK GENMASK(3, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG0 0x21
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK GENMASK(6, 5)
+#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK GENMASK(3, 0)
+
+#define INV_ICM42607_REG_TEMP_CONFIG0 0x22
+#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK GENMASK(6, 4)
+
+#define INV_ICM42607_REG_GYRO_CONFIG1 0x23
+#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG1 0x24
+#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK GENMASK(6, 4)
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_APEX_CONFIG0 0x25
+#define INV_ICM42607_APEX_CONFIG0_DMP_POWER_SAVE_EN BIT(3)
+#define INV_ICM42607_APEX_CONFIG0_DMP_INIT_EN BIT(2)
+#define INV_ICM42607_APEX_CONFIG0_DMP_MEM_RESET_EN BIT(0)
+
+#define INV_ICM42607_REG_APEX_CONFIG1 0x26
+#define INV_ICM42607_APEX_CONFIG1_SMD_ENABLE BIT(6)
+#define INV_ICM42607_APEX_CONFIG1_FF_ENABLE BIT(5)
+#define INV_ICM42607_APEX_CONFIG1_TILT_ENABLE BIT(4)
+#define INV_ICM42607_APEX_CONFIG1_PED_ENABLE BIT(3)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK GENMASK(1, 0)
+
+#define INV_ICM42607_REG_WOM_CONFIG 0x27
+#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK GENMASK(4, 3)
+#define INV_ICM42607_WOM_CONFIG_INT_MODE BIT(2)
+#define INV_ICM42607_WOM_CONFIG_MODE BIT(1)
+#define INV_ICM42607_WOM_CONFIG_EN BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG1 0x28
+#define INV_ICM42607_FIFO_CONFIG1_MODE BIT(1)
+#define INV_ICM42607_FIFO_CONFIG1_BYPASS BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG2 0x29
+#define INV_ICM42607_REG_FIFO_CONFIG3 0x2A
+#define INV_ICM42607_FIFO_WATERMARK_VAL(_wm) \
+ cpu_to_le16((_wm) & GENMASK(11, 0))
+/* FIFO is 2048 bytes, let 12 samples for reading latency */
+#define INV_ICM42607_FIFO_WATERMARK_MAX (2048 - 12 * 16)
+#define INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE 8
+#define INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE 16
+
+#define INV_ICM42607_REG_INT_SOURCE0 0x2B
+#define INV_ICM42607_INT_SOURCE0_ST_INT1_EN BIT(7)
+#define INV_ICM42607_INT_SOURCE0_FSYNC_INT1_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE0_PLL_RDY_INT1_EN BIT(5)
+#define INV_ICM42607_INT_SOURCE0_RESET_DONE_INT1_EN BIT(4)
+#define INV_ICM42607_INT_SOURCE0_DRDY_INT1_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE0_FIFO_FULL_INT1_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE0_AGC_RDY_INT1_EN BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE1 0x2C
+#define INV_ICM42607_INT_SOURCE1_I3C_ERROR_INT1_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE1_SMD_INT1_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE1_WOM_INT1_EN GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_SOURCE3 0x2D
+#define INV_ICM42607_INT_SOURCE3_ST_INT2_EN BIT(7)
+#define INV_ICM42607_INT_SOURCE3_FSYNC_INT2_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE3_PLL_RDY_INT2_EN BIT(5)
+#define INV_ICM42607_INT_SOURCE3_RESET_DONE_INT2_EN BIT(4)
+#define INV_ICM42607_INT_SOURCE3_DRDY_INT2_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE3_FIFO_THS_INT2_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE3_FIFO_FULL_INT2_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE3_AGC_RDY_INT2_EN BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE4 0x2E
+#define INV_ICM42607_INT_SOURCE4_I3C_ERROR_INT2_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE4_SMD_INT2_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE4_WOM_Z_INT2_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE4_WOM_Y_INT2_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE4_WOM_X_INT2_EN BIT(0)
+
+#define INV_ICM42607_REG_FIFO_LOST_PKT0 0x2F
+#define INV_ICM42607_REG_FIFO_LOST_PKT1 0x30
+
+#define INV_ICM42607_REG_INTF_CONFIG0 0x35
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT BIT(6)
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN BIT(5)
+#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN BIT(4)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS 2
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS 3
+
+#define INV_ICM42607_REG_INTF_CONFIG1 0x36
+#define INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN BIT(3)
+#define INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN BIT(2)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_INT 0
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL 1
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_OFF 2
+
+#define INV_ICM42607_REG_INT_STATUS_DRDY 0x39
+#define INV_ICM42607_INT_STATUS_DRDY_DATA_RDY BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS 0x3A
+#define INV_ICM42607_INT_STATUS_ST BIT(7)
+#define INV_ICM42607_INT_STATUS_FSYNC BIT(6)
+#define INV_ICM42607_INT_STATUS_PLL_RDY BIT(5)
+#define INV_ICM42607_INT_STATUS_RESET_DONE BIT(4)
+#define INV_ICM42607_INT_STATUS_FIFO_THS BIT(2)
+#define INV_ICM42607_INT_STATUS_FIFO_FULL BIT(1)
+#define INV_ICM42607_INT_STATUS_AGC_RDY BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS2 0x3B
+#define INV_ICM42607_INT_STATUS2_SMD BIT(3)
+#define INV_ICM42607_INT_STATUS2_WOM_INT GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_STATUS3 0x3C
+#define INV_ICM42607_INT_STATUS3_STEP_DET BIT(5)
+#define INV_ICM42607_INT_STATUS3_STEP_CNT_OVF BIT(4)
+#define INV_ICM42607_INT_STATUS3_TILT_DET BIT(3)
+#define INV_ICM42607_INT_STATUS3_FF_DET BIT(2)
+
+/*
+ * FIFO access registers
+ * FIFO count is 16 bits (2 registers) big-endian
+ * FIFO data is a continuous read register to read FIFO content
+ */
+#define INV_ICM42607_REG_FIFO_COUNTH 0x3D
+#define INV_ICM42607_REG_FIFO_COUNTL 0x3E
+#define INV_ICM42607_REG_FIFO_DATA 0x3F
+
+#define INV_ICM42607_REG_WHOAMI 0x75
+#define INV_ICM42607P_WHOAMI 0x60
+#define INV_ICM42607_WHOAMI 0x67
+
+/*
+ * Timings as listed in section 3 of datasheet, all values listed in datasheet
+ * in ms except temp startup time... setting all values in us and using
+ * USEC_PER_MSEC to convert from values displayed in datasheet.
+ */
+#define INV_ICM42607_POWER_UP_TIME_US (100 * USEC_PER_MSEC)
+#define INV_ICM42607_RESET_TIME_US (1 * USEC_PER_MSEC)
+#define INV_ICM42607_ACCEL_STARTUP_TIME_US (10 * USEC_PER_MSEC)
+#define INV_ICM42607_GYRO_STARTUP_TIME_US (30 * USEC_PER_MSEC)
+#define INV_ICM42607_GYRO_STOP_TIME_US (45 * USEC_PER_MSEC)
+#define INV_ICM42607_TEMP_STARTUP_TIME_US 77
+
+typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
+
+extern const struct regmap_config inv_icm42607_regmap_config;
+extern const struct inv_icm42607_hw inv_icm42607_hw_data;
+extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+ const struct inv_icm42607_hw *hw,
+ inv_icm42607_bus_setup bus_setup);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
new file mode 100644
index 000000000000..6ec1d730017e
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include "inv_icm42607.h"
+
+static bool inv_icm42607_is_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case INV_ICM42607_REG_MCLK_RDY ... INV_ICM42607_REG_INT_CONFIG:
+ case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_TMST_FSYNCL:
+ case INV_ICM42607_REG_APEX_DATA4 ... INV_ICM42607_REG_INTF_CONFIG1:
+ case INV_ICM42607_REG_INT_STATUS_DRDY ... INV_ICM42607_REG_FIFO_DATA:
+ case INV_ICM42607_REG_WHOAMI:
+ return true;
+ }
+
+ return false;
+}
+
+static bool inv_icm42607_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case INV_ICM42607_REG_DEVICE_CONFIG ... INV_ICM42607_REG_INT_CONFIG:
+ case INV_ICM42607_REG_PWR_MGMT0 ... INV_ICM42607_REG_INT_SOURCE4:
+ case INV_ICM42607_REG_INTF_CONFIG0 ... INV_ICM42607_REG_INTF_CONFIG1:
+ return true;
+ }
+
+ return false;
+}
+
+static bool inv_icm42607_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case INV_ICM42607_REG_MCLK_RDY:
+ case INV_ICM42607_REG_SIGNAL_PATH_RESET:
+ case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_APEX_DATA5:
+ case INV_ICM42607_REG_APEX_CONFIG0:
+ case INV_ICM42607_REG_FIFO_LOST_PKT0 ... INV_ICM42607_REG_APEX_DATA3:
+ case INV_ICM42607_REG_INT_STATUS_DRDY:
+ case INV_ICM42607_REG_INT_STATUS ... INV_ICM42607_REG_FIFO_DATA:
+ return true;
+ }
+
+ return false;
+}
+
+const struct regmap_config inv_icm42607_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = inv_icm42607_is_writeable_reg,
+ .readable_reg = inv_icm42607_is_readable_reg,
+ .volatile_reg = inv_icm42607_is_volatile_reg,
+ .max_register = INV_ICM42607_REG_WHOAMI,
+ .cache_type = REGCACHE_MAPLE,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_regmap_config, "IIO_ICM42607");
+
+/* chip initial default configuration */
+static const struct inv_icm42607_conf inv_icm42607_default_conf = {
+ .gyro = {
+ .mode = INV_ICM42607_SENSOR_MODE_OFF,
+ .fs = INV_ICM42607_GYRO_FS_1000DPS,
+ .odr = INV_ICM42607_ODR_100HZ,
+ .filter = INV_ICM42607_FILTER_BW_25HZ,
+ },
+ .accel = {
+ .mode = INV_ICM42607_SENSOR_MODE_OFF,
+ .fs = INV_ICM42607_ACCEL_FS_4G,
+ .odr = INV_ICM42607_ODR_100HZ,
+ .filter = INV_ICM42607_FILTER_BW_25HZ,
+ },
+};
+
+const struct inv_icm42607_hw inv_icm42607_hw_data = {
+ .whoami = INV_ICM42607_WHOAMI,
+ .name = "icm42607",
+ .conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_hw_data, "IIO_ICM42607");
+
+const struct inv_icm42607_hw inv_icm42607p_hw_data = {
+ .whoami = INV_ICM42607P_WHOAMI,
+ .name = "icm42607p",
+ .conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
+
+static int inv_icm42607_set_init_conf(struct inv_icm42607_state *st,
+ const struct inv_icm42607_conf *conf)
+{
+ unsigned int val;
+ int ret;
+
+ val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, conf->gyro.mode);
+ val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, conf->accel.mode);
+ ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, conf->gyro.fs);
+ val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, conf->gyro.odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->accel.fs);
+ val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->accel.odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, conf->gyro.filter);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+ INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, conf->accel.filter);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+ INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_TEMP_CONFIG0_FILTER_MASK,
+ INV_ICM42607_TEMP_FILTER_BW_34HZ);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_TEMP_CONFIG0,
+ INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, val);
+ if (ret)
+ return ret;
+
+ st->conf = *conf;
+
+ return 0;
+}
+
+static int inv_icm42607_setup(struct inv_icm42607_state *st,
+ inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+ const struct device *dev = regmap_get_device(st->map);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
+ if (ret)
+ return ret;
+
+ /* Warn, but don't fail. */
+ if (val != st->hw->whoami)
+ dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
+ val, st->hw->whoami, st->hw->name);
+
+ ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+ INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
+ if (ret)
+ return ret;
+
+ fsleep(1 * USEC_PER_MSEC);
+
+ /*
+ * No polling interval specified in datasheet, so use reset time as
+ * polling interval and 10x reset time as timeout period.
+ */
+ ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
+ val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
+ 1 * USEC_PER_MSEC, 10 * USEC_PER_MSEC);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "reset error, reset done bit not set\n");
+
+ /* Sync the regcache again after a reset. */
+ regcache_mark_dirty(st->map);
+ ret = regcache_sync(st->map);
+ if (ret)
+ return ret;
+
+ ret = inv_icm42607_bus_setup(st);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+ INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+ val);
+ if (ret)
+ return ret;
+
+ return inv_icm42607_set_init_conf(st, st->hw->conf);
+}
+
+static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
+{
+ int ret;
+
+ ret = regulator_enable(st->vddio_supply);
+ if (ret)
+ return ret;
+
+ fsleep(INV_ICM42607_POWER_UP_TIME_US);
+
+ return 0;
+}
+
+static void inv_icm42607_disable_vddio_reg(void *_data)
+{
+ struct inv_icm42607_state *st = _data;
+
+ regulator_disable(st->vddio_supply);
+}
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+ const struct inv_icm42607_hw *hw,
+ inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+ struct device *dev = regmap_get_device(regmap);
+ struct inv_icm42607_state *st;
+ int ret;
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ st->hw = hw;
+ st->map = regmap;
+
+ ret = iio_read_mount_matrix(dev, &st->orientation);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to retrieve mounting matrix\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get vdd regulator\n");
+
+ st->vddio_supply = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(st->vddio_supply))
+ return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
+ "Failed to get vddio regulator\n");
+
+ ret = inv_icm42607_enable_vddio_reg(st);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, inv_icm42607_disable_vddio_reg, st);
+ if (ret)
+ return ret;
+
+ /* Setup chip registers (includes WHOAMI check, reset check, bus setup) */
+ ret = inv_icm42607_setup(st, inv_icm42607_bus_setup);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
new file mode 100644
index 000000000000..f2b9067815b0
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_i2c_bus_setup(struct inv_icm42607_state *st)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+ INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK,
+ INV_ICM42607_SLEW_RATE_12_36NS);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG2,
+ INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
+
+ return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ val);
+}
+
+static int inv_icm42607_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ const struct inv_icm42607_hw *hw;
+ struct regmap *regmap;
+
+ hw = i2c_get_match_data(client);
+ if (!hw)
+ return dev_err_probe(dev, -ENODEV, "Failed to get i2c data\n");
+
+ regmap = devm_regmap_init_i2c(client, &inv_icm42607_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to register i2c regmap\n");
+
+ return inv_icm42607_core_probe(regmap, hw, inv_icm42607_i2c_bus_setup);
+}
+
+static const struct i2c_device_id inv_icm42607_id[] = {
+ {
+ .name = "icm42607",
+ .driver_data = (kernel_ulong_t)&inv_icm42607_hw_data,
+ }, {
+ .name = "icm42607p",
+ .driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, inv_icm42607_id);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+ {
+ .compatible = "invensense,icm42607",
+ .data = &inv_icm42607_hw_data,
+ }, {
+ .compatible = "invensense,icm42607p",
+ .data = &inv_icm42607p_hw_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct i2c_driver inv_icm42607_driver = {
+ .driver = {
+ .name = "inv-icm42607-i2c",
+ .of_match_table = inv_icm42607_of_matches,
+ },
+ .id_table = inv_icm42607_id,
+ .probe = inv_icm42607_probe,
+};
+module_i2c_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
--
2.43.0
^ permalink raw reply related
* [PATCH V18 4/9] iio: imu: inv_icm42607: Add SPI For icm42607
From: Chris Morgan @ 2026-07-20 20:23 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
In-Reply-To: <20260720202343.70138-1-macroalpha82@gmail.com>
From: Chris Morgan <macromorgan@hotmail.com>
Add SPI driver support for InvenSense ICM-42607 devices.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/iio/imu/inv_icm42607/Kconfig | 12 ++
drivers/iio/imu/inv_icm42607/Makefile | 3 +
.../iio/imu/inv_icm42607/inv_icm42607_spi.c | 106 ++++++++++++++++++
3 files changed, 121 insertions(+)
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig
index 083c212087ab..23f461f57afc 100644
--- a/drivers/iio/imu/inv_icm42607/Kconfig
+++ b/drivers/iio/imu/inv_icm42607/Kconfig
@@ -16,3 +16,15 @@ config INV_ICM42607_I2C
This driver can be built as a module. The module will be called
inv-icm42607-i2c.
+
+config INV_ICM42607_SPI
+ tristate "InvenSense ICM-42607 SPI driver"
+ depends on SPI_MASTER
+ select INV_ICM42607
+ select REGMAP_SPI
+ help
+ This driver supports the InvenSense ICM-42607 motion tracking
+ device over SPI.
+
+ This driver can be built as a module. The module will be called
+ inv-icm42607-spi.
diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index 32046e2727d7..be109102e203 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -5,3 +5,6 @@ inv-icm42607-y += inv_icm42607_core.o
obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
inv-icm42607-i2c-y += inv_icm42607_i2c.o
+
+obj-$(CONFIG_INV_ICM42607_SPI) += inv-icm42607-spi.o
+inv-icm42607-spi-y += inv_icm42607_spi.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
new file mode 100644
index 000000000000..eb04036a6712
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_spi_bus_setup(struct inv_icm42607_state *st)
+{
+ unsigned int val;
+ int ret;
+
+ /* Only support 4-wire mode for now. */
+ ret = regmap_set_bits(st->map, INV_ICM42607_REG_DEVICE_CONFIG,
+ INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE);
+ if (ret)
+ return ret;
+
+ ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+ INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK,
+ INV_ICM42607_SLEW_RATE_2NS);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG3,
+ INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
+
+ return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ val);
+}
+
+static int inv_icm42607_probe(struct spi_device *spi)
+{
+ const struct inv_icm42607_hw *hw;
+ struct device *dev = &spi->dev;
+ struct regmap *regmap;
+
+ hw = spi_get_device_match_data(spi);
+ if (!hw)
+ return dev_err_probe(dev, -ENODATA, "Failed to get SPI data\n");
+
+ if (spi->mode & SPI_3WIRE)
+ return dev_err_probe(dev, -ENODEV, "SPI 3-wire mode not supported\n");
+
+ regmap = devm_regmap_init_spi(spi, &inv_icm42607_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to register spi regmap\n");
+
+ return inv_icm42607_core_probe(regmap, hw, inv_icm42607_spi_bus_setup);
+}
+
+static const struct spi_device_id inv_icm42607_spi_id_table[] = {
+ {
+ .name = "icm42607",
+ .driver_data = (kernel_ulong_t)&inv_icm42607_hw_data,
+ }, {
+ .name = "icm42607p",
+ .driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, inv_icm42607_spi_id_table);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+ {
+ .compatible = "invensense,icm42607",
+ .data = &inv_icm42607_hw_data,
+ },
+ {
+ .compatible = "invensense,icm42607p",
+ .data = &inv_icm42607p_hw_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct spi_driver inv_icm42607_driver = {
+ .driver = {
+ .name = "inv-icm42607-spi",
+ .of_match_table = inv_icm42607_of_matches,
+ },
+ .id_table = inv_icm42607_spi_id_table,
+ .probe = inv_icm42607_probe,
+};
+module_spi_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 SPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
--
2.43.0
^ permalink raw reply related
* [PATCH V18 5/9] iio: imu: inv_icm42607: Add PM support for icm42607
From: Chris Morgan @ 2026-07-20 20:23 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
In-Reply-To: <20260720202343.70138-1-macroalpha82@gmail.com>
From: Chris Morgan <macromorgan@hotmail.com>
Add power management support for the ICM42607 device driver.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
drivers/iio/imu/inv_icm42607/inv_icm42607.h | 14 ++
.../iio/imu/inv_icm42607/inv_icm42607_core.c | 168 ++++++++++++++++++
.../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 8 +
.../iio/imu/inv_icm42607/inv_icm42607_spi.c | 8 +
4 files changed, 198 insertions(+)
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 169e848caf2e..61927a6c2663 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -9,6 +9,7 @@
#include <linux/bits.h>
#include <linux/iio/iio.h>
#include <linux/mutex.h>
+#include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/time.h>
@@ -125,6 +126,7 @@ struct inv_icm42607_hw {
* @lock: lock for serializing multiple registers access.
* @map: regmap pointer.
* @vddio_supply: I/O voltage regulator for the chip.
+ * @vddio_en: I/O voltage status for runtime PM.
* @conf: chip sensors configurations.
* @orientation: sensor chip orientation relative to main hardware.
*/
@@ -133,6 +135,7 @@ struct inv_icm42607_state {
struct mutex lock;
struct regmap *map;
struct regulator *vddio_supply;
+ bool vddio_en;
struct inv_icm42607_conf conf;
struct iio_mount_matrix orientation;
};
@@ -352,11 +355,22 @@ struct inv_icm42607_state {
#define INV_ICM42607_GYRO_STOP_TIME_US (45 * USEC_PER_MSEC)
#define INV_ICM42607_TEMP_STARTUP_TIME_US 77
+/*
+ * Suspend delay assumed from other icm42600 series device, not
+ * documented in datasheet.
+ */
+#define INV_ICM42607_SUSPEND_DELAY_MS (2 * MSEC_PER_SEC)
+
typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
extern const struct regmap_config inv_icm42607_regmap_config;
extern const struct inv_icm42607_hw inv_icm42607_hw_data;
extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+extern const struct dev_pm_ops inv_icm42607_pm_ops;
+
+int inv_icm42607_get_pwr_mgmt0(struct inv_icm42607_state *st,
+ enum inv_icm42607_sensor_mode *gyro,
+ enum inv_icm42607_sensor_mode *accel);
int inv_icm42607_core_probe(struct regmap *regmap,
const struct inv_icm42607_hw *hw,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 6ec1d730017e..c127ea0a94c4 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -4,15 +4,19 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
+#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/time.h>
+#include <linux/timekeeping.h>
#include <linux/types.h>
#include "inv_icm42607.h"
@@ -100,6 +104,93 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
};
EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
+int inv_icm42607_get_pwr_mgmt0(struct inv_icm42607_state *st,
+ enum inv_icm42607_sensor_mode *gyro,
+ enum inv_icm42607_sensor_mode *accel)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->map, INV_ICM42607_REG_PWR_MGMT0, &val);
+ if (ret)
+ return ret;
+
+ *gyro = FIELD_GET(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, val);
+ *accel = FIELD_GET(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, val);
+
+ return 0;
+}
+
+static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
+ enum inv_icm42607_sensor_mode gyro,
+ enum inv_icm42607_sensor_mode accel)
+{
+ enum inv_icm42607_sensor_mode oldaccel, oldgyro;
+ unsigned int sleepval_us;
+ unsigned int val;
+ s64 disable_wait;
+ int ret;
+
+ ret = inv_icm42607_get_pwr_mgmt0(st, &oldgyro, &oldaccel);
+ if (ret)
+ return ret;
+
+ if (gyro == oldgyro && accel == oldaccel)
+ return 0;
+
+ /*
+ * Datasheet on page 14.26 says we need to ensure the gyro sensor is on
+ * for a minimum of 45ms. So if we transition from an on state to an
+ * off state make sure at least 45ms have passed before power off and
+ * wait if it hasn't. In case some platforms don't respond well to a
+ * sleep of 0, make sure the fsleep duration is > 0.
+ */
+ if (!gyro && oldgyro) {
+ disable_wait = clamp(ktime_us_delta(st->conf.gyro_stop, ktime_get()),
+ 0, INV_ICM42607_GYRO_STOP_TIME_US);
+
+ if (disable_wait > 0)
+ fsleep(disable_wait);
+ }
+
+ val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro) |
+ FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel);
+ ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+ if (ret)
+ return ret;
+
+ /*
+ * If a state change occurs from off to on, sleep for the startup
+ * time of the sensor, unless a sleep_ms is specified. Since more
+ * than one sensor can be transitioned from off to on, select the
+ * maximum time from each of the sensors changing from off to on.
+ * The startup time for the temp sensor is considerably smaller
+ * than the startup time for the other sensors and one or more are
+ * required to be on for the temp sensor to function, so any start
+ * delay should be enough.
+ */
+ sleepval_us = 0;
+ if (accel && !oldaccel)
+ sleepval_us = max(sleepval_us, INV_ICM42607_ACCEL_STARTUP_TIME_US);
+
+ if (gyro && !oldgyro) {
+ sleepval_us = max(sleepval_us, INV_ICM42607_GYRO_STARTUP_TIME_US);
+ /* Track the earliest we can turn off the gyroscope. */
+ st->conf.gyro_stop = ktime_add_us(ktime_get(),
+ INV_ICM42607_GYRO_STOP_TIME_US);
+ }
+
+ /*
+ * Only sleep if sleepval_us is greater than 0 in case some
+ * platforms have issues with a 0 delay. The 0 delay can happen
+ * if one or both sensors is shut down.
+ */
+ if (sleepval_us > 0)
+ fsleep(sleepval_us);
+
+ return 0;
+}
+
static int inv_icm42607_set_init_conf(struct inv_icm42607_state *st,
const struct inv_icm42607_conf *conf)
{
@@ -212,12 +303,17 @@ static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
{
int ret;
+ if (st->vddio_en)
+ return 0;
+
ret = regulator_enable(st->vddio_supply);
if (ret)
return ret;
fsleep(INV_ICM42607_POWER_UP_TIME_US);
+ st->vddio_en = true;
+
return 0;
}
@@ -225,7 +321,12 @@ static void inv_icm42607_disable_vddio_reg(void *_data)
{
struct inv_icm42607_state *st = _data;
+ if (!st->vddio_en)
+ return;
+
regulator_disable(st->vddio_supply);
+
+ st->vddio_en = false;
}
int inv_icm42607_core_probe(struct regmap *regmap,
@@ -240,6 +341,8 @@ int inv_icm42607_core_probe(struct regmap *regmap,
if (!st)
return -ENOMEM;
+ dev_set_drvdata(dev, st);
+
ret = devm_mutex_init(dev, &st->lock);
if (ret)
return ret;
@@ -275,10 +378,75 @@ int inv_icm42607_core_probe(struct regmap *regmap,
if (ret)
return ret;
+ ret = devm_pm_runtime_set_active_enabled(dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+
return 0;
}
EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
+static int inv_icm42607_suspend(struct device *dev)
+{
+ struct inv_icm42607_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
+
+ inv_icm42607_disable_vddio_reg(st);
+
+ return 0;
+}
+
+static int inv_icm42607_resume(struct device *dev)
+{
+ struct inv_icm42607_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ ret = inv_icm42607_enable_vddio_reg(st);
+ if (ret)
+ return ret;
+
+ /* Sync the regcache again after regulator shutdown. */
+ regcache_mark_dirty(st->map);
+ ret = regcache_sync(st->map);
+ if (ret)
+ return ret;
+
+ return pm_runtime_force_resume(dev);
+}
+
+static int inv_icm42607_runtime_suspend(struct device *dev)
+{
+ struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+ guard(mutex)(&st->lock);
+
+ /*
+ * Set sensors state to off. Since we only support one-shot
+ * today we can use runtime PM to turn sensors off when not
+ * in use, and then when needed the reads/writes will
+ * re-enable the sensors as needed. This reduces complexity,
+ * however the tradeoff is that an unused sensor won't be
+ * turned off until the entire chip is no longer in use.
+ */
+ st->conf.gyro.mode = INV_ICM42607_SENSOR_MODE_OFF;
+ st->conf.accel.mode = INV_ICM42607_SENSOR_MODE_OFF;
+
+ return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode,
+ st->conf.accel.mode);
+}
+
+EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = {
+ SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume)
+ RUNTIME_PM_OPS(inv_icm42607_runtime_suspend, NULL, NULL)
+};
+
MODULE_AUTHOR("InvenSense, Inc.");
MODULE_DESCRIPTION("InvenSense ICM-42607 device driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
index f2b9067815b0..04ad37291783 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -8,6 +8,7 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include "inv_icm42607.h"
@@ -56,6 +57,11 @@ static int inv_icm42607_probe(struct i2c_client *client)
return inv_icm42607_core_probe(regmap, hw, inv_icm42607_i2c_bus_setup);
}
+static void inv_icm42607_i2c_remove(struct i2c_client *client)
+{
+ pm_runtime_force_suspend(&client->dev);
+}
+
static const struct i2c_device_id inv_icm42607_id[] = {
{
.name = "icm42607",
@@ -84,9 +90,11 @@ static struct i2c_driver inv_icm42607_driver = {
.driver = {
.name = "inv-icm42607-i2c",
.of_match_table = inv_icm42607_of_matches,
+ .pm = pm_ptr(&inv_icm42607_pm_ops),
},
.id_table = inv_icm42607_id,
.probe = inv_icm42607_probe,
+ .remove = inv_icm42607_i2c_remove,
};
module_i2c_driver(inv_icm42607_driver);
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
index eb04036a6712..995393dce942 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -7,6 +7,7 @@
#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -65,6 +66,11 @@ static int inv_icm42607_probe(struct spi_device *spi)
return inv_icm42607_core_probe(regmap, hw, inv_icm42607_spi_bus_setup);
}
+static void inv_icm42607_spi_remove(struct spi_device *spi)
+{
+ pm_runtime_force_suspend(&spi->dev);
+}
+
static const struct spi_device_id inv_icm42607_spi_id_table[] = {
{
.name = "icm42607",
@@ -94,9 +100,11 @@ static struct spi_driver inv_icm42607_driver = {
.driver = {
.name = "inv-icm42607-spi",
.of_match_table = inv_icm42607_of_matches,
+ .pm = pm_ptr(&inv_icm42607_pm_ops),
},
.id_table = inv_icm42607_spi_id_table,
.probe = inv_icm42607_probe,
+ .remove = inv_icm42607_spi_remove,
};
module_spi_driver(inv_icm42607_driver);
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox