Devicetree
 help / color / mirror / Atom feed
* [PATCH v3 0/2] hwmon: (pmbus) Add Analog Devices MAX16545/MAX16550 and Volterra VT7505 driver
From: Pradhan, Sanman @ 2026-07-24 16:49 UTC (permalink / raw)
  To: linux-hwmon@vger.kernel.org
  Cc: linux@roeck-us.net, robh@kernel.org, krzk+dt@kernel.org,
	krzk@kernel.org, conor+dt@kernel.org, corbet@lwn.net,
	skhan@linuxfoundation.org, devicetree@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	Sanman Pradhan

From: Sanman Pradhan <psanman@juniper.net>

This series adds a PMBus driver for the Analog Devices MAX16545 and
MAX16550, and the Volterra VT7505 controllers.

The driver reports input and output voltage, input and output current,
input power, and temperature over PMBus. All sensors use the direct data
format. Peak input voltage, output voltage, output current, input power
and temperature readings are exposed and can be reset.

The MAX16545 uses the same programming model as the VT7505 and is
described with a fallback compatible.

The current and power scaling depend on the external current-report
resistor on the ILOAD pin, which can be specified with the
"adi,rload-ohms" device tree property. On the MAX16550 and VT7505, the
severe overcurrent-protection deglitch time can optionally be programmed
with the "adi,ocp-severe-filter-us" property; on the MAX16545 that delay
is fixed, so the property is rejected for that part.

The driver was tested on Juniper PTX hardware.

Changes in v3:
- dt-bindings: clarify that adi,rload-ohms is the ILOAD telemetry
  resistor, not a current-path shunt; note that the severe-OCP filter
  retains the existing hardware setting when omitted, and add it to the
  example; move additionalProperties after the allOf block.
- driver: use per-device match data instead of an enum (no zero-valued
  match data), derive the temperature coefficients and severe-OCP filter
  support from it, add an explicit adi,max16545 match entry, and replace
  the SPDX-FileCopyrightText tag with a plain copyright line.

Changes in v2:
- dt-bindings: represent the severe-OCP deglitch filter in microseconds
  (renamed to adi,ocp-severe-filter-us, values 0/1/2/10).
- driver: map the microsecond value to the MFR_CONFIG[15:14] field.



Georgi Vlaev (1):
  hwmon: (pmbus/vt7505) Add driver for Analog Devices MAX16545/MAX16550
    and Volterra VT7505

Sanman Pradhan (1):
  dt-bindings: hwmon: pmbus: Add Analog Devices MAX16545/MAX16550 and
    Volterra VT7505

 .../bindings/hwmon/pmbus/adi,vt7505.yaml      |  84 ++++++
 Documentation/hwmon/index.rst                 |   1 +
 Documentation/hwmon/vt7505.rst                |  89 ++++++
 MAINTAINERS                                   |   8 +
 drivers/hwmon/pmbus/Kconfig                   |   9 +
 drivers/hwmon/pmbus/Makefile                  |   1 +
 drivers/hwmon/pmbus/vt7505.c                  | 284 ++++++++++++++++++
 7 files changed, 476 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwmon/pmbus/adi,vt7505.yaml
 create mode 100644 Documentation/hwmon/vt7505.rst
 create mode 100644 drivers/hwmon/pmbus/vt7505.c


base-commit: fa8ff8bde9207509f90adacc157b208ee732adad
-- 
2.34.1


^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: dpll: zl3073x: add ZL30643 compatible
From: Conor Dooley @ 2026-07-24 16:46 UTC (permalink / raw)
  To: vjardin
  Cc: Ivan Vecera, Prathosh Satish, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
	netdev, devicetree, linux-kernel
In-Reply-To: <20260724-for-upstream-zl30643-v1-1-ea93ba4d85c8@free.fr>

[-- Attachment #1: Type: text/plain, Size: 1086 bytes --]

On Fri, Jul 24, 2026 at 01:09:12AM +0200, Vincent Jardin via B4 Relay wrote:
> From: Vincent Jardin <vjardin@free.fr>
> 
> The Microchip ZL30643 (chip ID 0x0E3B) is a 3 DPLL channel member
> of the ZL3073x family. Add its compatible string to the binding enum.
> 
> Signed-off-by: Vincent Jardin <vjardin@free.fr>

What about this device makes it incomaptible with existing ones?

Cheers,
Conor.

> ---
>  Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml b/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
> index fa5a8f8e390c..13ea55c2c146 100644
> --- a/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
> +++ b/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
> @@ -18,6 +18,7 @@ description:
>  properties:
>    compatible:
>      enum:
> +      - microchip,zl30643
>        - microchip,zl30731
>        - microchip,zl30732
>        - microchip,zl30733
> 
> -- 
> 2.43.0
> 
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH v2 6/7] arm64: dts: freescale: imx8mm-verdin: Add Cortex-M4F remoteproc
From: sashiko-bot @ 2026-07-24 16:41 UTC (permalink / raw)
  To: Ernest Van Hoecke; +Cc: devicetree, Frank.Li, robh, imx, conor+dt
In-Reply-To: <20260724-v1-verdin-imx8mm-dtbos-v2-6-9d7988bd76f6@toradex.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Unconditional enablement of the Cortex-M4 co-processor and its memory reservations in a base SoM device tree file.
--

--- Patch [6]: [PATCH v2 6/7] arm64: dts: freescale: imx8mm-verdin: Add Cortex-M4F remoteproc ---
commit 5627e466b821e2ae1d5d44438ab0c467605d30f9
Author: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>

arm64: dts: freescale: imx8mm-verdin: Add Cortex-M4F remoteproc

This patch describes the Cortex-M4F remote processor available on the
Verdin iMX8M Mini SoM.

> diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
> index 5fc177f589cb2..ac450fc6cbfb3 100644
> --- a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
> @@ -52,6 +52,18 @@ hdmi_connector: hdmi-connector {
>  		status = "disabled";
>  	};
>  
> +	imx8mm-cm4 {
> +		compatible = "fsl,imx8mm-cm4";
> +		clocks = <&clk IMX8MM_CLK_M4_DIV>;

[Severity: Medium]
Should this node default to disabled?

Because it is added unconditionally to the base SoM dtsi, it defaults
to "okay". This causes the imx_rproc driver to bind and call
devm_clk_get_enabled() during probe, which keeps the IMX8MM_CLK_M4_DIV
clock permanently running even if the M4 firmware is never booted.

> +		mbox-names = "tx", "rx", "rxdb";
> +		mboxes = <&mu 0 1
> +			  &mu 1 1
> +			  &mu 3 1>;
> +		memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>,
> +				<&rsc_table>;
> +		syscon = <&src>;
> +	};
> +

[ ... ]

> @@ -164,6 +176,27 @@ reserved-memory {
>  
>  		/* Use the kernel configuration settings instead */
>  		/delete-node/ linux,cma;
> +
> +		vdev0vring0: vdev0vring0@55000000 {
> +			reg = <0 0x55000000 0 0x8000>;
> +			no-map;
> +		};
> +
> +		vdev0vring1: vdev0vring1@55008000 {
> +			reg = <0 0x55008000 0 0x8000>;
> +			no-map;
> +		};
> +
> +		rsc_table: rsc-table@550ff000 {
> +			reg = <0 0x550ff000 0 0x1000>;
> +			no-map;
> +		};
> +
> +		vdev0buffer: vdev0buffer@55400000 {
> +			compatible = "shared-dma-pool";
> +			reg = <0 0x55400000 0 0x100000>;
> +			no-map;
> +		};

[Severity: Medium]
Are we sure we want to unconditionally reserve these memory regions for
all boards using this base SoM?

Because of the no-map properties, this removes roughly 1.1MB of RAM
from the kernel's linear mapping permanently across all Verdin i.MX8MM
boards, even when the M4 coprocessor is not used.

>  	};
>  };

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-v1-verdin-imx8mm-dtbos-v2-0-9d7988bd76f6@toradex.com?part=6

^ permalink raw reply

* Re: [PATCH v5 3/3] hwmon: pmbus: add MPQ8646 driver
From: Markus Elfring @ 2026-07-24 16:40 UTC (permalink / raw)
  To: Vincent Jardin, linux-hwmon, devicetree, Conor Dooley,
	Günter Röck, Jonathan Corbet, Krzysztof Kozlowski,
	Rob Herring, Shuah Khan
  Cc: linux-doc, LKML
In-Reply-To: <20260724-mpq8646_v0-v5-3-5915b5ae9aa2@free.fr>

…
> +++ b/drivers/hwmon/pmbus/mpq8646.c
> @@ -0,0 +1,1253 @@
> +static int mpq8646_dbg_probe_smbus_rword(void *data, u64 val)
> +{
> +	mutex_lock(&priv->mps_lock);
> +	rc = i2c_smbus_read_word_data(priv->client, (u8)val);
> +	mutex_unlock(&priv->mps_lock);
> +	return 0;
> +}
…

Under which circumstances would you become interested to apply a statement
like “guard(mutex)(&priv->mps_lock);”?
https://elixir.bootlin.com/linux/v7.2-rc4/source/include/linux/mutex.h#L253

Regards,
Markus

^ permalink raw reply

* Re: [PATCH v3] dt-bindings: leds: lacie,ns2-leds: Convert to DT schema
From: sashiko-bot @ 2026-07-24 16:36 UTC (permalink / raw)
  To: Ninad Naik; +Cc: conor+dt, lee, robh, devicetree, linux-leds
In-Reply-To: <20260724162332.32291-1-ninadnaik07@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The top-level `additionalProperties` is incorrectly defined as a child-node schema, causing it to incorrectly reject standard device tree properties.
--

--- Patch [1]: [PATCH v3] dt-bindings: leds: lacie,ns2-leds: Convert to DT schema ---
commit 2e02c3a2b329288ad4aeeb155d96aec6b772c421
Author: Ninad Naik <ninadnaik07@gmail.com>

dt-bindings: leds: lacie,ns2-leds: Convert to DT schema

Convert lacie,ns2-leds to DT schema.

Closes: https://lore.kernel.org/r/202607231542.6ovJrInT-lkp@intel.com/

> diff --git a/Documentation/devicetree/bindings/leds/lacie,ns2-leds.yaml b/Documentation/devicetree/bindings/leds/lacie,ns2-leds.yaml
> new file mode 100644
> index 0000000000000..2138c75c04133
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/lacie,ns2-leds.yaml
[ ... ]
> +properties:
> +  compatible:
> +    const: lacie,ns2-leds
> +
> +additionalProperties:
> +  type: object
> +  $ref: common.yaml#
> +  unevaluatedProperties: false

[Severity: Medium]
Does this incorrectly apply an object constraint to all unspecified top-level
properties? 

It appears this schema logic will cause valid device trees containing standard
non-object properties (like status or pinctrl-0) to fail validation during
make dtbs_check. 

Should child nodes instead be matched using patternProperties, with
additionalProperties: false or unevaluatedProperties: false used at the top
level to allow standard DT properties?

> +
> +  description: Each child node represents a single LED
> +
> +  properties:
> +    cmd-gpio:
[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724162332.32291-1-ninadnaik07@gmail.com?part=1

^ permalink raw reply

* Re: [RFC PATCH 1/8] ASoC: SDCA: hw_params: program upstream Input Terminals for OT DAI
From: Srinivas Kandagatla @ 2026-07-24 16:35 UTC (permalink / raw)
  To: Charles Keepax
  Cc: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
	Maciej Strozek, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Srinivas Kandagatla, Bard Liao, Pierre-Louis Bossart,
	Richard Fitzgerald, Jorijn van der Graaf, linux-sound,
	linux-arm-msm, devicetree, patches, linux-kernel
In-Reply-To: <amNlSu3mcwKOmqvf@opensource.cirrus.com>

On 7/24/26 2:14 PM, Charles Keepax wrote:
> On Thu, Jul 23, 2026 at 12:42:11AM +0100, Srinivas Kandagatla wrote:
>> For a capture stream the DAI is the Output Terminal so
>> sdca_asoc_hw_params() only programs the OT itself: cluster, clock
>> and Usage.  The upstream Input Terminals that actually source the
>> audio never get their Usage, ClusterIndex or clock programmed, so
>> the power domain comes up but no samples are produced.
>>
>> Walk the source graph from the OT and program every Input Terminal
>> reachable through it.
> 
> What was the thinking with respect to the units in the middle?

As per $6.3.2.1 and 6.3.2.2
FUs does not modify the cluster, its transparent to cluster, Output Pin
uses same cluster as input pin

--srini
> It's not clear to me things are quite as simple as we can copy the
> cluster from the output terminal to the input terminal. Various
> entities in the middle could change the cluster, such as CRUs,
> MPFUs, UDMPUs. Also possibly SUs to consider too, since they
> may change which ITs are actually connected at that point in time,
> although potentially an argument to be made that programming the
> unconnected ones would have no ill effects I guess.
> 
> Any thoughts as well on the propogation of the clock and usage.
> Its a little less clear to me from the spec that they are even
> intended to propogate in this fashion, although it does seem
> fairly logical to me.
> 
> Thanks,
> Charles


^ permalink raw reply

* Re: [RFC PATCH 0/8] ASoC: SDCA: enable on DT platforms and add Qualcomm WCD9378 (Tambora) codec
From: Srinivas Kandagatla @ 2026-07-24 16:29 UTC (permalink / raw)
  To: Charles Keepax
  Cc: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
	Maciej Strozek, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Srinivas Kandagatla, Bard Liao, Pierre-Louis Bossart,
	Richard Fitzgerald, Jorijn van der Graaf, linux-sound,
	linux-arm-msm, devicetree, patches, linux-kernel
In-Reply-To: <amOHgSiSfm2MgQqB@opensource.cirrus.com>

On 7/24/26 4:40 PM, Charles Keepax wrote:
> On Fri, Jul 24, 2026 at 03:31:51PM +0100, Srinivas Kandagatla wrote:
>> On 7/24/26 1:36 PM, Charles Keepax wrote:
>>> On Thu, Jul 23, 2026 at 02:24:19PM +0100, Srinivas Kandagatla wrote:
>>>> Thanks Charles, for the feedback.
>>>> On 7/23/26 11:17 AM, Charles Keepax wrote:
>>>>> On Thu, Jul 23, 2026 at 12:42:10AM +0100, Srinivas Kandagatla wrote:
>>> Yeah agree be good to get the DT guys thoughts on this. It seems
>>> like a misstep to me to insist that the SDCA spec implements a
>>> completely different system of storing information for DT. SDCA
>>> is what SDCA is now, and supporting two different parsers seems
>>> like work no one needs when the one parser we have would work
>>> fine for both.
>> Am not sure I understood the two parser concern, what we are
>> representing in the table is something that sdca core already does after
>> parsing acpi tables. So we are reusing the same structures. Its like
>> result of already parsed acpi tables.
>>
>> I did try
> 
> Apologies for not being clear. It wasn't strictly a review
> comment on the code in the series. It was a wider point that at
> some point the world likely will want to put SDCA data in DT,
> when that happens there are basically two choices:
> 
> 1) Use the "same" representation as ACPI, in this case we can
> share all the parsing code we have now. But some of the things
> might be a little unusual for DT.
> 
> 2) Do something more idiomatic for DT, which would likely end
> up looking very different. But this would require a whole new
> parser and lengthy standardisation process.
> 
I'm inclined to go with this approach as well, provided the Device Tree
maintainers are satisfied with the initialization sequences. The rest of
the topology bindings appears solid.

This decision would also establish a precedent for handling other
DisCo-based devices in Device Trees.

> Mostly what I am interested in here is getting at what the end
> goal is. The impression I got was that really everyone from
> Plumbers was really more aligned to 2). I am not sure I agree
> that is the right choice, although willing to be convinced here.
> 
>>> That said I don't totally object to the idea of an option to
>>> supply a static block of information as you are in the series. It
>>> could be useful for transitional and work around situations. But
>>> it doesn't seem like a good choice for SDCA on DT going forward,
>>> it is basically going back to the board files that DT was saving
>>> us from.
>>
>> Either we have this at driver level or at dt level, both of them have
>> pros and cons.
>>
>> If we decide to go with dt, this how the dt entries will look like, this
>> should give fair bit of idea to DT maintianers for discussion.
> 
> Thank you so much for mocking this up, that is very helpful.
> 
> Are there additional constraints from your side pushing you
> one way or another on this? Or are you happy to do either? I am
> thinking things like DT needing to be flashed onto systems that
> have now shipped or something.
No restrictions as such, its just consensuses with DT maintainers.

--srini
> 
> Thanks,
> Charles


^ permalink raw reply

* [PATCH v3] dt-bindings: leds: lacie,ns2-leds: Convert to DT schema
From: Ninad Naik @ 2026-07-24 16:23 UTC (permalink / raw)
  To: lee, pavel, robh, krzk+dt, conor+dt, simon.guinot
  Cc: linux-leds, devicetree, linux-kernel, me, linux-kernel-mentees,
	skhan, Ninad Naik, kernel test robot

Convert lacie,ns2-leds to DT schema.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/r/202607231542.6ovJrInT-lkp@intel.com/
Signed-off-by: Ninad Naik <ninadnaik07@gmail.com>
---
Changes in v3:
- Add optional property num-modes to the schema.

 .../bindings/leds/lacie,ns2-leds.yaml         | 85 +++++++++++++++++++
 .../devicetree/bindings/leds/leds-ns2.txt     | 35 --------
 2 files changed, 85 insertions(+), 35 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/leds/lacie,ns2-leds.yaml
 delete mode 100644 Documentation/devicetree/bindings/leds/leds-ns2.txt

diff --git a/Documentation/devicetree/bindings/leds/lacie,ns2-leds.yaml b/Documentation/devicetree/bindings/leds/lacie,ns2-leds.yaml
new file mode 100644
index 000000000000..2138c75c0413
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/lacie,ns2-leds.yaml
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/lacie,ns2-leds.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Dual-GPIO LEDs found on Network Space v2 (and parents)
+
+maintainers:
+  - Simon Guinot <simon.guinot@sequanux.org>
+
+description:
+  The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED
+  modes are available, off, on and SATA activity blinking. The LED modes are
+  controlled through two GPIOs (command and slow), each combination of values
+  for the command/slow GPIOs corresponds to a LED mode.
+
+properties:
+  compatible:
+    const: lacie,ns2-leds
+
+additionalProperties:
+  type: object
+  $ref: common.yaml#
+  unevaluatedProperties: false
+
+  description: Each child node represents a single LED
+
+  properties:
+    cmd-gpio:
+      maxItems: 1
+      description: GPIO connected to the command LED output
+
+    slow-gpio:
+      maxItems: 1
+      description: GPIO connected to the slow LED output
+
+    num-modes:
+      $ref: /schemas/types.yaml#/definitions/uint32
+      description:
+        Number of entries in modes-map.
+
+    modes-map:
+      $ref: /schemas/types.yaml#/definitions/uint32-matrix
+      description:
+        A mapping between LED modes (off, on or SATA activity blinking) and
+        the corresponding cmd-gpio/slow-gpio values. All the GPIO values
+        combinations should be given in order to avoid having an unknown
+        mode at driver probe time.
+
+      items:
+        items:
+          - description: LED mode
+            enum: [0, 1, 2]
+          - description: Command GPIO level
+            enum: [0, 1]
+          - description: Slow GPIO level
+            enum: [0, 1]
+
+  required:
+    - cmd-gpio
+    - slow-gpio
+    - modes-map
+
+required:
+  - compatible
+
+examples:
+  - |
+    #include <dt-bindings/leds/leds-ns2.h>
+
+    led-controller {
+        compatible = "lacie,ns2-leds";
+
+        led-0 {
+            label = "ns2:blue:sata";
+            slow-gpio = <&gpio0 29 0>;
+            cmd-gpio = <&gpio0 30 0>;
+            modes-map = <NS_V2_LED_OFF  0 1
+                         NS_V2_LED_ON   1 0
+                         NS_V2_LED_ON   0 0
+                         NS_V2_LED_SATA 1 1>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/leds/leds-ns2.txt b/Documentation/devicetree/bindings/leds/leds-ns2.txt
deleted file mode 100644
index 9f81258a5b6e..000000000000
--- a/Documentation/devicetree/bindings/leds/leds-ns2.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-Binding for dual-GPIO LED found on Network Space v2 (and parents).
-
-Required properties:
-- compatible: "lacie,ns2-leds".
-
-Each LED is represented as a sub-node of the ns2-leds device.
-
-Required sub-node properties:
-- cmd-gpio: Command LED GPIO. See OF device-tree GPIO specification.
-- slow-gpio: Slow LED GPIO. See OF device-tree GPIO specification.
-- modes-map: A mapping between LED modes (off, on or SATA activity blinking) and
-  the corresponding cmd-gpio/slow-gpio values. All the GPIO values combinations
-  should be given in order to avoid having an unknown mode at driver probe time.
-
-Optional sub-node properties:
-- label: Name for this LED. If omitted, the label is taken from the node name.
-- linux,default-trigger: Trigger assigned to the LED.
-
-Example:
-
-#include <dt-bindings/leds/leds-ns2.h>
-
-ns2-leds {
-	compatible = "lacie,ns2-leds";
-
-	blue-sata {
-		label = "ns2:blue:sata";
-		slow-gpio = <&gpio0 29 0>;
-		cmd-gpio = <&gpio0 30 0>;
-		modes-map = <NS_V2_LED_OFF  0 1
-			     NS_V2_LED_ON   1 0
-			     NS_V2_LED_ON   0 0
-			     NS_V2_LED_SATA 1 1>;
-	};
-};
-- 
2.55.0


^ permalink raw reply related

* [PATCH v2 7/7] arm64: dts: freescale: imx8mm-verdin: Add Cortex-M4F UART_4 overlay
From: Ernest Van Hoecke @ 2026-07-24 16:24 UTC (permalink / raw)
  To: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kieran Bingham
  Cc: Francesco Dolcini, imx, linux-arm-kernel, devicetree,
	linux-kernel, Ernest Van Hoecke
In-Reply-To: <20260724-v1-verdin-imx8mm-dtbos-v2-0-9d7988bd76f6@toradex.com>

From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>

Verdin UART_4 can be assigned to Cortex-M4F firmware. Add an overlay
that marks the UART as reserved so Linux does not claim the port.

The overlay is also combined with the Verdin iMX8M Mini Development
Board device tree to provide a ready-to-use DTB for the WiFi SoM
variant.

Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
---
 arch/arm64/boot/dts/freescale/Makefile                     |  3 +++
 arch/arm64/boot/dts/freescale/imx8mm-verdin-uart4-mcu.dtso | 14 ++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index fe261d7bdab5..95ae85ab4adf 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -192,6 +192,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-zinnia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-panel-cap-touch-10inch-dsi.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-panel-cap-touch-7inch-dsi.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-uart4-mcu.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia-panel-cap-touch-10inch-dsi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb
@@ -199,6 +200,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-nau8822-btl.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-panel-cap-touch-7inch-dsi.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-uart4-mcu.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-ivy.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-mallow.dtb
@@ -220,6 +222,7 @@ imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := imx8mm-verdin-
 imx8mm-verdin-wifi-dev-nau8822-btl-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-dev-nau8822-btl.dtbo
 imx8mm-verdin-wifi-dev-panel-cap-touch-7inch-dsi-dtbs := imx8mm-verdin-wifi-dev.dtb \
 	imx8mm-verdin-panel-cap-touch-7inch-dsi.dtbo
+imx8mm-verdin-wifi-dev-uart4-mcu-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-uart4-mcu.dtbo
 imx8mm-verdin-wifi-yavia-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-yavia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 
 imx8mm-tqma8mqml-mba8mx-lvds-g133han01-dtbs += imx8mm-tqma8mqml-mba8mx.dtb imx8mm-tqma8mqml-mba8mx-lvds-g133han01.dtbo
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-uart4-mcu.dtso b/arch/arm64/boot/dts/freescale/imx8mm-verdin-uart4-mcu.dtso
new file mode 100644
index 000000000000..8dbecffe9e7b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-uart4-mcu.dtso
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Verdin iMX8M Mini UART_4 for Cortex-M4F
+ */
+
+/dts-v1/;
+/plugin/;
+
+/* Verdin UART_4 */
+&uart4 {
+	status = "reserved";
+};

-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 6/7] arm64: dts: freescale: imx8mm-verdin: Add Cortex-M4F remoteproc
From: Ernest Van Hoecke @ 2026-07-24 16:24 UTC (permalink / raw)
  To: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kieran Bingham
  Cc: Francesco Dolcini, imx, linux-arm-kernel, devicetree,
	linux-kernel, Ernest Van Hoecke
In-Reply-To: <20260724-v1-verdin-imx8mm-dtbos-v2-0-9d7988bd76f6@toradex.com>

From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>

Describe the Cortex-M4F remote processor available on the Verdin iMX8M
Mini SoM.

Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
---
 arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi | 33 ++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
index 5fc177f589cb..ac450fc6cbfb 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
@@ -52,6 +52,18 @@ hdmi_connector: hdmi-connector {
 		status = "disabled";
 	};
 
+	imx8mm-cm4 {
+		compatible = "fsl,imx8mm-cm4";
+		clocks = <&clk IMX8MM_CLK_M4_DIV>;
+		mbox-names = "tx", "rx", "rxdb";
+		mboxes = <&mu 0 1
+			  &mu 1 1
+			  &mu 3 1>;
+		memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>,
+				<&rsc_table>;
+		syscon = <&src>;
+	};
+
 	/* Carrier Board Supplies */
 	reg_1p8v: regulator-1p8v {
 		compatible = "regulator-fixed";
@@ -164,6 +176,27 @@ reserved-memory {
 
 		/* Use the kernel configuration settings instead */
 		/delete-node/ linux,cma;
+
+		vdev0vring0: vdev0vring0@55000000 {
+			reg = <0 0x55000000 0 0x8000>;
+			no-map;
+		};
+
+		vdev0vring1: vdev0vring1@55008000 {
+			reg = <0 0x55008000 0 0x8000>;
+			no-map;
+		};
+
+		rsc_table: rsc-table@550ff000 {
+			reg = <0 0x550ff000 0 0x1000>;
+			no-map;
+		};
+
+		vdev0buffer: vdev0buffer@55400000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x55400000 0 0x100000>;
+			no-map;
+		};
 	};
 };
 

-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 5/7] arm64: dts: freescale: imx8mm-verdin: Add Toradex Capacitive Touch Display 7" DSI
From: Ernest Van Hoecke @ 2026-07-24 16:24 UTC (permalink / raw)
  To: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kieran Bingham
  Cc: Francesco Dolcini, imx, linux-arm-kernel, devicetree,
	linux-kernel, Ernest Van Hoecke
In-Reply-To: <20260724-v1-verdin-imx8mm-dtbos-v2-0-9d7988bd76f6@toradex.com>

From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>

Add a device tree overlay for the Toradex Capacitive Touch Display 7"
on the Verdin DSI_1 interface. The display features an internal Texas
Instruments SN65DSI83 DSI-to-LVDS bridge driving a Riverdi
RVT70HSLNWCA0 7" WSVGA IPS TFT LCD panel. The touch input is provided
by an Ilitek ILI2132 capacitive touch controller.

Link: https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-7inch-dsi
Link: https://developer.toradex.com/hardware/accessories/add-ons/dsi-display-adapter
Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   4 +
 .../imx8mm-verdin-panel-cap-touch-7inch-dsi.dtso   | 129 +++++++++++++++++++++
 2 files changed, 133 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 00dc2893c754..fe261d7bdab5 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -191,12 +191,14 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-zinnia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-panel-cap-touch-10inch-dsi.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-panel-cap-touch-7inch-dsi.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia-panel-cap-touch-10inch-dsi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-nau8822-btl.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-panel-cap-touch-7inch-dsi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-ivy.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-mallow.dtb
@@ -216,6 +218,8 @@ imx8mm-verdin-wifi-dev-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-ver
 imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := imx8mm-verdin-wifi-dev.dtb \
 	imx8mm-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
 imx8mm-verdin-wifi-dev-nau8822-btl-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-dev-nau8822-btl.dtbo
+imx8mm-verdin-wifi-dev-panel-cap-touch-7inch-dsi-dtbs := imx8mm-verdin-wifi-dev.dtb \
+	imx8mm-verdin-panel-cap-touch-7inch-dsi.dtbo
 imx8mm-verdin-wifi-yavia-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-yavia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 
 imx8mm-tqma8mqml-mba8mx-lvds-g133han01-dtbs += imx8mm-tqma8mqml-mba8mx.dtb imx8mm-tqma8mqml-mba8mx-lvds-g133han01.dtbo
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-panel-cap-touch-7inch-dsi.dtso b/arch/arm64/boot/dts/freescale/imx8mm-verdin-panel-cap-touch-7inch-dsi.dtso
new file mode 100644
index 000000000000..0e15b4b3f3ec
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-panel-cap-touch-7inch-dsi.dtso
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Toradex Capacitive Touch Display 7" on Verdin DSI_1.
+ * On Dahlia (X17) and Development Board (X48), DSI_1 is exposed via a
+ * Samtec LSS-130 connector and requires the Toradex DSI Display Adapter
+ * to convert to FFC/FPC connector.
+ *
+ * https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-7inch-dsi
+ * https://www.toradex.com/accessories/capacitive-touch-display-7-inch-dsi
+ * https://developer.toradex.com/hardware/accessories/add-ons/dsi-display-adapter
+ * https://www.toradex.com/accessories/verdin-dsi-display-adapter
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pwm/pwm.h>
+
+&{/} {
+	backlight_pwm3: backlight-pwm3 {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 45 63 88 119 158 203 255>;
+		default-brightness-level = <4>;
+		power-supply = <&reg_3p3v>;
+		/* Verdin PWM_3_DSI (SODIMM 19) */
+		pwms = <&pwm1 0 6666667 0>;
+	};
+
+	panel-lvds-bridge {
+		compatible = "riverdi,rvt70hslnwca0", "panel-lvds";
+		backlight = <&backlight_pwm3>;
+		data-mapping = "vesa-24";
+		height-mm = <86>;
+		width-mm = <154>;
+
+		panel-timing {
+			clock-frequency = <51200000>;
+			de-active = <1>;
+			hactive = <1024>;
+			hback-porch = <100 100 100>;
+			hfront-porch = <16 160 216>;
+			hsync-active = <0>;
+			hsync-len = <50 60 140>;
+			pixelclk-active = <1>;
+			vactive = <600>;
+			vback-porch = <23 23 23>;
+			vfront-porch = <1 12 126>;
+			vsync-active = <0>;
+			vsync-len = <1 10 20>;
+		};
+
+		port {
+			panel_lvds_bridge_in: endpoint {
+				remote-endpoint = <&dsi_lvds_bridge_out>;
+			};
+		};
+	};
+};
+
+/* Verdin I2C_2_DSI */
+&i2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	status = "okay";
+
+	bridge@2c {
+		compatible = "ti,sn65dsi83";
+		reg = <0x2c>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_10_dsi>;
+		/* Verdin GPIO_10_DSI (SODIMM 21) - DSI_1_BKL_EN */
+		enable-gpios = <&gpio3 3 GPIO_ACTIVE_HIGH>;
+		vcc-supply = <&reg_1p8v>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+
+				dsi_lvds_bridge_in: endpoint {
+					data-lanes = <1 2 3 4>;
+					remote-endpoint = <&mipi_dsi_out>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+
+				dsi_lvds_bridge_out: endpoint {
+					remote-endpoint = <&panel_lvds_bridge_in>;
+				};
+			};
+		};
+	};
+
+	touchscreen@41 {
+		compatible = "ilitek,ili2132";
+		reg = <0x41>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_9_dsi>, <&pinctrl_i2s_2_bclk_touch_reset>;
+		/* Verdin GPIO_9_DSI (SODIMM 17) - TOUCH_INT# */
+		/* Rising edge avoids spurious interrupts from the noisy falling edge. */
+		interrupt-parent = <&gpio3>;
+		interrupts = <15 IRQ_TYPE_EDGE_RISING>;
+		/* Verdin I2S_2_BCLK (SODIMM 42) - TOUCH_RESET# */
+		reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&lcdif {
+	status = "okay";
+};
+
+&mipi_dsi {
+	samsung,esc-clock-frequency = <16000000>;
+
+	status = "okay";
+};
+
+&mipi_dsi_out {
+	remote-endpoint = <&dsi_lvds_bridge_in>;
+};

-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 4/7] arm64: dts: freescale: imx8mm-verdin: Add Toradex Capacitive Touch Display 10.1" DSI
From: Ernest Van Hoecke @ 2026-07-24 16:24 UTC (permalink / raw)
  To: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kieran Bingham
  Cc: Francesco Dolcini, imx, linux-arm-kernel, devicetree,
	linux-kernel, Ernest Van Hoecke
In-Reply-To: <20260724-v1-verdin-imx8mm-dtbos-v2-0-9d7988bd76f6@toradex.com>

From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>

Add a device tree overlay for the Toradex Capacitive Touch Display
10.1" on the Verdin DSI_1 interface. The display features an internal
Texas Instruments SN65DSI83 DSI-to-LVDS bridge driving a Riverdi
RVT101HVLNWC00 10.1" WXGA IPS TFT LCD panel. The touch input is
provided by an Ilitek ILI2132 capacitive touch controller.

The overlay is also combined with the Verdin iMX8M Mini Dahlia carrier
board device trees to provide ready-to-use DTBs in both WiFi and
non-WiFi SoM variants.

Link: https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-101inch-dsi
Link: https://developer.toradex.com/hardware/accessories/add-ons/dsi-display-adapter
Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   7 ++
 .../imx8mm-verdin-panel-cap-touch-10inch-dsi.dtso  | 129 +++++++++++++++++++++
 2 files changed, 136 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 91ae54931818..00dc2893c754 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -181,6 +181,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-dev-nau8822-btl.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-dsi-to-hdmi.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia-dsi-to-hdmi.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia-panel-cap-touch-10inch-dsi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dev-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dev.dtb
@@ -189,7 +190,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-mallow.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-zinnia.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-panel-cap-touch-10inch-dsi.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia-dsi-to-hdmi.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia-panel-cap-touch-10inch-dsi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb
@@ -202,9 +205,13 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-yavia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-zinnia.dtb
 
 imx8mm-verdin-nonwifi-dahlia-dsi-to-hdmi-dtbs := imx8mm-verdin-nonwifi-dahlia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
+imx8mm-verdin-nonwifi-dahlia-panel-cap-touch-10inch-dsi-dtbs := imx8mm-verdin-nonwifi-dahlia.dtb \
+	imx8mm-verdin-panel-cap-touch-10inch-dsi.dtbo
 imx8mm-verdin-nonwifi-dev-dsi-to-hdmi-dtbs := imx8mm-verdin-nonwifi-dev.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 imx8mm-verdin-nonwifi-yavia-dsi-to-hdmi-dtbs := imx8mm-verdin-nonwifi-yavia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 imx8mm-verdin-wifi-dahlia-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-dahlia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
+imx8mm-verdin-wifi-dahlia-panel-cap-touch-10inch-dsi-dtbs := imx8mm-verdin-wifi-dahlia.dtb \
+	imx8mm-verdin-panel-cap-touch-10inch-dsi.dtbo
 imx8mm-verdin-wifi-dev-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := imx8mm-verdin-wifi-dev.dtb \
 	imx8mm-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-panel-cap-touch-10inch-dsi.dtso b/arch/arm64/boot/dts/freescale/imx8mm-verdin-panel-cap-touch-10inch-dsi.dtso
new file mode 100644
index 000000000000..5626903d668a
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-panel-cap-touch-10inch-dsi.dtso
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Toradex Capacitive Touch Display 10.1" on Verdin DSI_1.
+ * On Dahlia (X17) and Development Board (X48), DSI_1 is exposed via a
+ * Samtec LSS-130 connector and requires the Toradex DSI Display Adapter
+ * to convert to FFC/FPC connector.
+ *
+ * https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-101inch-dsi
+ * https://www.toradex.com/accessories/capacitive-touch-display-10.1-inch-dsi
+ * https://developer.toradex.com/hardware/accessories/add-ons/dsi-display-adapter
+ * https://www.toradex.com/accessories/verdin-dsi-display-adapter
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pwm/pwm.h>
+
+&{/} {
+	backlight_pwm3: backlight-pwm3 {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 45 63 88 119 158 203 255>;
+		default-brightness-level = <4>;
+		power-supply = <&reg_3p3v>;
+		/* Verdin PWM_3_DSI (SODIMM 19) */
+		pwms = <&pwm1 0 6666667 0>;
+	};
+
+	panel-lvds-bridge {
+		compatible = "riverdi,rvt101hvlnwc00", "panel-lvds";
+		backlight = <&backlight_pwm3>;
+		data-mapping = "vesa-24";
+		height-mm = <136>;
+		width-mm = <217>;
+
+		panel-timing {
+			clock-frequency = <71100000>;
+			de-active = <1>;
+			hactive = <1280>;
+			hback-porch = <64 64 64>;
+			hfront-porch = <36 36 36>;
+			hsync-active = <0>;
+			hsync-len = <24 24 24>;
+			pixelclk-active = <1>;
+			vactive = <800>;
+			vback-porch = <24 24 24>;
+			vfront-porch = <8 8 8>;
+			vsync-active = <0>;
+			vsync-len = <8 8 8>;
+		};
+
+		port {
+			panel_lvds_bridge_in: endpoint {
+				remote-endpoint = <&dsi_lvds_bridge_out>;
+			};
+		};
+	};
+};
+
+/* Verdin I2C_2_DSI */
+&i2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	status = "okay";
+
+	bridge@2c {
+		compatible = "ti,sn65dsi83";
+		reg = <0x2c>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_10_dsi>;
+		/* Verdin GPIO_10_DSI (SODIMM 21) - DSI_1_BKL_EN */
+		enable-gpios = <&gpio3 3 GPIO_ACTIVE_HIGH>;
+		vcc-supply = <&reg_1p8v>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+
+				dsi_lvds_bridge_in: endpoint {
+					data-lanes = <1 2 3 4>;
+					remote-endpoint = <&mipi_dsi_out>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+
+				dsi_lvds_bridge_out: endpoint {
+					remote-endpoint = <&panel_lvds_bridge_in>;
+				};
+			};
+		};
+	};
+
+	touchscreen@41 {
+		compatible = "ilitek,ili2132";
+		reg = <0x41>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_9_dsi>, <&pinctrl_i2s_2_bclk_touch_reset>;
+		/* Verdin GPIO_9_DSI (SODIMM 17) - TOUCH_INT# */
+		/* Rising edge avoids spurious interrupts from the noisy falling edge. */
+		interrupt-parent = <&gpio3>;
+		interrupts = <15 IRQ_TYPE_EDGE_RISING>;
+		/* Verdin I2S_2_BCLK (SODIMM 42) - TOUCH_RESET# */
+		reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&lcdif {
+	status = "okay";
+};
+
+&mipi_dsi {
+	samsung,esc-clock-frequency = <16000000>;
+
+	status = "okay";
+};
+
+&mipi_dsi_out {
+	remote-endpoint = <&dsi_lvds_bridge_in>;
+};

-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 3/7] arm64: dts: freescale: imx8mm-verdin: Add Toradex DSI to LVDS adapter with 10.1" display
From: Ernest Van Hoecke @ 2026-07-24 16:24 UTC (permalink / raw)
  To: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kieran Bingham
  Cc: Francesco Dolcini, imx, linux-arm-kernel, devicetree,
	linux-kernel, Ernest Van Hoecke
In-Reply-To: <20260724-v1-verdin-imx8mm-dtbos-v2-0-9d7988bd76f6@toradex.com>

From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>

Add a device tree overlay for the Toradex DSI to LVDS Adapter with the
Toradex Capacitive Touch Display 10.1" LVDS. The adapter connects to the
Verdin DSI_1 interface. It is based on the Texas Instruments SN65DSI84
DSI-to-LVDS bridge and drives a LogicTechno LT170410-2WHC 10.1" WXGA IPS
LCD panel. Touch input is provided by an Atmel maXTouch capacitive touch
controller.

Link: https://developer.toradex.com/hardware/accessories/add-ons/dsi-lvds-adapter
Link: https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-101inch-lvds
Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   4 +
 ...-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtso | 104 +++++++++++++++++++++
 2 files changed, 108 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f55c570cb3e3..91ae54931818 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -179,6 +179,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7903.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7904.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-dev-nau8822-btl.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-dsi-to-hdmi.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dev-dsi-to-hdmi.dtb
@@ -191,6 +192,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-zinnia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-hdmi.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-nau8822-btl.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-ivy.dtb
@@ -204,6 +206,8 @@ imx8mm-verdin-nonwifi-dev-dsi-to-hdmi-dtbs := imx8mm-verdin-nonwifi-dev.dtb imx8
 imx8mm-verdin-nonwifi-yavia-dsi-to-hdmi-dtbs := imx8mm-verdin-nonwifi-yavia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 imx8mm-verdin-wifi-dahlia-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-dahlia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 imx8mm-verdin-wifi-dev-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
+imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := imx8mm-verdin-wifi-dev.dtb \
+	imx8mm-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
 imx8mm-verdin-wifi-dev-nau8822-btl-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-dev-nau8822-btl.dtbo
 imx8mm-verdin-wifi-yavia-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-yavia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtso b/arch/arm64/boot/dts/freescale/imx8mm-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtso
new file mode 100644
index 000000000000..2c253018893b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtso
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Toradex DSI to LVDS Adapter on Verdin DSI_1 with Capacitive Touch Display
+ * 10.1". Used on Dahlia (X17) and Development Board (X48) that expose DSI_1
+ * via a Samtec LSS-130 connector.
+ *
+ * https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-101inch-lvds
+ * https://www.toradex.com/accessories/capacitive-touch-display-10.1-inch-lvds
+ * https://developer.toradex.com/hardware/accessories/add-ons/dsi-lvds-adapter
+ * https://www.toradex.com/accessories/verdin-dsi-to-lvds-adapter
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pwm/pwm.h>
+
+&{/} {
+	backlight_pwm3: backlight-pwm3 {
+		compatible = "pwm-backlight";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_i2s_2_d_out_dsi_1_bkl_en>;
+		brightness-levels = <0 45 63 88 119 158 203 255>;
+		default-brightness-level = <4>;
+		/* Verdin I2S_2_D_OUT (SODIMM 46) - DSI_1_BKL_EN_LVDS */
+		enable-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>;
+		power-supply = <&reg_3p3v>;
+		/* Verdin PWM_3_DSI (SODIMM 19) - PWM_3_DSI_LVDS */
+		pwms = <&pwm1 0 6666667 PWM_POLARITY_INVERTED>;
+	};
+
+	panel-lvds-bridge {
+		compatible = "logictechno,lt170410-2whc";
+		backlight = <&backlight_pwm3>;
+		power-supply = <&reg_dsi_lvds>;
+
+		port {
+			panel_lvds_bridge_in: endpoint {
+				remote-endpoint = <&dsi_lvds_bridge_out>;
+			};
+		};
+	};
+
+	reg_dsi_lvds: regulator-dsi-lvds {
+		compatible = "regulator-fixed";
+		/* Verdin CTRL_SLEEP_MOCI# (SODIMM 256) */
+		gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-boot-on;
+		regulator-name = "DSI_1_PWR_EN";
+	};
+};
+
+&atmel_mxt_ts {
+	vdd-supply = <&reg_dsi_lvds>;
+
+	status = "okay";
+};
+
+&lcdif {
+	status = "okay";
+};
+
+&lvds_ti_sn65dsi84 {
+	vcc-supply = <&reg_dsi_lvds>;
+
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+
+			dsi_lvds_bridge_in: endpoint {
+				data-lanes = <1 2 3 4>;
+				remote-endpoint = <&mipi_dsi_out>;
+			};
+		};
+
+		port@2 {
+			reg = <2>;
+
+			dsi_lvds_bridge_out: endpoint {
+				remote-endpoint = <&panel_lvds_bridge_in>;
+			};
+		};
+	};
+};
+
+&mipi_dsi {
+	samsung,esc-clock-frequency = <16000000>;
+
+	status = "okay";
+};
+
+&mipi_dsi_out {
+	remote-endpoint = <&dsi_lvds_bridge_in>;
+};

-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 2/7] arm64: dts: freescale: imx8mm-verdin: Add DSI to HDMI adapter overlay
From: Ernest Van Hoecke @ 2026-07-24 16:24 UTC (permalink / raw)
  To: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kieran Bingham
  Cc: Francesco Dolcini, imx, linux-arm-kernel, devicetree,
	linux-kernel, Ernest Van Hoecke
In-Reply-To: <20260724-v1-verdin-imx8mm-dtbos-v2-0-9d7988bd76f6@toradex.com>

From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>

Add a device tree overlay for the Toradex DSI to HDMI Adapter, an
accessory that connects to the Verdin DSI_1 interface and provides a
full-size HDMI Type-A output. The adapter is based on the Lontium
LT8912B DSI-to-HDMI bridge.

The overlay is also combined with the Verdin iMX8M Mini carrier board
device trees to provide ready-to-use DTBs for the Dahlia, Yavia and
Development Board carriers, in both WiFi and non-WiFi SoM variants.

Link: https://developer.toradex.com/hardware/accessories/add-ons/dsi-hdmi-adapter
Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
---
 arch/arm64/boot/dts/freescale/Makefile             | 13 ++++
 .../dts/freescale/imx8mm-verdin-dsi-to-hdmi.dtso   | 88 ++++++++++++++++++++++
 2 files changed, 101 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index dcc0464b4e80..f55c570cb3e3 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -178,21 +178,34 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7902.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7903.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7904.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-dev-nau8822-btl.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-dsi-to-hdmi.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dev-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-ivy.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-mallow.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-zinnia.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-nau8822-btl.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-ivy.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-mallow.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-yavia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-yavia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-zinnia.dtb
 
+imx8mm-verdin-nonwifi-dahlia-dsi-to-hdmi-dtbs := imx8mm-verdin-nonwifi-dahlia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
+imx8mm-verdin-nonwifi-dev-dsi-to-hdmi-dtbs := imx8mm-verdin-nonwifi-dev.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
+imx8mm-verdin-nonwifi-yavia-dsi-to-hdmi-dtbs := imx8mm-verdin-nonwifi-yavia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
+imx8mm-verdin-wifi-dahlia-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-dahlia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
+imx8mm-verdin-wifi-dev-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 imx8mm-verdin-wifi-dev-nau8822-btl-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-dev-nau8822-btl.dtbo
+imx8mm-verdin-wifi-yavia-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-yavia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
 
 imx8mm-tqma8mqml-mba8mx-lvds-g133han01-dtbs += imx8mm-tqma8mqml-mba8mx.dtb imx8mm-tqma8mqml-mba8mx-lvds-g133han01.dtbo
 imx8mm-tqma8mqml-mba8mx-lvds-tm070jvhg33-dtbs += imx8mm-tqma8mqml-mba8mx.dtb imx8mm-tqma8mqml-mba8mx-lvds-tm070jvhg33.dtbo
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-dsi-to-hdmi.dtso b/arch/arm64/boot/dts/freescale/imx8mm-verdin-dsi-to-hdmi.dtso
new file mode 100644
index 000000000000..507d0bbb5935
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-dsi-to-hdmi.dtso
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Toradex DSI to HDMI Adapter on Verdin DSI_1.
+ *
+ * https://developer.toradex.com/hardware/accessories/add-ons/dsi-hdmi-adapter
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&{/} {
+	reg_dsi_hdmi: regulator-dsi-hdmi {
+		compatible = "regulator-fixed";
+		/* Verdin CTRL_SLEEP_MOCI# (SODIMM 256) */
+		gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-boot-on;
+		regulator-name = "DSI_1_PWR_EN";
+	};
+};
+
+&hdmi_connector {
+	status = "okay";
+
+	port {
+		hdmi_connector_in: endpoint {
+			remote-endpoint = <&dsi_hdmi_bridge_out>;
+		};
+	};
+};
+
+&hdmi_lontium_lt8912 {
+	vdd-supply = <&reg_dsi_hdmi>;
+
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+
+			dsi_hdmi_bridge_in: endpoint {
+				data-lanes = <1 2 3 4>;
+				remote-endpoint = <&mipi_dsi_out>;
+			};
+		};
+
+		port@1 {
+			reg = <1>;
+
+			dsi_hdmi_bridge_out: endpoint {
+				remote-endpoint = <&hdmi_connector_in>;
+			};
+		};
+	};
+};
+
+/* Verdin I2C_2_DSI */
+&i2c2 {
+	clock-frequency = <10000>;
+
+	status = "okay";
+};
+
+&lcdif {
+	status = "okay";
+};
+
+&mipi_dsi {
+	samsung,esc-clock-frequency = <16000000>;
+
+	status = "okay";
+};
+
+&mipi_dsi_out {
+	remote-endpoint = <&dsi_hdmi_bridge_in>;
+};
+
+/* Verdin PWM_3_DSI (SODIMM 19) repurposed as HDMI HPD GPIO */
+&pwm1 {
+	status = "disabled";
+};

-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 1/7] arm64: dts: freescale: imx8mm-verdin: Add NAU8822 Bridge Tied Load
From: Ernest Van Hoecke @ 2026-07-24 16:24 UTC (permalink / raw)
  To: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kieran Bingham
  Cc: Francesco Dolcini, imx, linux-arm-kernel, devicetree,
	linux-kernel, Ernest Van Hoecke
In-Reply-To: <20260724-v1-verdin-imx8mm-dtbos-v2-0-9d7988bd76f6@toradex.com>

From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>

Add a device tree overlay for configuring the NAU8822 loudspeaker
outputs as a Bridge Tied Load (BTL) output on the Verdin Development
Board.

The overlay adds the codec property for the BTL-capable output
configuration, where the two loudspeaker outputs are combined for higher
output power.

Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
---
 arch/arm64/boot/dts/freescale/Makefile                     |  4 ++++
 .../boot/dts/freescale/imx8mm-verdin-dev-nau8822-btl.dtso  | 14 ++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index d5c2dc720197..dcc0464b4e80 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -177,6 +177,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7901.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7902.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7903.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7904.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-dev-nau8822-btl.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-ivy.dtb
@@ -184,12 +185,15 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-mallow.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-zinnia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-nau8822-btl.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-ivy.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-mallow.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-yavia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-zinnia.dtb
 
+imx8mm-verdin-wifi-dev-nau8822-btl-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-dev-nau8822-btl.dtbo
+
 imx8mm-tqma8mqml-mba8mx-lvds-g133han01-dtbs += imx8mm-tqma8mqml-mba8mx.dtb imx8mm-tqma8mqml-mba8mx-lvds-g133han01.dtbo
 imx8mm-tqma8mqml-mba8mx-lvds-tm070jvhg33-dtbs += imx8mm-tqma8mqml-mba8mx.dtb imx8mm-tqma8mqml-mba8mx-lvds-tm070jvhg33.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-tqma8mqml-mba8mx-lvds-g133han01.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-dev-nau8822-btl.dtso b/arch/arm64/boot/dts/freescale/imx8mm-verdin-dev-nau8822-btl.dtso
new file mode 100644
index 000000000000..e4b662519a6b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-dev-nau8822-btl.dtso
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Enable Bridge Tied Load (BTL) speaker mode on the Verdin Development Board,
+ * combining the two loudspeaker outputs for higher output power.
+ */
+
+/dts-v1/;
+/plugin/;
+
+&nau8822_1a {
+	nuvoton,spk-btl;
+};

-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 0/7] arm64: dts: freescale: Add Verdin iMX8M Mini overlays
From: Ernest Van Hoecke @ 2026-07-24 16:24 UTC (permalink / raw)
  To: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kieran Bingham
  Cc: Francesco Dolcini, imx, linux-arm-kernel, devicetree,
	linux-kernel, Ernest Van Hoecke

This series adds device tree overlays for the Toradex Verdin iMX8M Mini
SoM. The overlays cover audio configuration, display adapters, DSI
displays, and Cortex-M4F integration.

The series adds support for:
- NAU8822 Bridge Tied Load configuration on the Verdin Development Board
- DSI-to-HDMI adapter based on the Lontium LT8912B bridge
- DSI-to-LVDS adapter based on the TI SN65DSI84 bridge, combined with the
  Toradex Capacitive Touch Display 10.1" LVDS
- Toradex Capacitive Touch Display 7" and 10.1" DSI variants
- Cortex-M4F remoteproc support

Cortex-M4F support is split between the SoM description and an optional
UART_4 overlay. The SoM dtsi describes the remote processor and RPMsg
reserved-memory regions, while the overlay reserves Verdin UART_4 for
Cortex-M4F firmware use.

The Makefile entries build the standalone overlays as DTBOs, add
ready-to-use composed DTBs for selected carrier board and accessory
combinations, and add representative composed DTBs for build-time
coverage.

As discussed in v1, the overlays for the OV5640 cameras will follow
later and use the partial connectors model to specify the Verdin CSI
connector.

Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
---
Changes in v2:
- Dropped the OV5640 overlays, they will be added by a later series
- Link to v1: https://lore.kernel.org/r/20260713-v1-verdin-imx8mm-dtbos-v1-0-4acd63db4504@toradex.com

---
Ernest Van Hoecke (7):
      arm64: dts: freescale: imx8mm-verdin: Add NAU8822 Bridge Tied Load
      arm64: dts: freescale: imx8mm-verdin: Add DSI to HDMI adapter overlay
      arm64: dts: freescale: imx8mm-verdin: Add Toradex DSI to LVDS adapter with 10.1" display
      arm64: dts: freescale: imx8mm-verdin: Add Toradex Capacitive Touch Display 10.1" DSI
      arm64: dts: freescale: imx8mm-verdin: Add Toradex Capacitive Touch Display 7" DSI
      arm64: dts: freescale: imx8mm-verdin: Add Cortex-M4F remoteproc
      arm64: dts: freescale: imx8mm-verdin: Add Cortex-M4F UART_4 overlay

 arch/arm64/boot/dts/freescale/Makefile             |  35 ++++++
 .../freescale/imx8mm-verdin-dev-nau8822-btl.dtso   |  14 +++
 .../dts/freescale/imx8mm-verdin-dsi-to-hdmi.dtso   |  88 ++++++++++++++
 ...-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtso | 104 +++++++++++++++++
 .../imx8mm-verdin-panel-cap-touch-10inch-dsi.dtso  | 129 +++++++++++++++++++++
 .../imx8mm-verdin-panel-cap-touch-7inch-dsi.dtso   | 129 +++++++++++++++++++++
 .../dts/freescale/imx8mm-verdin-uart4-mcu.dtso     |  14 +++
 arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi   |  33 ++++++
 8 files changed, 546 insertions(+)
---
base-commit: 4d0d3a3d1993a41b2bf8d28aa6c6071fa1a3bff7
change-id: 20260707-v1-verdin-imx8mm-dtbos-a326146c62c4

Best regards,
-- 
Ernest Van Hoecke <ernest.vanhoecke@toradex.com>


^ permalink raw reply

* Re: [PATCH v8 5/9] block: implement NVMEM provider
From: Loic Poulain @ 2026-07-24 16:19 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
	Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
	Russell King, Saravana Kannan, Christian Marangi, linux-mmc,
	devicetree, linux-kernel, linux-arm-msm, linux-block,
	linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
	Bartosz Golaszewski
In-Reply-To: <amNkX6HV7c_8jRUa@infradead.org>

On Fri, Jul 24, 2026 at 3:11 PM Christoph Hellwig <hch@infradead.org> wrote:
>
> On Fri, Jul 24, 2026 at 11:10:58AM +0200, Loic Poulain wrote:
> > Right, I was planning to add partition support in a follow-up series.
> > But since this is really supposed to be a block-agnostic feature,
> > whether it's a disk or a partition, I'll include partition in v8.
>
> Please include the partitions, as including them or not matters for
> the interfaces.  What is holding that support back now?  fwnode
> magic?

Yes, there is a bit of fwnode magic involved in partitions of/core,
but adding it is fairly straightforward.

>
> > > Also once you register the whole devices as nvmem provider, we really
> > > should keep it from being used a block device, shouldn't we?
> >
> >
> > I'm not sure, the whole concept is block backed NVMEM, so we still
> > need to add that block as base layer, though we could discuss
> > suppressing uevent for it. Preventing block usage would make the
> > feature much more intrusive than other NVMEM providers like MTD, where
> > the underlying device stays accessible. And we may genuinely still
> > want to write the disk (e.g. for factory provisioning), updating the
> > very data the cells point to, etc. There's also the layering aspect,
> > if a disk (e.g. mmcblk0) has logical partitions on top (mmcblk0pX), we
> > still register/expose the whole disk mmcblk0 as a block device
> > regardless. So if a disk contains NVMEM cells, I think it should still
> > be exposed as a block device as well.
>
> So we now get two unsynchronized ways to access the same device?
> At least we need to prevent exclusive openers on the block device
> side.  And document the side channel very well.

Yes, effectively, so the simpler is to open it exclusively per read
in reg_read with a holder (exclusive). This gives us proper exclusion
against other holders, but only transiently for the duration of the read.
It's the simpler solution if acceptable.

Another option would be to claim the device for the whole NVMEM
lifetime, but currently we can't bdev/open the block device from
nvmem_register(). That path runs early, while the disk/partition setup
already holds disk->open_mutex. So that would require a larger change.

Regards,
Loic

^ permalink raw reply

* Re: [PATCH v6 0/2] clk: amlogic: Add A9 peripherals clock controller
From: Jerome Brunet @ 2026-07-24 16:07 UTC (permalink / raw)
  To: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao, Kevin Hilman,
	Martin Blumenstingl, Brian Masney, Jian Hu
  Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
	linux-arm-kernel, Conor Dooley
In-Reply-To: <20260701-a9_peripherals-v6-0-9630f39879e5@amlogic.com>

Applied to clk-meson (clk-meson-next), thanks!

[1/2] dt-bindings: clock: Add Amlogic A9 peripherals clock controller
      https://github.com/BayLibre/clk-meson/commit/33972977d632
[2/2] clk: amlogic: Add A9 peripherals clock controller driver
      https://github.com/BayLibre/clk-meson/commit/f905fc7b7a81

Best regards,
--
Jerome


^ permalink raw reply

* Re: [PATCH v2 2/2] arm64: dts: qcom: Add support for Acer Swift Go Pro AI (SFA14-11)
From: Kaipeng Zeng @ 2026-07-24 16:06 UTC (permalink / raw)
  To: Konrad Dybcio
  Cc: devicetree, linux-arm-msm, conor+dt, krzk+dt, robh, konradybcio,
	andersson
In-Reply-To: <aee1e26d-d3f7-4903-a34f-02fcda6a6beb@oss.qualcomm.com>

On Tue, Jul 21, 2026 at 6:22 PM Konrad Dybcio
<konrad.dybcio@oss.qualcomm.com> wrote:
>
> On 7/21/26 10:24 AM, Kaipeng Zeng wrote:
> > Introduce device tree for the Acer Swift Go Pro AI (SFA14-11).
> > It is a laptop based on the Qualcomm Snapdragon X Elite (X1E78100) SoC.
> > This device tree implementation references nodes from the x1-crd.dtsi.
> >
> > Supported features:
> >
> >  - Internal display & Brightness control
> >  - Keyboard & Touchpad
> >  - USB Type-C, Type-A
> >  - Wi-Fi & Bluetooth
> >  - ADSP & CDSP
> >  - Adreno X1-85 GPU
> >  - HDMI & USB Type-C display
> >  - Webcam
> >
> > Signed-off-by: Kaipeng Zeng <kaipeng94@gmail.com>
> > ---
>
> [...]
>
> > +             wcd-playback-dai-link {
> > +                     link-name = "WCD Playback";
> > +
> > +                     cpu {
> > +                             sound-dai = <&q6apmbedai RX_CODEC_DMA_RX_0>;
> > +                     };
> > +
> > +                     codec {
> > +                             sound-dai = <&wcd938x 0>, <&swr1 0>, <&lpass_rxmacro 0>;
> > +                     };
>
> 'co'dev < 'cp'u (other nodes have it correct), please also re-sort
> the -link {} nodes alphabetically
>
> [...]
>
> > +&iris {
> > +     firmware-name = "qcom/x1e80100/ACER/SFA14-11/qcvss8380.mbn";
> > +     status = "okay";
>
> Let's also keep a \n before 'status', file-wide
>
> [...]
>
>
> > +&mdss_dp1 {
> > +     ports {
> > +             /delete-node/ port@1;
> > +     };
>
> Hm?
>
> [...]
>
> > +     wcd_default: wcd-reset-n-active-state {
> > +             pins = "gpio191";
> > +             function = "gpio";
> > +             drive-strength = <16>;
> > +             bias-disable;
> > +             output-low;
>
> You don't need to specify output-foo on TLMM pins, the GPIO consumer
> will assert it as necessary

I noticed this before.
spkr_01_sd_n_active and spkr_23_sd_n_active (in lpass_tlmm) are also set to
output-low.

I tested that Gnome cannot detect either the speakers or the headphone using
the current DTS.
If I remove the "output-low" from wcd_default, Gnome can detect headphone
plug-in (not the speakers) and speakers will randomly output an audio pop noise,
specifically when playback starts and stops.
I kept the "output-low" of them for safety.

Is it still proper to remove this "output-low"?
Should I also remove the "output-low" from spkr_*?

>
> Konrad

^ permalink raw reply

* Re: [PATCH 08/12] clk: composite: Export devm_clk_hw_register_composite_pdata
From: Brian Masney @ 2026-07-24 16:01 UTC (permalink / raw)
  To: Luo Jie
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, linux-arm-msm,
	linux-clk, linux-kernel, devicetree, quic_kkumarcs, quic_linchen,
	quic_leiwei, quic_suruchia
In-Reply-To: <20260724-qcom_ipq5210_cmnpll-v1-8-a8b8679d215f@oss.qualcomm.com>

On Fri, Jul 24, 2026 at 08:00:30AM -0700, Luo Jie wrote:
> devm_clk_hw_register_composite_pdata() is defined but not exported,
> preventing its use from loadable modules. Add EXPORT_SYMBOL_GPL() so
> that out-of-tree and built-as-module clock drivers can call it.
> 
> Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>

Reviewed-by: Brian Masney <bmasney@redhat.com>

FYI there's a separate series for the UltraRISC DP1000 SoC to export
this same symbol. It depends on which series Stephen merges first gets
in.

https://lore.kernel.org/linux-clk/20260720-ultrarisc-clock-v4-1-fe639d63bbac@ultrarisc.com/


^ permalink raw reply

* Re: [PATCH v8 2/2] media: i2c: Add driver for AMS-OSRAM Mira220
From: sashiko-bot @ 2026-07-24 15:58 UTC (permalink / raw)
  To: Jacopo Mondi; +Cc: robh, conor+dt, media-ci, devicetree
In-Reply-To: <20260724-mira220-v8-2-d1899ab64709@ideasonboard.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Teardown order in `mira220_remove` creates a Use-After-Free / NULL pointer dereference race with `mira220_set_ctrl`.
- [High] The device can be unexpectedly runtime suspended during probe, leading to I2C communication failures.
- [High] Unconditional dereference of `ep_cfg.link_frequencies` crashes the kernel if the `link-frequencies` property is missing from the device tree.
- [Medium] The `mira220_set_pad_format` function unconditionally resets the user-configured `vblank` control back to its minimum limit on every format access.
- [Medium] Missing delays in the hardware power-on sequence before attempting I2C communication.
- [Low] Missing Kconfig dependency and select statements for V4L2_FWNODE and VIDEO_V4L2_SUBDEV_API.
--

--- Patch [2]: [PATCH v8 2/2] media: i2c: Add driver for AMS-OSRAM Mira220 ---
commit d6f8c2bd4b0b5b01ffb4db66a1a981625b434f77
Author: Philippe Baetens <philippebaetens@gmail.com>

media: i2c: Add driver for AMS-OSRAM Mira220
    
Add a V4L2 subdev driver for driver for the AMS-OSRAM Mira220 image sensor.
The driver implements support for mono and RGB 12, 10 and 8 bits formats.

> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 5c52007f9cbeb..650d5c86baa4d 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -313,6 +313,18 @@ config VIDEO_IMX678
>  config VIDEO_MAX9271_LIB
>  	tristate
>  
> +config VIDEO_MIRA220
> +	tristate "ams MIRA220 sensor support"
> +	depends on I2C && VIDEO_DEV
> +	depends on GPIOLIB
> +	select V4L2_CCI_I2C

[Severity: Low]
Are we missing dependencies on V4L2_FWNODE and VIDEO_V4L2_SUBDEV_API here?

If a configuration enables VIDEO_MIRA220 but leaves CONFIG_V4L2_FWNODE
or CONFIG_VIDEO_V4L2_SUBDEV_API disabled, it looks like the build might
fail with undefined references since the driver heavily relies on functions
from these modules.

> diff --git a/drivers/media/i2c/mira220.c b/drivers/media/i2c/mira220.c
> new file mode 100644
> index 0000000000000..8b9148efc581e
> --- /dev/null
> +++ b/drivers/media/i2c/mira220.c

[ ... ]

> +static int mira220_power_on(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct mira220 *mira220 = to_mira220(sd);
> +	int ret;
> +
> +	ret = regulator_bulk_enable(ARRAY_SIZE(mira220_supplies),
> +				    mira220->supplies);
> +	if (ret) {
> +		dev_err(&client->dev, "%s: failed to enable regulators\n",
> +			__func__);
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(mira220->xclk);
> +	if (ret) {
> +		dev_err(&client->dev, "%s: failed to enable clock\n", __func__);
> +		goto reg_off;
> +	}
> +
> +	gpiod_set_value_cansleep(mira220->reset_gpio, 0);
> +
> +	return 0;
> +}

[Severity: Medium]
Should there be a delay before returning here?

After de-asserting the reset GPIO line, the driver returns and the probe
sequence proceeds directly to mira220_identify_module(), which begins I2C
reads to the OTP memory.

If the sensor requires a minimum delay after reset de-assertion to boot its
internal microcontroller, skipping this delay could cause I2C communication
to fail on faster platforms.

[ ... ]

> +static int mira220_set_pad_format(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *state,
> +				  struct v4l2_subdev_format *fmt)
> +{

[ ... ]

> +	/* Update vblank based on new mode. */
> +	min_vblank = mira220_calc_min_vblank(mira220);
> +	ret = __v4l2_ctrl_modify_range(mira220->vblank, min_vblank,
> +				       MIRA220_MAX_VBLANK, 1, min_vblank);
> +	if (ret)
> +		return ret;
> +
> +	return __v4l2_ctrl_s_ctrl(mira220->vblank, min_vblank);
> +}

[Severity: Medium]
Does this inadvertently wipe out custom user configurations?

Whenever userspace configures the format via VIDIOC_SUBDEV_S_FMT, the
driver calls __v4l2_ctrl_modify_range() to adjust the vblank control limits.

However, explicitly calling __v4l2_ctrl_s_ctrl() to force the value to
min_vblank overrides whatever value the user had previously configured or
clamped to, which seems to violate V4L2 API expectations for control
orthogonality.

[ ... ]

> +static int mira220_parse_endpoint(struct device *dev, struct mira220 *mira220)
> +{

[ ... ]

> +	if (ep_cfg.nr_of_link_frequencies > ARRAY_SIZE(mira220_link_freqs)) {
> +		ret = -EINVAL;
> +		dev_err(dev, "Unsupported number of link_frequencies: %u\n",
> +			ep_cfg.nr_of_link_frequencies);
> +		goto error_out;
> +	}
> +
> +	if (ep_cfg.link_frequencies[0] != MIRA220_LINK_FREQ_750M) {

[Severity: High]
Can this dereference a NULL pointer if the device tree omits the
link-frequencies property?

If v4l2_fwnode_endpoint_alloc_parse() parses an endpoint without a
link-frequencies property, it successfully returns 0 but leaves
ep_cfg.link_frequencies as NULL and ep_cfg.nr_of_link_frequencies as 0.

Since the check directly above only tests if nr_of_link_frequencies is
greater than the array size, an empty property evaluates to false (0 > 1).
The code then immediately accesses ep_cfg.link_frequencies[0], which would
dereference the NULL pointer.

[ ... ]

> +static int mira220_probe(struct i2c_client *client)
> +{

[ ... ]

> +	ret = mira220_power_on(dev);
> +	if (ret)
> +		return ret;
> +
> +	/* Enable runtime PM and power on the device */
> +	pm_runtime_set_active(dev);
> +	pm_runtime_enable(dev);
> +
> +	ret = mira220_identify_module(mira220);

[Severity: High]
Is there a race condition here where the device might be suspended during
probe?

Enabling runtime PM with pm_runtime_enable() while the device usage count is
0 makes the device eligible for suspension immediately.

If userspace has set power/control to auto, a concurrent suspend operation
could call mira220_power_off() exactly as mira220_identify_module() or
mira220_init_controls() are attempting to perform hardware I2C reads, causing
initialization to fail.

Would it be safer to call pm_runtime_get_noresume(dev) before enabling
runtime PM, and then drop the reference at the end of the probe function?

[ ... ]

> +static void mira220_remove(struct i2c_client *client)
> +{
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct mira220 *mira220 = to_mira220(sd);
> +
> +	v4l2_async_unregister_subdev(sd);
> +	v4l2_subdev_cleanup(&mira220->sd);
> +	media_entity_cleanup(&sd->entity);
> +
> +	v4l2_ctrl_handler_free(mira220->sd.ctrl_handler);

[Severity: High]
Could this cleanup order trigger a use-after-free or NULL pointer
dereference?

Calling v4l2_subdev_cleanup() frees sd->active_state and sets it to NULL,
but the control handler is still active and registered at this point.

If userspace unbinds the driver via sysfs while concurrently issuing a
VIDIOC_S_CTRL ioctl on an open file descriptor, mira220_set_ctrl() could
execute during this window:

mira220_set_ctrl() {
    ...
    state = v4l2_subdev_get_locked_active_state(&mira220->sd);
    format = v4l2_subdev_state_get_format(state, 0);
}

Since mira220_set_ctrl() acquires the control lock and expects the state to
be valid, this sequence would dereference the freed state. Calling
v4l2_ctrl_handler_free() before v4l2_subdev_cleanup() might avoid this race.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-mira220-v8-0-d1899ab64709@ideasonboard.com?part=2

^ permalink raw reply

* Re: [PATCH 01/12] clk: qcom: ipq-cmn-pll: Use devm_clk_hw_register_fixed_rate_parent_data
From: Konrad Dybcio @ 2026-07-24 15:50 UTC (permalink / raw)
  To: Luo Jie, Bjorn Andersson, Michael Turquette, Stephen Boyd,
	Brian Masney, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Konrad Dybcio
  Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
	quic_linchen, quic_leiwei, quic_suruchia
In-Reply-To: <20260724-qcom_ipq5210_cmnpll-v1-1-a8b8679d215f@oss.qualcomm.com>

On 7/24/26 5:00 PM, Luo Jie wrote:
> Replace clk_hw_register_fixed_rate_parent_hw() with the managed
> devm_clk_hw_register_fixed_rate_parent_data() so the fixed-rate output
> clocks are automatically unregistered when the device is unbound.
> 
> Since all clocks in the driver are now registered via devm_ variants,
> the remove callback 'ipq_cmn_pll_clk_remove()' and the manual
> 'unregister_fixed_clk' error-path loop are no longer needed and are
> removed.
> 
> Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
> ---

Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

Konrad

^ permalink raw reply

* Re: [PATCH v3 1/2] dt-bindings: mmc: Document no-mmc-poweroff-suspend property
From: Ulf Hansson @ 2026-07-24 15:42 UTC (permalink / raw)
  To: Kamal Dasu, Krzysztof Kozlowski
  Cc: Ulf Hansson, Florian Fainelli, Wolfram Sang, Oleksij Rempel,
	Avri Altman, Pedro Demarchi Gomes, Erick Shepherd, Adrian Hunter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-mmc,
	devicetree, linux-kernel
In-Reply-To: <CAKekbeuMtzwYWax97DRo89p_UnG-Gg0ALnhRNFjS-XP9-KV_WA@mail.gmail.com>

On Thu, Jul 23, 2026 at 9:51 PM Kamal Dasu <kamal.dasu@broadcom.com> wrote:
>
> On Thu, Jul 23, 2026 at 3:36 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:
> >
> > On 23/07/2026 21:24, Kamal Dasu wrote:
> > > On Thu, Jul 23, 2026 at 3:01 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > >>
> > >> On 23/07/2026 20:53, Kamal Dasu wrote:
> > >>> On Thu, Jul 23, 2026 at 3:51 AM Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > >>>
> > >>>> On Wed, Jul 22, 2026 at 05:14:16PM -0400, Kamal Dasu wrote:
> > >>>>> On some platforms, firmware accesses the (e)MMC card directly during
> > >>>>> system resume from Suspend-to-DRAM, before the kernel's own resume
> > >>>>> path has run, in order to load boot code using hard wired logic that
> > >>>>> is not field updatable. This requires the card to remain powered
> > >>>>> and responsive throughout suspend: it cannot be put to sleep, sent a
> > >>>>> power-off notification, or have its supply removed.
> > >>>>>
> > >>>>> Add a no-mmc-poweroff-suspend flag property so affected boards can
> > >>>>> tell the mmc core to keep the card powered across suspend instead of
> > >>>>> sleeping or powering it off.
> > >>>>>
> > >>>>> Signed-off-by: Kamal Dasu <kamal.dasu@broadcom.com>
> > >>>>> ---
> > >>>>> Changes in v3:
> > >>>>>   - Renamed from no-mmc-sleep; dropped S_A_TIMEOUT framing per Ulf.
> > >>>>>
> > >>>>> Changes in v2:
> > >>>>>   - New patch, replacing v1's card-level quirk, per Ulf.
> > >>>>>
> > >>>>>  .../devicetree/bindings/mmc/mmc-controller-common.yaml | 10 ++++++++++
> > >>>>>  1 file changed, 10 insertions(+)
> > >>>>>
> > >>>>> diff --git
> > >>>> a/Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml
> > >>>> b/Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml
> > >>>>> index 3d7195e9461c..5f7b3f8ef1dd 100644
> > >>>>> --- a/Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml
> > >>>>> +++ b/Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml
> > >>>>> @@ -232,6 +232,16 @@ properties:
> > >>>>>      description:
> > >>>>>        All eMMC HS400 modes are not supported.
> > >>>>>
> > >>>>> +  no-mmc-poweroff-suspend:
> > >>>>> +    $ref: /schemas/types.yaml#/definitions/flag
> > >>>>> +    description:
> > >>>>> +      On this platform, firmware accesses the attached (e)MMC card
> > >>>>> +      directly during system resume, before the kernel's own resume
> > >>>>> +      path runs. The card must therefore stay powered throughout
> > >>>>> +      suspend, and the controller must not send it a sleep or
> > >>>>> +      power-off notification. The kernel re-initializes the card
> > >>>>> +      after resume, since firmware may have already reset it.
> > >>>>
> > >>>> Isn't this exactly the same as keep-power-in-suspend?
> > >>>>
> > >>>>
> > >>> Not quite, though I see why it reads that way from the description
> > >>> alone.
> > >>>
> > >>> keep-power-in-suspend only takes effect through host->pm_flags, which
> > >>> gets set at runtime via sdio_set_host_pm_flags() -- an SDIO function
> > >>> driver opts in from its own suspend() callback, per suspend cycle.
> > >>> The consuming logic lives entirely in mmc_sdio_suspend()/
> > >>> mmc_sdio_resume() (drivers/mmc/core/sdio.c); pm_flags is never read
> > >>> in mmc.c, which is what this series touches.
> > >>>
> > >>> no-mmc-poweroff-suspend differs in two ways:
> > >>>
> > >>>   - It's a fixed platform characteristic, not a per-driver runtime
> > >>>     request. There's no SDIO-style function driver to call an opt-in
> > >>>     API from for a plain (e)MMC storage card -- the requirement here
> > >>>     (firmware always touches the card at resume, on this board) is
> > >>>     always true, not something decided per suspend cycle.
> > >>>   - The resume-side behavior differs. keep-power-in-suspend without a
> > >>>     wake IRQ does nothing at resume: it assumes the card's state
> > >>>     survived untouched. This flag needs the opposite -- keep power,
> > >>>     but still fully re-initialize the card via mmc_init_card(), since
> > >>>     firmware may have reconfigured it while the kernel was suspended.
> > >>
> > >> All this is just driver stuff which I did not ask about.
> > >>
> > >> The property is described pretty the same - do not power off during
> > >> suspend/resume.
> > >>
> > >
> > > Do you want me to fold this change into using 'keep-power-in-suspend'
> > > for mmc as well ?.
> >
> > I don't want a new property if it has exactly the same meaning. Of
> > course I am happy to hear why the property has different meaning in
> > terms of hardware description. We do not talk here about drivers, obviously.
> >
>
> In terms of hardware description, yes, it's the same meaning: don't
> power off the card across suspend/resume. I've folded this into
> keep-power-in-suspend rather than keeping a separate property --
> extended its description to cover (e)MMC alongside the existing SDIO
> wording, and reworked the mmc core side to honor it for (e)MMC too.
>
> Sending v4 shortly.

Hold on, this isn't what is needed from the HW point of view. At
least, according to what Florian told me from the earlier discussions.

What we need is a property that means: "Keep power in suspend/resume,
but also re-initialize the eMMC/card at resume since the FW have
fiddled with the card before the kernel resumes".

Kind regards
Uffe

^ permalink raw reply

* Re: [RFC PATCH 0/8] ASoC: SDCA: enable on DT platforms and add Qualcomm WCD9378 (Tambora) codec
From: Charles Keepax @ 2026-07-24 15:40 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
	Maciej Strozek, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Srinivas Kandagatla, Bard Liao, Pierre-Louis Bossart,
	Richard Fitzgerald, Jorijn van der Graaf, linux-sound,
	linux-arm-msm, devicetree, patches, linux-kernel
In-Reply-To: <6d1870c1-7fff-4569-8de2-bb45b83cde25@oss.qualcomm.com>

On Fri, Jul 24, 2026 at 03:31:51PM +0100, Srinivas Kandagatla wrote:
> On 7/24/26 1:36 PM, Charles Keepax wrote:
> > On Thu, Jul 23, 2026 at 02:24:19PM +0100, Srinivas Kandagatla wrote:
> >> Thanks Charles, for the feedback.
> >> On 7/23/26 11:17 AM, Charles Keepax wrote:
> >>> On Thu, Jul 23, 2026 at 12:42:10AM +0100, Srinivas Kandagatla wrote:
> > Yeah agree be good to get the DT guys thoughts on this. It seems
> > like a misstep to me to insist that the SDCA spec implements a
> > completely different system of storing information for DT. SDCA
> > is what SDCA is now, and supporting two different parsers seems
> > like work no one needs when the one parser we have would work
> > fine for both.
> Am not sure I understood the two parser concern, what we are
> representing in the table is something that sdca core already does after
> parsing acpi tables. So we are reusing the same structures. Its like
> result of already parsed acpi tables.
> 
> I did try

Apologies for not being clear. It wasn't strictly a review
comment on the code in the series. It was a wider point that at
some point the world likely will want to put SDCA data in DT,
when that happens there are basically two choices:

1) Use the "same" representation as ACPI, in this case we can
share all the parsing code we have now. But some of the things
might be a little unusual for DT.

2) Do something more idiomatic for DT, which would likely end
up looking very different. But this would require a whole new
parser and lengthy standardisation process.

Mostly what I am interested in here is getting at what the end
goal is. The impression I got was that really everyone from
Plumbers was really more aligned to 2). I am not sure I agree
that is the right choice, although willing to be convinced here.

> > That said I don't totally object to the idea of an option to
> > supply a static block of information as you are in the series. It
> > could be useful for transitional and work around situations. But
> > it doesn't seem like a good choice for SDCA on DT going forward,
> > it is basically going back to the board files that DT was saving
> > us from.
> 
> Either we have this at driver level or at dt level, both of them have
> pros and cons.
> 
> If we decide to go with dt, this how the dt entries will look like, this
> should give fair bit of idea to DT maintianers for discussion.

Thank you so much for mocking this up, that is very helpful.

Are there additional constraints from your side pushing you
one way or another on this? Or are you happy to do either? I am
thinking things like DT needing to be flashed onto systems that
have now shipped or something.

Thanks,
Charles

^ permalink raw reply

* [PATCH v8 2/2] media: i2c: Add driver for AMS-OSRAM Mira220
From: Jacopo Mondi @ 2026-07-24 15:37 UTC (permalink / raw)
  To: Philippe Baetens, Mauro Carvalho Chehab, Rob Herring,
	Sakari Ailus, Krzysztof Kozlowski, Conor Dooley
  Cc: Kieran Bingham, Jai Luthra, linux-media, devicetree, linux-kernel,
	Jacopo Mondi
In-Reply-To: <20260724-mira220-v8-0-d1899ab64709@ideasonboard.com>

From: Philippe Baetens <philippebaetens@gmail.com>

Add a V4L2 subdev driver for driver for the AMS-OSRAM Mira220 image
sensor.

Mira220 is a global shutter image sensor with a resolution of 1600x1400
pixels.

The driver implements support for mono and RGB 12, 10 and 8 bits
formats. The output data-rate per lane is 1500Mbit/s, with a maximum
frame rate up to 90 fps.

Signed-off-by: Philippe Baetens <philippebaetens@gmail.com>
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

---
v7->v8:
- Adjust KConfig entry to only depend on GPIOLIB and select CCI
- Register V4L2_CID_LINK_FREQ and validate the dts link-frequencies property
- Refuse the clock-continuous dts property
- Drop MIRA220_NUM_SUPPLIES and use ARRAY_SIZE()
- Rework flip index computation through a dedicated function
- Re-sort mira220_mbus_color_formats[] to avoid inverting hflip value
  when adjusting format to flips
- Address Jai's review comments
  - Re-indent macros with tabs
  - Use container_of_const
  - Use lowercase for hex values
  - Remove left-over mira220_mode *
  - Use HSTART_MASK when programming register
  - Use cci_write(..., &ret) to simplify register write sequences
  - Drop outdate comment
  - Do not * 1 sizes to initialize crop rectangle
  - Remove support for events
  - Use devm_v4l2_sensor_clk_get() to support ACPI systems

v6->v7:
- Address Sashiko review comments:
  - Return error code from mira220_power_on()
  - Use if (!pm_runtime_get_if_in_use(&client->dev)) in set_ctrl to
    support !PM
  - Power OTP off in case of errors
  - Use pm_ptr() when initializing the pm ops

v5->v6:
- Address Sashiko review comments:
  - Clamp max exposure not to overlow the 16 bits register
  - Update pad format on flip
  - Check otp_read() return value before accessing 'id'
  - Add v4l2_subdev_cleanup() to remove()
  - Do not access vblank in init_controls
  - Enable pm_runtime autosuspend last in probe
  - Scale hblank according to lane number to match row_length

v4->v5:
- Address checkpatch warnings and other minor style fixes (c++ comments
  80-cols etc)
- Restore MEDIA_BUS_FMT_Y12_1X12 format
- Run-time identify mono vs rgb variants
- Remove debug messages
- Remove delays not documented in datasheet
- Adjust min/max blankings to datasheet values
- Do not update limits of read-only controls with a single values on
  set_fmt
- Use pm_runtime autosuspend delay
- Remove fixed modes and dynamically program:
  - CSI-2 bus config (lanes number and clock mode)
  - frame windowing
  - image format and data-type
- Remove programming of secondary page for fast switiching (not used yet)
- Add support for reset_gpio in driver
- Use control's mutex for state locking
- Use format from subdev state and remove format from driver structure
- Rework OTP programming routines to shorten error handling
- Use enable/disable_streams() in place of set_stream()
- Add fwnode parsing for data lanes configuration
---
 MAINTAINERS                 |    1 +
 drivers/media/i2c/Kconfig   |   12 +
 drivers/media/i2c/Makefile  |    1 +
 drivers/media/i2c/mira220.c | 2080 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 2094 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 55ac4ec433a6..7c4f743ae026 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1436,6 +1436,7 @@ M:	Jacopo Mondi <jacopo.mondi@ideasonboard.com>
 L:	linux-media@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/media/i2c/ams,mira220.yaml
+F:	drivers/media/i2c/mira220.c
 
 AMT (Automatic Multicast Tunneling)
 M:	Taehee Yoo <ap420073@gmail.com>
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5c52007f9cbe..650d5c86baa4 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -313,6 +313,18 @@ config VIDEO_IMX678
 config VIDEO_MAX9271_LIB
 	tristate
 
+config VIDEO_MIRA220
+	tristate "ams MIRA220 sensor support"
+	depends on I2C && VIDEO_DEV
+	depends on GPIOLIB
+	select V4L2_CCI_I2C
+	help
+	  This is a Video4Linux2 sensor driver for the ams
+	  MIRA220 camera.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mira220.
+
 config VIDEO_MT9M001
 	tristate "mt9m001 support"
 	help
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index d04bd5724552..6ecfe6c65af4 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o
 obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
 obj-$(CONFIG_VIDEO_MAX96714) += max96714.o
 obj-$(CONFIG_VIDEO_MAX96717) += max96717.o
+obj-$(CONFIG_VIDEO_MIRA220)	+= mira220.o
 obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
 obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
diff --git a/drivers/media/i2c/mira220.c b/drivers/media/i2c/mira220.c
new file mode 100644
index 000000000000..8b9148efc581
--- /dev/null
+++ b/drivers/media/i2c/mira220.c
@@ -0,0 +1,2080 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A V4L2 driver for ams MIRA220 cameras.
+ *
+ * Mira220 comes in monochrome, RGB and IR-RGB variants. The driver supports
+ * the mono and RGB variants.
+ *
+ * Copyright (C) 2026, ams-OSRAM
+ *
+ * Based on Sony IMX219 camera driver
+ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+
+/*
+ * Active pixel array is 1600 (H) x 1400 (V) pixels.
+ * Physical resolution including buffer pixels: 1642 (H) x 1464 (V) pixels.
+ */
+#define MIRA220_NATIVE_WIDTH		1642U
+#define MIRA220_NATIVE_HEIGHT		1464U
+#define MIRA220_PIXEL_ARRAY_LEFT	21U
+#define MIRA220_PIXEL_ARRAY_TOP		32U
+#define MIRA220_PIXEL_ARRAY_WIDTH	1600U
+#define MIRA220_PIXEL_ARRAY_HEIGHT	1400U
+
+/* Mira220 does not support analog gain. */
+#define MIRA220_ANALOG_GAIN_MIN		1
+#define MIRA220_ANALOG_GAIN_MAX		1
+#define MIRA220_ANALOG_GAIN_STEP	1
+#define MIRA220_ANALOG_GAIN_DEFAULT	MIRA220_ANALOG_GAIN_MIN
+
+/* Bit order */
+#define MIRA220_BIT_ORDER_REG		CCI_REG8(0x2063)
+#define MIRA220_BIT_ORDER_NORMAL	0x00
+#define MIRA220_BIT_ORDER_REVERSED	0x01
+
+/* Bit depth */
+#define MIRA220_BIT_DEPTH_REG		CCI_REG8(0x209e)
+#define MIRA220_BIT_DEPTH_12_BIT	0x02
+#define MIRA220_BIT_DEPTH_10_BIT	0x04
+#define MIRA220_BIT_DEPTH_8_BIT		0x06
+#define MIRA220_CSI_DATA_TYPE_REG	CCI_REG8(0x208d)
+#define MIRA220_CSI_DATA_TYPE_12_BIT	0x04
+#define MIRA220_CSI_DATA_TYPE_10_BIT	0x02
+#define MIRA220_CSI_DATA_TYPE_8_BIT	0x01
+
+/* Imager state master/slave registers */
+#define MIRA220_IMAGER_STATE_REG		CCI_REG8(0x1003)
+#define MIRA220_IMAGER_STATE_STOP_AT_ROW	0x02
+#define MIRA220_IMAGER_STATE_STOP_AT_FRAME	0x04
+#define MIRA220_IMAGER_STATE_MASTER_CONTROL	0x10
+#define MIRA220_IMAGER_STATE_SLAVE_CONTROL	0x08
+
+/* Start image acquisition */
+#define MIRA220_IMAGER_RUN_REG		CCI_REG8(0x10f0)
+#define MIRA220_IMAGER_RUN_START	0x01
+#define MIRA220_IMAGER_RUN_STOP		0x00
+
+/* Continuous running, not limited to nr of frames. */
+#define MIRA220_IMAGER_RUN_CONT_REG	CCI_REG8(0x1002)
+#define MIRA220_IMAGER_RUN_CONT_ENABLE	0x04
+#define MIRA220_IMAGER_RUN_CONT_DISABLE	0x00
+
+/* Exposure time is indicated in number of rows */
+#define MIRA220_EXP_TIME_REG		CCI_REG16_LE(0x100c)
+
+/* Vertical Blank */
+#define MIRA220_VBLANK_REG		CCI_REG16_LE(0x1012)
+#define MIRA220_MIN_VBLANK_MARGIN	11
+#define MIRA220_MAX_VBLANK		0xffff
+
+/* Horizontal flip */
+#define MIRA220_HFLIP_REG		CCI_REG8(0x209c)
+#define MIRA220_HFLIP_ENABLE_MIRROR	1
+#define MIRA220_HFLIP_DISABLE_MIRROR	0
+
+/* Vertical flip */
+#define MIRA220_VFLIP_REG		CCI_REG8(0x1095)
+#define MIRA220_VFLIP_ENABLE_FLIP	1
+#define MIRA220_VFLIP_DISABLE_FLIP	0
+
+#define MIRA220_VSIZE_REG		CCI_REG16_LE(0x1087)
+#define MIRA220_VSTART_REG		CCI_REG16_LE(0x107d)
+#define MIRA220_HSIZE_REG		CCI_REG16_LE(0x2008)
+#define MIRA220_HSIZE_MASK		GENMASK(9, 0)
+#define MIRA220_HSTART_REG		CCI_REG16_LE(0x200a)
+#define MIRA220_HSTART_MASK		GENMASK(9, 0)
+#define MIRA220_MIPI_HSIZE_REG		CCI_REG16_LE(0x207d)
+
+/* MIPI bus control */
+#define MIRA220_MIPI_LANES_REG		CCI_REG8(0x6012)
+
+#define MIRA220_MIPI_CLK_MODE_REG	CCI_REG8(0x6013)
+#define MIRA220_MIPI_CLK_CONTINUOUS	0x00
+#define MIRA220_MIPI_CLK_NON_CONTINUOUS	0x01
+
+/* OTP control */
+#define MIRA220_OTP_CMD_REG		CCI_REG8(0x0080)
+#define MIRA220_OTP_CMD_UP		0x4
+#define MIRA220_OTP_CMD_DOWN		0x8
+
+/* Global sampling time */
+#define MIRA220_GLOB_NUM_CLK_CYCLES	1928
+
+/* External clock frequency is 38.4 M */
+#define MIRA220_SUPPORTED_XCLK_FREQ	38400000
+
+/* Default exposure is adjusted to mode with smallest height */
+#define MIRA220_DEFAULT_EXPOSURE	1000
+#define MIRA220_MAX_EXPOSURE		0xffff
+#define MIRA220_EXPOSURE_MIN		1
+
+/*
+ * Pixel rate is an artificial value. This value is used for timing calculations
+ * in combination with vblank/hblank.
+ */
+#define MIRA220_PIXEL_RATE		384000000
+
+/* Total line length for 2 lanes calculated for ROW_LENGTH = 304. */
+#define MIRA220_LLP_1600x1400_304	3040
+
+/*
+ * ROW_LENGTH: duration of row length in clk_in cycles; set to minimum supported
+ * value for higher frame rate.
+ */
+#define MIRA220_REG_ROW_LENGTH		CCI_REG16_LE(0x102b)
+#define MIRA220_ROW_LENGTH_MIN		304
+
+/* MIPI CSI-2 link frequency for 1.5Mbps per lane */
+#define MIRA220_LINK_FREQ_750M		750000000
+
+/* Test Pattern */
+#define MIRA220_REG_TEST_PATTERN	CCI_REG8(0x2091)
+#define MIRA220_TEST_PATTERN_DISABLE	0x00
+#define MIRA220_TEST_PATTERN_VERTICAL_GRADIENT 0x01
+
+/* Module variant identifiers */
+#define MIRA220_MONO_PLAIN_PF		0x1e62a032
+#define MIRA220_MONO_PLAIN_NO_PF	0x1e62a045
+#define MIRA220_MONO_AR_PF		0x1e62a036
+#define MIRA220_RGB_PLAIN_PF		0x1e62a03b
+#define MIRA220_RGB_PLAIN_NO_PF		0x1e62a046
+#define MIRA220_RGB_AR_PF		0x1e62a03d
+
+enum mira220_variants {
+	MIRA220_VARIANT_MONO,
+	MIRA220_VARIANT_RGB,
+};
+
+static const s64 mira220_link_freqs[] = {
+	[0] = MIRA220_LINK_FREQ_750M,
+};
+
+static const struct cci_reg_sequence mira220_init_reg_list[] = {
+	/* Base configuration*/
+	{ CCI_REG8(0x6006), 0x0 },
+	{ CCI_REG8(0x6012), 0x1 },
+	{ CCI_REG8(0x6013), 0x0 },
+	{ CCI_REG8(0x6006), 0x1 },
+	{ CCI_REG8(0x205d), 0x0 },
+	{ CCI_REG8(0x2063), 0x0 },
+	{ CCI_REG8(0x24dc), 0x13 },
+	{ CCI_REG8(0x24dd), 0x3 },
+	{ CCI_REG8(0x24de), 0x3 },
+	{ CCI_REG8(0x24df), 0x0 },
+	{ CCI_REG8(0x4006), 0x8 },
+	{ CCI_REG8(0x401c), 0x6f },
+	{ CCI_REG8(0x204b), 0x3 },
+	{ CCI_REG8(0x205b), 0x64 },
+	{ CCI_REG8(0x205c), 0x0 },
+	{ CCI_REG8(0x4018), 0x3f },
+	{ CCI_REG8(0x403b), 0xb },
+	{ CCI_REG8(0x403e), 0xe },
+	{ CCI_REG8(0x402b), 0x6 },
+	{ CCI_REG8(0x401e), 0x2 },
+	{ CCI_REG8(0x4038), 0x3b },
+	{ CCI_REG8(0x1077), 0x0 },
+	{ CCI_REG8(0x1078), 0x0 },
+	{ CCI_REG8(0x1009), 0x8 },
+	{ CCI_REG8(0x100a), 0x0 },
+	{ CCI_REG8(0x110f), 0x8 },
+	{ CCI_REG8(0x1110), 0x0 },
+	{ CCI_REG8(0x1006), 0x2 },
+	{ CCI_REG8(0x402c), 0x64 },
+	{ CCI_REG8(0x3064), 0x0 },
+	{ CCI_REG8(0x3065), 0xf0 },
+	{ CCI_REG8(0x4013), 0x13 },
+	{ CCI_REG8(0x401f), 0x9 },
+	{ CCI_REG8(0x4020), 0x13 },
+	{ CCI_REG8(0x4044), 0x75 },
+	{ CCI_REG8(0x4027), 0x0 },
+	{ CCI_REG8(0x3215), 0x69 },
+	{ CCI_REG8(0x3216), 0xf },
+	{ CCI_REG8(0x322b), 0x69 },
+	{ CCI_REG8(0x322c), 0xf },
+	{ CCI_REG8(0x4051), 0x80 },
+	{ CCI_REG8(0x4052), 0x10 },
+	{ CCI_REG8(0x4057), 0x80 },
+	{ CCI_REG8(0x4058), 0x10 },
+	{ CCI_REG8(0x3212), 0x59 },
+	{ CCI_REG8(0x4047), 0x8f },
+	{ CCI_REG8(0x4026), 0x10 },
+	{ CCI_REG8(0x4032), 0x53 },
+	{ CCI_REG8(0x4036), 0x17 },
+	{ CCI_REG8(0x50b8), 0xf4 },
+	{ CCI_REG8(0x3016), 0x0 },
+	{ CCI_REG8(0x3017), 0x2c },
+	{ CCI_REG8(0x3018), 0x8c },
+	{ CCI_REG8(0x3019), 0x45 },
+	{ CCI_REG8(0x301a), 0x5 },
+	{ CCI_REG8(0x3013), 0xa },
+	{ CCI_REG8(0x301b), 0x0 },
+	{ CCI_REG8(0x301c), 0x4 },
+	{ CCI_REG8(0x301d), 0x88 },
+	{ CCI_REG8(0x301e), 0x45 },
+	{ CCI_REG8(0x301f), 0x5 },
+	{ CCI_REG8(0x3020), 0x0 },
+	{ CCI_REG8(0x3021), 0x4 },
+	{ CCI_REG8(0x3022), 0x88 },
+	{ CCI_REG8(0x3023), 0x45 },
+	{ CCI_REG8(0x3024), 0x5 },
+	{ CCI_REG8(0x3025), 0x0 },
+	{ CCI_REG8(0x3026), 0x4 },
+	{ CCI_REG8(0x3027), 0x88 },
+	{ CCI_REG8(0x3028), 0x45 },
+	{ CCI_REG8(0x3029), 0x5 },
+	{ CCI_REG8(0x302f), 0x0 },
+	{ CCI_REG8(0x3056), 0x0 },
+	{ CCI_REG8(0x3057), 0x0 },
+	{ CCI_REG8(0x3300), 0x1 },
+	{ CCI_REG8(0x3301), 0x0 },
+	{ CCI_REG8(0x3302), 0xb0 },
+	{ CCI_REG8(0x3303), 0xb0 },
+	{ CCI_REG8(0x3304), 0x16 },
+	{ CCI_REG8(0x3305), 0x15 },
+	{ CCI_REG8(0x3306), 0x1 },
+	{ CCI_REG8(0x3307), 0x0 },
+	{ CCI_REG8(0x3308), 0x30 },
+	{ CCI_REG8(0x3309), 0xa0 },
+	{ CCI_REG8(0x330a), 0x16 },
+	{ CCI_REG8(0x330b), 0x15 },
+	{ CCI_REG8(0x330c), 0x1 },
+	{ CCI_REG8(0x330d), 0x0 },
+	{ CCI_REG8(0x330e), 0x30 },
+	{ CCI_REG8(0x330f), 0xa0 },
+	{ CCI_REG8(0x3310), 0x16 },
+	{ CCI_REG8(0x3311), 0x15 },
+	{ CCI_REG8(0x3312), 0x1 },
+	{ CCI_REG8(0x3313), 0x0 },
+	{ CCI_REG8(0x3314), 0x30 },
+	{ CCI_REG8(0x3315), 0xa0 },
+	{ CCI_REG8(0x3316), 0x16 },
+	{ CCI_REG8(0x3317), 0x15 },
+	{ CCI_REG8(0x3318), 0x1 },
+	{ CCI_REG8(0x3319), 0x0 },
+	{ CCI_REG8(0x331a), 0x30 },
+	{ CCI_REG8(0x331b), 0xa0 },
+	{ CCI_REG8(0x331c), 0x16 },
+	{ CCI_REG8(0x331d), 0x15 },
+	{ CCI_REG8(0x331e), 0x1 },
+	{ CCI_REG8(0x331f), 0x0 },
+	{ CCI_REG8(0x3320), 0x30 },
+	{ CCI_REG8(0x3321), 0xa0 },
+	{ CCI_REG8(0x3322), 0x16 },
+	{ CCI_REG8(0x3323), 0x15 },
+	{ CCI_REG8(0x3324), 0x1 },
+	{ CCI_REG8(0x3325), 0x0 },
+	{ CCI_REG8(0x3326), 0x30 },
+	{ CCI_REG8(0x3327), 0xa0 },
+	{ CCI_REG8(0x3328), 0x16 },
+	{ CCI_REG8(0x3329), 0x15 },
+	{ CCI_REG8(0x332a), 0x2b },
+	{ CCI_REG8(0x332b), 0x0 },
+	{ CCI_REG8(0x332c), 0x30 },
+	{ CCI_REG8(0x332d), 0xa0 },
+	{ CCI_REG8(0x332e), 0x16 },
+	{ CCI_REG8(0x332f), 0x15 },
+	{ CCI_REG8(0x3330), 0x1 },
+	{ CCI_REG8(0x3331), 0x0 },
+	{ CCI_REG8(0x3332), 0x10 },
+	{ CCI_REG8(0x3333), 0xa0 },
+	{ CCI_REG8(0x3334), 0x16 },
+	{ CCI_REG8(0x3335), 0x15 },
+	{ CCI_REG8(0x3058), 0x8 },
+	{ CCI_REG8(0x3059), 0x0 },
+	{ CCI_REG8(0x305a), 0x9 },
+	{ CCI_REG8(0x305b), 0x0 },
+	{ CCI_REG8(0x3336), 0x1 },
+	{ CCI_REG8(0x3337), 0x0 },
+	{ CCI_REG8(0x3338), 0x90 },
+	{ CCI_REG8(0x3339), 0xb0 },
+	{ CCI_REG8(0x333a), 0x16 },
+	{ CCI_REG8(0x333b), 0x15 },
+	{ CCI_REG8(0x333c), 0x1f },
+	{ CCI_REG8(0x333d), 0x0 },
+	{ CCI_REG8(0x333e), 0x10 },
+	{ CCI_REG8(0x333f), 0xa0 },
+	{ CCI_REG8(0x3340), 0x16 },
+	{ CCI_REG8(0x3341), 0x15 },
+	{ CCI_REG8(0x3342), 0x52 },
+	{ CCI_REG8(0x3343), 0x0 },
+	{ CCI_REG8(0x3344), 0x10 },
+	{ CCI_REG8(0x3345), 0x80 },
+	{ CCI_REG8(0x3346), 0x16 },
+	{ CCI_REG8(0x3347), 0x15 },
+	{ CCI_REG8(0x3348), 0x1 },
+	{ CCI_REG8(0x3349), 0x0 },
+	{ CCI_REG8(0x334a), 0x10 },
+	{ CCI_REG8(0x334b), 0x80 },
+	{ CCI_REG8(0x334c), 0x16 },
+	{ CCI_REG8(0x334d), 0x1d },
+	{ CCI_REG8(0x334e), 0x1 },
+	{ CCI_REG8(0x334f), 0x0 },
+	{ CCI_REG8(0x3350), 0x50 },
+	{ CCI_REG8(0x3351), 0x84 },
+	{ CCI_REG8(0x3352), 0x16 },
+	{ CCI_REG8(0x3353), 0x1d },
+	{ CCI_REG8(0x3354), 0x18 },
+	{ CCI_REG8(0x3355), 0x0 },
+	{ CCI_REG8(0x3356), 0x10 },
+	{ CCI_REG8(0x3357), 0x84 },
+	{ CCI_REG8(0x3358), 0x16 },
+	{ CCI_REG8(0x3359), 0x1d },
+	{ CCI_REG8(0x335a), 0x80 },
+	{ CCI_REG8(0x335b), 0x2 },
+	{ CCI_REG8(0x335c), 0x10 },
+	{ CCI_REG8(0x335d), 0xc4 },
+	{ CCI_REG8(0x335e), 0x14 },
+	{ CCI_REG8(0x335f), 0x1d },
+	{ CCI_REG8(0x3360), 0xa5 },
+	{ CCI_REG8(0x3361), 0x0 },
+	{ CCI_REG8(0x3362), 0x10 },
+	{ CCI_REG8(0x3363), 0x84 },
+	{ CCI_REG8(0x3364), 0x16 },
+	{ CCI_REG8(0x3365), 0x1d },
+	{ CCI_REG8(0x3366), 0x1 },
+	{ CCI_REG8(0x3367), 0x0 },
+	{ CCI_REG8(0x3368), 0x90 },
+	{ CCI_REG8(0x3369), 0x84 },
+	{ CCI_REG8(0x336a), 0x16 },
+	{ CCI_REG8(0x336b), 0x1d },
+	{ CCI_REG8(0x336c), 0x12 },
+	{ CCI_REG8(0x336d), 0x0 },
+	{ CCI_REG8(0x336e), 0x10 },
+	{ CCI_REG8(0x336f), 0x84 },
+	{ CCI_REG8(0x3370), 0x16 },
+	{ CCI_REG8(0x3371), 0x15 },
+	{ CCI_REG8(0x3372), 0x32 },
+	{ CCI_REG8(0x3373), 0x0 },
+	{ CCI_REG8(0x3374), 0x30 },
+	{ CCI_REG8(0x3375), 0x84 },
+	{ CCI_REG8(0x3376), 0x16 },
+	{ CCI_REG8(0x3377), 0x15 },
+	{ CCI_REG8(0x3378), 0x26 },
+	{ CCI_REG8(0x3379), 0x0 },
+	{ CCI_REG8(0x337a), 0x10 },
+	{ CCI_REG8(0x337b), 0x84 },
+	{ CCI_REG8(0x337c), 0x16 },
+	{ CCI_REG8(0x337d), 0x15 },
+	{ CCI_REG8(0x337e), 0x80 },
+	{ CCI_REG8(0x337f), 0x2 },
+	{ CCI_REG8(0x3380), 0x10 },
+	{ CCI_REG8(0x3381), 0xc4 },
+	{ CCI_REG8(0x3382), 0x14 },
+	{ CCI_REG8(0x3383), 0x15 },
+	{ CCI_REG8(0x3384), 0xa9 },
+	{ CCI_REG8(0x3385), 0x0 },
+	{ CCI_REG8(0x3386), 0x10 },
+	{ CCI_REG8(0x3387), 0x84 },
+	{ CCI_REG8(0x3388), 0x16 },
+	{ CCI_REG8(0x3389), 0x15 },
+	{ CCI_REG8(0x338a), 0x41 },
+	{ CCI_REG8(0x338b), 0x0 },
+	{ CCI_REG8(0x338c), 0x10 },
+	{ CCI_REG8(0x338d), 0x80 },
+	{ CCI_REG8(0x338e), 0x16 },
+	{ CCI_REG8(0x338f), 0x15 },
+	{ CCI_REG8(0x3390), 0x2 },
+	{ CCI_REG8(0x3391), 0x0 },
+	{ CCI_REG8(0x3392), 0x10 },
+	{ CCI_REG8(0x3393), 0xa0 },
+	{ CCI_REG8(0x3394), 0x16 },
+	{ CCI_REG8(0x3395), 0x15 },
+	{ CCI_REG8(0x305c), 0x18 },
+	{ CCI_REG8(0x305d), 0x0 },
+	{ CCI_REG8(0x305e), 0x19 },
+	{ CCI_REG8(0x305f), 0x0 },
+	{ CCI_REG8(0x3396), 0x1 },
+	{ CCI_REG8(0x3397), 0x0 },
+	{ CCI_REG8(0x3398), 0x90 },
+	{ CCI_REG8(0x3399), 0x30 },
+	{ CCI_REG8(0x339a), 0x56 },
+	{ CCI_REG8(0x339b), 0x57 },
+	{ CCI_REG8(0x339c), 0x1 },
+	{ CCI_REG8(0x339d), 0x0 },
+	{ CCI_REG8(0x339e), 0x10 },
+	{ CCI_REG8(0x339f), 0x20 },
+	{ CCI_REG8(0x33a0), 0xd6 },
+	{ CCI_REG8(0x33a1), 0x17 },
+	{ CCI_REG8(0x33a2), 0x1 },
+	{ CCI_REG8(0x33a3), 0x0 },
+	{ CCI_REG8(0x33a4), 0x10 },
+	{ CCI_REG8(0x33a5), 0x28 },
+	{ CCI_REG8(0x33a6), 0xd6 },
+	{ CCI_REG8(0x33a7), 0x17 },
+	{ CCI_REG8(0x33a8), 0x3 },
+	{ CCI_REG8(0x33a9), 0x0 },
+	{ CCI_REG8(0x33aa), 0x10 },
+	{ CCI_REG8(0x33ab), 0x20 },
+	{ CCI_REG8(0x33ac), 0xd6 },
+	{ CCI_REG8(0x33ad), 0x17 },
+	{ CCI_REG8(0x33ae), 0x61 },
+	{ CCI_REG8(0x33af), 0x0 },
+	{ CCI_REG8(0x33b0), 0x10 },
+	{ CCI_REG8(0x33b1), 0x20 },
+	{ CCI_REG8(0x33b2), 0xd6 },
+	{ CCI_REG8(0x33b3), 0x15 },
+	{ CCI_REG8(0x33b4), 0x1 },
+	{ CCI_REG8(0x33b5), 0x0 },
+	{ CCI_REG8(0x33b6), 0x10 },
+	{ CCI_REG8(0x33b7), 0x20 },
+	{ CCI_REG8(0x33b8), 0xd6 },
+	{ CCI_REG8(0x33b9), 0x1d },
+	{ CCI_REG8(0x33ba), 0x1 },
+	{ CCI_REG8(0x33bb), 0x0 },
+	{ CCI_REG8(0x33bc), 0x50 },
+	{ CCI_REG8(0x33bd), 0x20 },
+	{ CCI_REG8(0x33be), 0xd6 },
+	{ CCI_REG8(0x33bf), 0x1d },
+	{ CCI_REG8(0x33c0), 0x2c },
+	{ CCI_REG8(0x33c1), 0x0 },
+	{ CCI_REG8(0x33c2), 0x10 },
+	{ CCI_REG8(0x33c3), 0x20 },
+	{ CCI_REG8(0x33c4), 0xd6 },
+	{ CCI_REG8(0x33c5), 0x1d },
+	{ CCI_REG8(0x33c6), 0x1 },
+	{ CCI_REG8(0x33c7), 0x0 },
+	{ CCI_REG8(0x33c8), 0x90 },
+	{ CCI_REG8(0x33c9), 0x20 },
+	{ CCI_REG8(0x33ca), 0xd6 },
+	{ CCI_REG8(0x33cb), 0x1d },
+	{ CCI_REG8(0x33cc), 0x83 },
+	{ CCI_REG8(0x33cd), 0x0 },
+	{ CCI_REG8(0x33ce), 0x10 },
+	{ CCI_REG8(0x33cf), 0x20 },
+	{ CCI_REG8(0x33d0), 0xd6 },
+	{ CCI_REG8(0x33d1), 0x15 },
+	{ CCI_REG8(0x33d2), 0x1 },
+	{ CCI_REG8(0x33d3), 0x0 },
+	{ CCI_REG8(0x33d4), 0x10 },
+	{ CCI_REG8(0x33d5), 0x30 },
+	{ CCI_REG8(0x33d6), 0xd6 },
+	{ CCI_REG8(0x33d7), 0x15 },
+	{ CCI_REG8(0x33d8), 0x1 },
+	{ CCI_REG8(0x33d9), 0x0 },
+	{ CCI_REG8(0x33da), 0x10 },
+	{ CCI_REG8(0x33db), 0x20 },
+	{ CCI_REG8(0x33dc), 0xd6 },
+	{ CCI_REG8(0x33dd), 0x15 },
+	{ CCI_REG8(0x33de), 0x1 },
+	{ CCI_REG8(0x33df), 0x0 },
+	{ CCI_REG8(0x33e0), 0x10 },
+	{ CCI_REG8(0x33e1), 0x20 },
+	{ CCI_REG8(0x33e2), 0x56 },
+	{ CCI_REG8(0x33e3), 0x15 },
+	{ CCI_REG8(0x33e4), 0x7 },
+	{ CCI_REG8(0x33e5), 0x0 },
+	{ CCI_REG8(0x33e6), 0x10 },
+	{ CCI_REG8(0x33e7), 0x20 },
+	{ CCI_REG8(0x33e8), 0x16 },
+	{ CCI_REG8(0x33e9), 0x15 },
+	{ CCI_REG8(0x3060), 0x26 },
+	{ CCI_REG8(0x3061), 0x0 },
+	{ CCI_REG8(0x302a), 0xff },
+	{ CCI_REG8(0x302b), 0xff },
+	{ CCI_REG8(0x302c), 0xff },
+	{ CCI_REG8(0x302d), 0xff },
+	{ CCI_REG8(0x302e), 0x3f },
+	{ CCI_REG8(0x3013), 0xb },
+	{ CCI_REG8(0x102b), 0x2c },
+	{ CCI_REG8(0x102c), 0x1 },
+	{ CCI_REG8(0x1035), 0x54 },
+	{ CCI_REG8(0x1036), 0x0 },
+	{ CCI_REG8(0x3090), 0x2a },
+	{ CCI_REG8(0x3091), 0x1 },
+	{ CCI_REG8(0x30c6), 0x5 },
+	{ CCI_REG8(0x30c7), 0x0 },
+	{ CCI_REG8(0x30c8), 0x0 },
+	{ CCI_REG8(0x30c9), 0x0 },
+	{ CCI_REG8(0x30ca), 0x0 },
+	{ CCI_REG8(0x30cb), 0x0 },
+	{ CCI_REG8(0x30cc), 0x0 },
+	{ CCI_REG8(0x30cd), 0x0 },
+	{ CCI_REG8(0x30ce), 0x0 },
+	{ CCI_REG8(0x30cf), 0x5 },
+	{ CCI_REG8(0x30d0), 0x0 },
+	{ CCI_REG8(0x30d1), 0x0 },
+	{ CCI_REG8(0x30d2), 0x0 },
+	{ CCI_REG8(0x30d3), 0x0 },
+	{ CCI_REG8(0x30d4), 0x0 },
+	{ CCI_REG8(0x30d5), 0x0 },
+	{ CCI_REG8(0x30d6), 0x0 },
+	{ CCI_REG8(0x30d7), 0x0 },
+	{ CCI_REG8(0x30f3), 0x5 },
+	{ CCI_REG8(0x30f4), 0x0 },
+	{ CCI_REG8(0x30f5), 0x0 },
+	{ CCI_REG8(0x30f6), 0x0 },
+	{ CCI_REG8(0x30f7), 0x0 },
+	{ CCI_REG8(0x30f8), 0x0 },
+	{ CCI_REG8(0x30f9), 0x0 },
+	{ CCI_REG8(0x30fa), 0x0 },
+	{ CCI_REG8(0x30fb), 0x0 },
+	{ CCI_REG8(0x30d8), 0x5 },
+	{ CCI_REG8(0x30d9), 0x0 },
+	{ CCI_REG8(0x30da), 0x0 },
+	{ CCI_REG8(0x30db), 0x0 },
+	{ CCI_REG8(0x30dc), 0x0 },
+	{ CCI_REG8(0x30dd), 0x0 },
+	{ CCI_REG8(0x30de), 0x0 },
+	{ CCI_REG8(0x30df), 0x0 },
+	{ CCI_REG8(0x30e0), 0x0 },
+	{ CCI_REG8(0x30e1), 0x5 },
+	{ CCI_REG8(0x30e2), 0x0 },
+	{ CCI_REG8(0x30e3), 0x0 },
+	{ CCI_REG8(0x30e4), 0x0 },
+	{ CCI_REG8(0x30e5), 0x0 },
+	{ CCI_REG8(0x30e6), 0x0 },
+	{ CCI_REG8(0x30e7), 0x0 },
+	{ CCI_REG8(0x30e8), 0x0 },
+	{ CCI_REG8(0x30e9), 0x0 },
+	{ CCI_REG8(0x30f3), 0x5 },
+	{ CCI_REG8(0x30f4), 0x2 },
+	{ CCI_REG8(0x30f5), 0x0 },
+	{ CCI_REG8(0x30f6), 0x17 },
+	{ CCI_REG8(0x30f7), 0x1 },
+	{ CCI_REG8(0x30f8), 0x0 },
+	{ CCI_REG8(0x30f9), 0x0 },
+	{ CCI_REG8(0x30fa), 0x0 },
+	{ CCI_REG8(0x30fb), 0x0 },
+	{ CCI_REG8(0x30d8), 0x3 },
+	{ CCI_REG8(0x30d9), 0x1 },
+	{ CCI_REG8(0x30da), 0x0 },
+	{ CCI_REG8(0x30db), 0x19 },
+	{ CCI_REG8(0x30dc), 0x1 },
+	{ CCI_REG8(0x30dd), 0x0 },
+	{ CCI_REG8(0x30de), 0x0 },
+	{ CCI_REG8(0x30df), 0x0 },
+	{ CCI_REG8(0x30e0), 0x0 },
+	{ CCI_REG8(0x30a2), 0x5 },
+	{ CCI_REG8(0x30a3), 0x2 },
+	{ CCI_REG8(0x30a4), 0x0 },
+	{ CCI_REG8(0x30a5), 0x22 },
+	{ CCI_REG8(0x30a6), 0x0 },
+	{ CCI_REG8(0x30a7), 0x0 },
+	{ CCI_REG8(0x30a8), 0x0 },
+	{ CCI_REG8(0x30a9), 0x0 },
+	{ CCI_REG8(0x30aa), 0x0 },
+	{ CCI_REG8(0x30ab), 0x5 },
+	{ CCI_REG8(0x30ac), 0x2 },
+	{ CCI_REG8(0x30ad), 0x0 },
+	{ CCI_REG8(0x30ae), 0x22 },
+	{ CCI_REG8(0x30af), 0x0 },
+	{ CCI_REG8(0x30b0), 0x0 },
+	{ CCI_REG8(0x30b1), 0x0 },
+	{ CCI_REG8(0x30b2), 0x0 },
+	{ CCI_REG8(0x30b3), 0x0 },
+	{ CCI_REG8(0x30bd), 0x5 },
+	{ CCI_REG8(0x30be), 0x9f },
+	{ CCI_REG8(0x30bf), 0x0 },
+	{ CCI_REG8(0x30c0), 0x7d },
+	{ CCI_REG8(0x30c1), 0x0 },
+	{ CCI_REG8(0x30c2), 0x0 },
+	{ CCI_REG8(0x30c3), 0x0 },
+	{ CCI_REG8(0x30c4), 0x0 },
+	{ CCI_REG8(0x30c5), 0x0 },
+	{ CCI_REG8(0x30b4), 0x4 },
+	{ CCI_REG8(0x30b5), 0x9c },
+	{ CCI_REG8(0x30b6), 0x0 },
+	{ CCI_REG8(0x30b7), 0x7d },
+	{ CCI_REG8(0x30b8), 0x0 },
+	{ CCI_REG8(0x30b9), 0x0 },
+	{ CCI_REG8(0x30ba), 0x0 },
+	{ CCI_REG8(0x30bb), 0x0 },
+	{ CCI_REG8(0x30bc), 0x0 },
+	{ CCI_REG8(0x30fc), 0x5 },
+	{ CCI_REG8(0x30fd), 0x0 },
+	{ CCI_REG8(0x30fe), 0x0 },
+	{ CCI_REG8(0x30ff), 0x0 },
+	{ CCI_REG8(0x3100), 0x0 },
+	{ CCI_REG8(0x3101), 0x0 },
+	{ CCI_REG8(0x3102), 0x0 },
+	{ CCI_REG8(0x3103), 0x0 },
+	{ CCI_REG8(0x3104), 0x0 },
+	{ CCI_REG8(0x3105), 0x5 },
+	{ CCI_REG8(0x3106), 0x0 },
+	{ CCI_REG8(0x3107), 0x0 },
+	{ CCI_REG8(0x3108), 0x0 },
+	{ CCI_REG8(0x3109), 0x0 },
+	{ CCI_REG8(0x310a), 0x0 },
+	{ CCI_REG8(0x310b), 0x0 },
+	{ CCI_REG8(0x310c), 0x0 },
+	{ CCI_REG8(0x310d), 0x0 },
+	{ CCI_REG8(0x3099), 0x5 },
+	{ CCI_REG8(0x309a), 0x96 },
+	{ CCI_REG8(0x309b), 0x0 },
+	{ CCI_REG8(0x309c), 0x6 },
+	{ CCI_REG8(0x309d), 0x0 },
+	{ CCI_REG8(0x309e), 0x0 },
+	{ CCI_REG8(0x309f), 0x0 },
+	{ CCI_REG8(0x30a0), 0x0 },
+	{ CCI_REG8(0x30a1), 0x0 },
+	{ CCI_REG8(0x310e), 0x5 },
+	{ CCI_REG8(0x310f), 0x2 },
+	{ CCI_REG8(0x3110), 0x0 },
+	{ CCI_REG8(0x3111), 0x2b },
+	{ CCI_REG8(0x3112), 0x0 },
+	{ CCI_REG8(0x3113), 0x0 },
+	{ CCI_REG8(0x3114), 0x0 },
+	{ CCI_REG8(0x3115), 0x0 },
+	{ CCI_REG8(0x3116), 0x0 },
+	{ CCI_REG8(0x3117), 0x5 },
+	{ CCI_REG8(0x3118), 0x2 },
+	{ CCI_REG8(0x3119), 0x0 },
+	{ CCI_REG8(0x311a), 0x2c },
+	{ CCI_REG8(0x311b), 0x0 },
+	{ CCI_REG8(0x311c), 0x0 },
+	{ CCI_REG8(0x311d), 0x0 },
+	{ CCI_REG8(0x311e), 0x0 },
+	{ CCI_REG8(0x311f), 0x0 },
+	{ CCI_REG8(0x30ea), 0x0 },
+	{ CCI_REG8(0x30eb), 0x0 },
+	{ CCI_REG8(0x30ec), 0x0 },
+	{ CCI_REG8(0x30ed), 0x0 },
+	{ CCI_REG8(0x30ee), 0x0 },
+	{ CCI_REG8(0x30ef), 0x0 },
+	{ CCI_REG8(0x30f0), 0x0 },
+	{ CCI_REG8(0x30f1), 0x0 },
+	{ CCI_REG8(0x30f2), 0x0 },
+	{ CCI_REG8(0x313b), 0x3 },
+	{ CCI_REG8(0x313c), 0x31 },
+	{ CCI_REG8(0x313d), 0x0 },
+	{ CCI_REG8(0x313e), 0x7 },
+	{ CCI_REG8(0x313f), 0x0 },
+	{ CCI_REG8(0x3140), 0x68 },
+	{ CCI_REG8(0x3141), 0x0 },
+	{ CCI_REG8(0x3142), 0x34 },
+	{ CCI_REG8(0x3143), 0x0 },
+	{ CCI_REG8(0x31a0), 0x3 },
+	{ CCI_REG8(0x31a1), 0x16 },
+	{ CCI_REG8(0x31a2), 0x0 },
+	{ CCI_REG8(0x31a3), 0x8 },
+	{ CCI_REG8(0x31a4), 0x0 },
+	{ CCI_REG8(0x31a5), 0x7e },
+	{ CCI_REG8(0x31a6), 0x0 },
+	{ CCI_REG8(0x31a7), 0x8 },
+	{ CCI_REG8(0x31a8), 0x0 },
+	{ CCI_REG8(0x31a9), 0x3 },
+	{ CCI_REG8(0x31aa), 0x16 },
+	{ CCI_REG8(0x31ab), 0x0 },
+	{ CCI_REG8(0x31ac), 0x8 },
+	{ CCI_REG8(0x31ad), 0x0 },
+	{ CCI_REG8(0x31ae), 0x7e },
+	{ CCI_REG8(0x31af), 0x0 },
+	{ CCI_REG8(0x31b0), 0x8 },
+	{ CCI_REG8(0x31b1), 0x0 },
+	{ CCI_REG8(0x31b2), 0x3 },
+	{ CCI_REG8(0x31b3), 0x16 },
+	{ CCI_REG8(0x31b4), 0x0 },
+	{ CCI_REG8(0x31b5), 0x8 },
+	{ CCI_REG8(0x31b6), 0x0 },
+	{ CCI_REG8(0x31b7), 0x7e },
+	{ CCI_REG8(0x31b8), 0x0 },
+	{ CCI_REG8(0x31b9), 0x8 },
+	{ CCI_REG8(0x31ba), 0x0 },
+	{ CCI_REG8(0x3120), 0x5 },
+	{ CCI_REG8(0x3121), 0x45 },
+	{ CCI_REG8(0x3122), 0x0 },
+	{ CCI_REG8(0x3123), 0x1d },
+	{ CCI_REG8(0x3124), 0x0 },
+	{ CCI_REG8(0x3125), 0xa9 },
+	{ CCI_REG8(0x3126), 0x0 },
+	{ CCI_REG8(0x3127), 0x6d },
+	{ CCI_REG8(0x3128), 0x0 },
+	{ CCI_REG8(0x3129), 0x5 },
+	{ CCI_REG8(0x312a), 0x15 },
+	{ CCI_REG8(0x312b), 0x0 },
+	{ CCI_REG8(0x312c), 0xa },
+	{ CCI_REG8(0x312d), 0x0 },
+	{ CCI_REG8(0x312e), 0x45 },
+	{ CCI_REG8(0x312f), 0x0 },
+	{ CCI_REG8(0x3130), 0x1d },
+	{ CCI_REG8(0x3131), 0x0 },
+	{ CCI_REG8(0x3132), 0x5 },
+	{ CCI_REG8(0x3133), 0x7d },
+	{ CCI_REG8(0x3134), 0x0 },
+	{ CCI_REG8(0x3135), 0xa },
+	{ CCI_REG8(0x3136), 0x0 },
+	{ CCI_REG8(0x3137), 0xa9 },
+	{ CCI_REG8(0x3138), 0x0 },
+	{ CCI_REG8(0x3139), 0x6d },
+	{ CCI_REG8(0x313a), 0x0 },
+	{ CCI_REG8(0x3144), 0x5 },
+	{ CCI_REG8(0x3145), 0x0 },
+	{ CCI_REG8(0x3146), 0x0 },
+	{ CCI_REG8(0x3147), 0x30 },
+	{ CCI_REG8(0x3148), 0x0 },
+	{ CCI_REG8(0x3149), 0x0 },
+	{ CCI_REG8(0x314a), 0x0 },
+	{ CCI_REG8(0x314b), 0x0 },
+	{ CCI_REG8(0x314c), 0x0 },
+	{ CCI_REG8(0x314d), 0x3 },
+	{ CCI_REG8(0x314e), 0x0 },
+	{ CCI_REG8(0x314f), 0x0 },
+	{ CCI_REG8(0x3150), 0x31 },
+	{ CCI_REG8(0x3151), 0x0 },
+	{ CCI_REG8(0x3152), 0x0 },
+	{ CCI_REG8(0x3153), 0x0 },
+	{ CCI_REG8(0x3154), 0x0 },
+	{ CCI_REG8(0x3155), 0x0 },
+	{ CCI_REG8(0x31d8), 0x5 },
+	{ CCI_REG8(0x31d9), 0x3a },
+	{ CCI_REG8(0x31da), 0x0 },
+	{ CCI_REG8(0x31db), 0x2e },
+	{ CCI_REG8(0x31dc), 0x0 },
+	{ CCI_REG8(0x31dd), 0x9e },
+	{ CCI_REG8(0x31de), 0x0 },
+	{ CCI_REG8(0x31df), 0x7e },
+	{ CCI_REG8(0x31e0), 0x0 },
+	{ CCI_REG8(0x31e1), 0x5 },
+	{ CCI_REG8(0x31e2), 0x4 },
+	{ CCI_REG8(0x31e3), 0x0 },
+	{ CCI_REG8(0x31e4), 0x4 },
+	{ CCI_REG8(0x31e5), 0x0 },
+	{ CCI_REG8(0x31e6), 0x73 },
+	{ CCI_REG8(0x31e7), 0x0 },
+	{ CCI_REG8(0x31e8), 0x4 },
+	{ CCI_REG8(0x31e9), 0x0 },
+	{ CCI_REG8(0x31ea), 0x5 },
+	{ CCI_REG8(0x31eb), 0x0 },
+	{ CCI_REG8(0x31ec), 0x0 },
+	{ CCI_REG8(0x31ed), 0x0 },
+	{ CCI_REG8(0x31ee), 0x0 },
+	{ CCI_REG8(0x31ef), 0x0 },
+	{ CCI_REG8(0x31f0), 0x0 },
+	{ CCI_REG8(0x31f1), 0x0 },
+	{ CCI_REG8(0x31f2), 0x0 },
+	{ CCI_REG8(0x31f3), 0x0 },
+	{ CCI_REG8(0x31f4), 0x0 },
+	{ CCI_REG8(0x31f5), 0x0 },
+	{ CCI_REG8(0x31f6), 0x0 },
+	{ CCI_REG8(0x31f7), 0x0 },
+	{ CCI_REG8(0x31f8), 0x0 },
+	{ CCI_REG8(0x31f9), 0x0 },
+	{ CCI_REG8(0x31fa), 0x0 },
+	{ CCI_REG8(0x31fb), 0x5 },
+	{ CCI_REG8(0x31fc), 0x0 },
+	{ CCI_REG8(0x31fd), 0x0 },
+	{ CCI_REG8(0x31fe), 0x0 },
+	{ CCI_REG8(0x31ff), 0x0 },
+	{ CCI_REG8(0x3200), 0x0 },
+	{ CCI_REG8(0x3201), 0x0 },
+	{ CCI_REG8(0x3202), 0x0 },
+	{ CCI_REG8(0x3203), 0x0 },
+	{ CCI_REG8(0x3204), 0x0 },
+	{ CCI_REG8(0x3205), 0x0 },
+	{ CCI_REG8(0x3206), 0x0 },
+	{ CCI_REG8(0x3207), 0x0 },
+	{ CCI_REG8(0x3208), 0x0 },
+	{ CCI_REG8(0x3209), 0x0 },
+	{ CCI_REG8(0x320a), 0x0 },
+	{ CCI_REG8(0x320b), 0x0 },
+	{ CCI_REG8(0x3164), 0x5 },
+	{ CCI_REG8(0x3165), 0x14 },
+	{ CCI_REG8(0x3166), 0x0 },
+	{ CCI_REG8(0x3167), 0xc },
+	{ CCI_REG8(0x3168), 0x0 },
+	{ CCI_REG8(0x3169), 0x44 },
+	{ CCI_REG8(0x316a), 0x0 },
+	{ CCI_REG8(0x316b), 0x1f },
+	{ CCI_REG8(0x316c), 0x0 },
+	{ CCI_REG8(0x316d), 0x5 },
+	{ CCI_REG8(0x316e), 0x7c },
+	{ CCI_REG8(0x316f), 0x0 },
+	{ CCI_REG8(0x3170), 0xc },
+	{ CCI_REG8(0x3171), 0x0 },
+	{ CCI_REG8(0x3172), 0xa8 },
+	{ CCI_REG8(0x3173), 0x0 },
+	{ CCI_REG8(0x3174), 0x6f },
+	{ CCI_REG8(0x3175), 0x0 },
+	{ CCI_REG8(0x31c4), 0x5 },
+	{ CCI_REG8(0x31c5), 0x24 },
+	{ CCI_REG8(0x31c6), 0x1 },
+	{ CCI_REG8(0x31c7), 0x4 },
+	{ CCI_REG8(0x31c8), 0x0 },
+	{ CCI_REG8(0x31c9), 0x5 },
+	{ CCI_REG8(0x31ca), 0x24 },
+	{ CCI_REG8(0x31cb), 0x1 },
+	{ CCI_REG8(0x31cc), 0x4 },
+	{ CCI_REG8(0x31cd), 0x0 },
+	{ CCI_REG8(0x31ce), 0x5 },
+	{ CCI_REG8(0x31cf), 0x24 },
+	{ CCI_REG8(0x31d0), 0x1 },
+	{ CCI_REG8(0x31d1), 0x4 },
+	{ CCI_REG8(0x31d2), 0x0 },
+	{ CCI_REG8(0x31d3), 0x5 },
+	{ CCI_REG8(0x31d4), 0x73 },
+	{ CCI_REG8(0x31d5), 0x0 },
+	{ CCI_REG8(0x31d6), 0xb1 },
+	{ CCI_REG8(0x31d7), 0x0 },
+	{ CCI_REG8(0x3176), 0x5 },
+	{ CCI_REG8(0x3177), 0x10 },
+	{ CCI_REG8(0x3178), 0x0 },
+	{ CCI_REG8(0x3179), 0x56 },
+	{ CCI_REG8(0x317a), 0x0 },
+	{ CCI_REG8(0x317b), 0x0 },
+	{ CCI_REG8(0x317c), 0x0 },
+	{ CCI_REG8(0x317d), 0x0 },
+	{ CCI_REG8(0x317e), 0x0 },
+	{ CCI_REG8(0x317f), 0x5 },
+	{ CCI_REG8(0x3180), 0x6a },
+	{ CCI_REG8(0x3181), 0x0 },
+	{ CCI_REG8(0x3182), 0xad },
+	{ CCI_REG8(0x3183), 0x0 },
+	{ CCI_REG8(0x3184), 0x0 },
+	{ CCI_REG8(0x3185), 0x0 },
+	{ CCI_REG8(0x3186), 0x0 },
+	{ CCI_REG8(0x3187), 0x0 },
+	{ CCI_REG8(0x100d), 0x0 },
+	{ CCI_REG8(0x1013), 0x2b },
+	/* Sensor control mode */
+	{ CCI_REG8(0x0043), 0x0 }, //  Sensor Control Mode.SLEEP_POWER_MODE(0)
+	{ CCI_REG8(0x0043), 0x0 }, //  Sensor Control Mode.IDLE_POWER_MODE(0)
+	{ CCI_REG8(0x0043), 0x4 }, //  Sensor Control Mode.SYSTEM_CLOCK_ENABLE(0)
+	{ CCI_REG8(0x0043), 0xC }, //  Sensor Control Mode.SRAM_CLOCK_ENABLE(0)
+	{ CCI_REG8(0x1001), 0x41 }, //  Sensor Control Mode.EXT_EVENT_SEL(0)
+	{ CCI_REG8(0x10f2), 0x1 }, //  Sensor Control Mode.NB_OF_FRAMES_A(0)
+	{ CCI_REG8(0x10f3), 0x0 }, //  Sensor Control Mode.NB_OF_FRAMES_A(1)
+	{ CCI_REG8(0x0012), 0x0 }, //  IO Drive Strength.DIG_DRIVE_STRENGTH(0)
+	{ CCI_REG8(0x0012), 0x0 }, //  IO Drive Strength.CCI_DRIVE_STRENGTH(0)
+	{ CCI_REG8(0x1001), 0x41 }, //  Readout && Exposure.EXT_EXP_PW_SEL(0)
+	{ CCI_REG8(0x10d0), 0x0 }, //  Readout && Exposure.EXT_EXP_PW_DELAY(0)
+	{ CCI_REG8(0x10d1), 0x0 }, //  Readout && Exposure.EXT_EXP_PW_DELAY(1)
+	/* MIPI */
+	{ CCI_REG8(0x6006), 0x0 }, //  MIPI.TX_CTRL_EN(0)
+	{ CCI_REG8(0x5004), 0x1 }, //  MIPI.datarate
+	{ CCI_REG8(0x5086), 0x2 }, //  MIPI.datarate
+	{ CCI_REG8(0x5087), 0x4e }, //  MIPI.datarate
+	{ CCI_REG8(0x5088), 0x0 }, //  MIPI.datarate
+	{ CCI_REG8(0x5090), 0x0 }, //  MIPI.datarate
+	{ CCI_REG8(0x5091), 0x8 }, //  MIPI.datarate
+	{ CCI_REG8(0x5092), 0x14 }, //  MIPI.datarate
+	{ CCI_REG8(0x5093), 0xf }, //  MIPI.datarate
+	{ CCI_REG8(0x5094), 0x6 }, //  MIPI.datarate
+	{ CCI_REG8(0x5095), 0x32 }, //  MIPI.datarate
+	{ CCI_REG8(0x5096), 0xe }, //  MIPI.datarate
+	{ CCI_REG8(0x5097), 0x0 }, //  MIPI.datarate
+	{ CCI_REG8(0x5098), 0x11 }, //  MIPI.datarate
+	{ CCI_REG8(0x5004), 0x0 }, //  MIPI.datarate
+	{ CCI_REG8(0x2066), 0x6c }, //  MIPI.datarate
+	{ CCI_REG8(0x2067), 0x7 }, //  MIPI.datarate
+	{ CCI_REG8(0x206e), 0x7e }, //  MIPI.datarate
+	{ CCI_REG8(0x206f), 0x6 }, //  MIPI.datarate
+	{ CCI_REG8(0x20ac), 0x7e }, //  MIPI.datarate
+	{ CCI_REG8(0x20ad), 0x6 }, //  MIPI.datarate
+	{ CCI_REG8(0x2076), 0xc8 }, //  MIPI.datarate
+	{ CCI_REG8(0x2077), 0x0 }, //  MIPI.datarate
+	{ CCI_REG8(0x20b4), 0xc8 }, //  MIPI.datarate
+	{ CCI_REG8(0x20b5), 0x0 }, //  MIPI.datarate
+	{ CCI_REG8(0x2078), 0x1e }, //  MIPI.datarate
+	{ CCI_REG8(0x2079), 0x4 }, //  MIPI.datarate
+	{ CCI_REG8(0x20b6), 0x1e }, //  MIPI.datarate
+	{ CCI_REG8(0x20b7), 0x4 }, //  MIPI.datarate
+	{ CCI_REG8(0x207a), 0xd4 }, //  MIPI.datarate
+	{ CCI_REG8(0x207b), 0x4 }, //  MIPI.datarate
+	{ CCI_REG8(0x20b8), 0xd4 }, //  MIPI.datarate
+	{ CCI_REG8(0x20b9), 0x4 }, //  MIPI.datarate
+	{ CCI_REG8(0x207c), 0x0 }, //  MIPI.VC_ID(0)
+	{ CCI_REG8(0x6001), 0x7 }, //  MIPI.TINIT(0)
+	{ CCI_REG8(0x6002), 0xd8 }, //  MIPI.TINIT(1)
+	{ CCI_REG8(0x6010), 0x0 }, //  MIPI.FRAME_MODE(0)
+	{ CCI_REG8(0x6010), 0x0 }, //  MIPI.EMBEDDED_FRAME_MODE(0)
+	{ CCI_REG8(0x6011), 0x0 }, //  MIPI.DATA_ENABLE_POLARITY(0)
+	{ CCI_REG8(0x6011), 0x0 }, //  MIPI.HSYNC_POLARITY(0)
+	{ CCI_REG8(0x6011), 0x0 }, //  MIPI.VSYNC_POLARITY(0)
+	{ CCI_REG8(0x6016), 0x0 }, //  MIPI.FRAME_COUNTER(0)
+	{ CCI_REG8(0x6017), 0x0 }, //  MIPI.FRAME_COUNTER(1)
+	{ CCI_REG8(0x6037), 0x1 }, //  MIPI.LINE_COUNT_RAW8(0)
+	{ CCI_REG8(0x6037), 0x3 }, //  MIPI.LINE_COUNT_RAW10(0)
+	{ CCI_REG8(0x6037), 0x7 }, //  MIPI.LINE_COUNT_RAW12(0)
+	{ CCI_REG8(0x6039), 0x1 }, //  MIPI.LINE_COUNT_EMB(0)
+	{ CCI_REG8(0x6018), 0x0 }, //  MIPI.CCI_READ_INTERRUPT_EN(0)
+	{ CCI_REG8(0x6018), 0x0 }, //  MIPI.CCI_WRITE_INTERRUPT_EN(0)
+	{ CCI_REG8(0x6065), 0x0 }, //  MIPI.TWAKE_TIMER(0)
+	{ CCI_REG8(0x6066), 0x0 }, //  MIPI.TWAKE_TIMER(1)
+	{ CCI_REG8(0x601c), 0x0 }, //  MIPI.SKEW_CAL_EN(0)
+	{ CCI_REG8(0x601d), 0x0 }, //  MIPI.SKEW_COUNT(0)
+	{ CCI_REG8(0x601e), 0x22 }, //  MIPI.SKEW_COUNT(1)
+	{ CCI_REG8(0x601f), 0x0 }, //  MIPI.SCRAMBLING_EN(0)
+	{ CCI_REG8(0x6003), 0x1 }, //  MIPI.INIT_SKEW_EN(0)
+	{ CCI_REG8(0x6004), 0x7a }, //  MIPI.INIT_SKEW(0)
+	{ CCI_REG8(0x6005), 0x12 }, //  MIPI.INIT_SKEW(1)
+	{ CCI_REG8(0x6006), 0x1 }, //  MIPI.TX_CTRL_EN(0)
+	/* Processing */
+	{ CCI_REG8(0x4006), 0x8 }, //  Processing.BSP(0)
+	{ CCI_REG8(0x2045), 0x1 }, //  Processing.CDS_RNC(0)
+	{ CCI_REG8(0x2048), 0x1 }, //  Processing.CDS_IMG(0)
+	{ CCI_REG8(0x204b), 0x3 }, //  Processing.RNC_EN(0)
+	{ CCI_REG8(0x205b), 0x64 }, //  Processing.RNC_DARK_TARGET(0)
+	{ CCI_REG8(0x205c), 0x0 }, //  Processing.RNC_DARK_TARGET(1)
+	{ CCI_REG8(0x24dc), 0x12 }, //  Defect Pixel Correction.DC_ENABLE(0)
+	{ CCI_REG8(0x24dc), 0x10 }, //  Defect Pixel Correction.DC_MODE(0)
+	{ CCI_REG8(0x24dc), 0x0 }, //  Defect Pixel Correction.DC_REPLACEMENT_VALUE(0)
+	{ CCI_REG8(0x24dd), 0x0 }, //  Defect Pixel Correction.DC_LIMIT_LOW(0)
+	{ CCI_REG8(0x24de), 0x0 }, //  Defect Pixel Correction.DC_LIMIT_HIGH(0)
+	{ CCI_REG8(0x24df), 0x0 }, //  Defect Pixel Correction.DC_LIMIT_HIGH_MODE(0)
+	/* Illumination */
+	{ CCI_REG8(0x10d7), 0x1 }, //  Illumination Trigger.ILLUM_EN(0)
+	{ CCI_REG8(0x10d8), 0x2 }, //  Illumination Trigger.ILLUM_POL(0)
+	/* Histogram */
+	{ CCI_REG8(0x205d), 0x0 }, //  Histogram.HIST_EN(0)
+	{ CCI_REG8(0x205e), 0x0 }, //  Histogram.HIST_USAGE_RATIO(0)
+	{ CCI_REG8(0x2063), 0x0 }, //  Histogram.PIXEL_DATA_SUPP(0)
+	{ CCI_REG8(0x2063), 0x0 }, //  Histogram.PIXEL_TRANSMISSION(0)
+	/* TP */
+	{ CCI_REG8(0x2091), 0x0 }, //  Test Pattern Generator.TPG_EN(0)
+	{ CCI_REG8(0x2091), 0x0 }, //  Test Pattern Generator.TPG_CONFIG(0)
+	/* Reduce Slew Rate - fix for defect line */
+	{ CCI_REG8(0x402d), 0x7b },
+};
+
+static const char *const mira220_test_pattern_menu[] = {
+	"Disabled",
+	"Vertical Gradient",
+};
+
+static const int mira220_test_pattern_val[] = {
+	MIRA220_TEST_PATTERN_DISABLE,
+	MIRA220_TEST_PATTERN_VERTICAL_GRADIENT,
+};
+
+/* regulator supplies */
+static const char *const mira220_supplies[] = {
+	/* Supplies can be enabled in any order */
+	"vana", /* Analog (2.8V) supply */
+	"vdig", /* Digital Core (1.8V) supply */
+	"vddl", /* IF (1.2V) supply */
+};
+
+struct mira220 {
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+
+	enum mira220_variants variant;
+
+	struct v4l2_mbus_framefmt fmt;
+
+	struct clk *xclk;
+	u32 xclk_freq;
+
+	struct regulator_bulk_data supplies[ARRAY_SIZE(mira220_supplies)];
+
+	struct gpio_desc *reset_gpio;
+
+	unsigned int lanes;
+	unsigned int row_length;
+
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *exposure;
+
+	struct regmap *regmap;
+};
+
+static inline struct mira220 *to_mira220(struct v4l2_subdev *sd)
+{
+	return container_of_const(sd, struct mira220, sd);
+}
+
+static bool mira220_is_mono(struct mira220 *mira220)
+{
+	return mira220->variant == MIRA220_VARIANT_MONO;
+}
+
+/*
+ * The supported formats. This table contains 4 entries per format, to cover the
+ * various flip combinations in the order:
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 mira220_mbus_color_formats[] = {
+	MEDIA_BUS_FMT_SGRBG12_1X12,
+	MEDIA_BUS_FMT_SRGGB12_1X12,
+	MEDIA_BUS_FMT_SBGGR12_1X12,
+	MEDIA_BUS_FMT_SGBRG12_1X12,
+
+	MEDIA_BUS_FMT_SGRBG10_1X10,
+	MEDIA_BUS_FMT_SRGGB10_1X10,
+	MEDIA_BUS_FMT_SBGGR10_1X10,
+	MEDIA_BUS_FMT_SGBRG10_1X10,
+
+	MEDIA_BUS_FMT_SGRBG8_1X8,
+	MEDIA_BUS_FMT_SRGGB8_1X8,
+	MEDIA_BUS_FMT_SBGGR8_1X8,
+	MEDIA_BUS_FMT_SGBRG8_1X8,
+};
+
+static const u32 mira220_mbus_mono_formats[] = {
+	MEDIA_BUS_FMT_Y12_1X12,
+	MEDIA_BUS_FMT_Y10_1X10,
+	MEDIA_BUS_FMT_Y8_1X8,
+};
+
+#define MIRA220_FLIP_FORMAT_MASK	0x3
+static inline unsigned int mira220_flip_format_index(struct mira220 *mira220,
+						     unsigned int index)
+{
+	return (index & ~MIRA220_FLIP_FORMAT_MASK)	|
+	       (mira220->vflip->val ? BIT(1) : 0)	|
+	       (mira220->hflip->val ? BIT(0) : 0);
+}
+
+
+/* Power/clock management functions */
+static int mira220_power_on(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct mira220 *mira220 = to_mira220(sd);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(mira220_supplies),
+				    mira220->supplies);
+	if (ret) {
+		dev_err(&client->dev, "%s: failed to enable regulators\n",
+			__func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(mira220->xclk);
+	if (ret) {
+		dev_err(&client->dev, "%s: failed to enable clock\n", __func__);
+		goto reg_off;
+	}
+
+	gpiod_set_value_cansleep(mira220->reset_gpio, 0);
+
+	return 0;
+
+reg_off:
+	regulator_bulk_disable(ARRAY_SIZE(mira220_supplies), mira220->supplies);
+	return ret;
+}
+
+static int mira220_power_off(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct mira220 *mira220 = to_mira220(sd);
+
+	gpiod_set_value_cansleep(mira220->reset_gpio, 1);
+	clk_disable_unprepare(mira220->xclk);
+	regulator_bulk_disable(ARRAY_SIZE(mira220_supplies), mira220->supplies);
+
+	return 0;
+}
+
+static int mira220_write_start_streaming_regs(struct mira220 *mira220)
+{
+	int ret = 0;
+
+	/* Setting master control */
+	cci_write(mira220->regmap, MIRA220_IMAGER_STATE_REG,
+		  MIRA220_IMAGER_STATE_MASTER_CONTROL, &ret);
+
+	/* Enable continuous streaming */
+	cci_write(mira220->regmap, MIRA220_IMAGER_RUN_CONT_REG,
+		  MIRA220_IMAGER_RUN_CONT_ENABLE, &ret);
+	cci_write(mira220->regmap, MIRA220_IMAGER_RUN_REG,
+		  MIRA220_IMAGER_RUN_START, &ret);
+
+	return ret;
+}
+
+static int mira220_write_stop_streaming_regs(struct mira220 *mira220)
+{
+	int ret = 0;
+
+	cci_write(mira220->regmap, MIRA220_IMAGER_STATE_REG,
+		  MIRA220_IMAGER_STATE_STOP_AT_ROW, &ret);
+	cci_write(mira220->regmap, MIRA220_IMAGER_RUN_REG,
+		  MIRA220_IMAGER_RUN_STOP, &ret);
+
+	return ret;
+}
+
+/*
+ * Returns the exposure in lines. Calculation is baded on Mira220 datasheet
+ * Section 9.2.
+ */
+static u32 mira220_calc_exposure(struct mira220 *mira220, u32 height, u32 vblank)
+{
+	u32 max_exposure = (height + vblank) -
+			   (MIRA220_GLOB_NUM_CLK_CYCLES / mira220->row_length);
+
+	return min(max_exposure, MIRA220_MAX_EXPOSURE);
+}
+
+static u32 mira220_calc_min_vblank(struct mira220 *mira220)
+{
+	return (MIRA220_GLOB_NUM_CLK_CYCLES / mira220->row_length)
+	       + MIRA220_MIN_VBLANK_MARGIN;
+}
+
+static int mira220_write_exposure_reg(struct mira220 *mira220, u32 exposure)
+{
+	struct i2c_client *const client = v4l2_get_subdevdata(&mira220->sd);
+	int ret;
+
+	ret = cci_write(mira220->regmap, MIRA220_EXP_TIME_REG, exposure, NULL);
+	if (ret) {
+		dev_err_ratelimited(&client->dev,
+				    "Error setting exposure time to %d",
+				    exposure);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* Get bayer order based on flip setting. */
+static u32 mira220_get_format_code(struct mira220 *mira220, u32 code)
+{
+	unsigned int i;
+
+	if (mira220_is_mono(mira220)) {
+		for (i = 0; i < ARRAY_SIZE(mira220_mbus_mono_formats); i++) {
+			if (mira220_mbus_mono_formats[i] == code)
+				return mira220_mbus_mono_formats[i];
+		}
+
+		return mira220_mbus_mono_formats[0];
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mira220_mbus_color_formats); i++) {
+		if (mira220_mbus_color_formats[i] == code)
+			break;
+	}
+	if (i >= ARRAY_SIZE(mira220_mbus_color_formats))
+		i = 0;
+
+	i = mira220_flip_format_index(mira220, i);
+
+	return mira220_mbus_color_formats[i];
+}
+
+static int mira220_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mira220 *mira220 =
+		container_of(ctrl->handler, struct mira220, ctrl_handler);
+	struct i2c_client *client = v4l2_get_subdevdata(&mira220->sd);
+	struct v4l2_mbus_framefmt *format;
+	struct v4l2_subdev_state *state;
+	int ret = 0;
+
+	state = v4l2_subdev_get_locked_active_state(&mira220->sd);
+	format = v4l2_subdev_state_get_format(state, 0);
+
+	if (ctrl->id == V4L2_CID_VBLANK) {
+		int exposure_max, exposure_def;
+
+		/* Update max exposure while meeting expected vblanking */
+		exposure_max = mira220_calc_exposure(mira220, format->height,
+						     ctrl->val);
+		exposure_def = min(exposure_max, MIRA220_DEFAULT_EXPOSURE);
+		ret = __v4l2_ctrl_modify_range(mira220->exposure,
+					       mira220->exposure->minimum,
+					       exposure_max,
+					       mira220->exposure->step,
+					       exposure_def);
+		if (ret)
+			return ret;
+	}
+
+	/* Update the format code to adjust it to the new flip state. */
+	if (ctrl->id == V4L2_CID_VFLIP || ctrl->id == V4L2_CID_HFLIP)
+		format->code = mira220_get_format_code(mira220, format->code);
+
+	if (!pm_runtime_get_if_in_use(&client->dev))
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		ret = mira220_write_exposure_reg(mira220, ctrl->val);
+		break;
+	case V4L2_CID_TEST_PATTERN:
+		ret = cci_write(mira220->regmap, MIRA220_REG_TEST_PATTERN,
+				mira220_test_pattern_val[ctrl->val], NULL);
+		break;
+	case V4L2_CID_HFLIP:
+		ret = cci_write(mira220->regmap, MIRA220_HFLIP_REG,
+				mira220->hflip->val, NULL);
+		break;
+	case V4L2_CID_VFLIP:
+		ret = cci_write(mira220->regmap, MIRA220_VFLIP_REG,
+				mira220->vflip->val, NULL);
+		break;
+	case V4L2_CID_VBLANK:
+		ret = cci_write(mira220->regmap, MIRA220_VBLANK_REG, ctrl->val,
+				NULL);
+		break;
+	default:
+		dev_info(&client->dev,
+			 "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id,
+			 ctrl->val);
+		ret = -EINVAL;
+		break;
+	}
+
+	pm_runtime_put_autosuspend(&client->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops mira220_ctrl_ops = {
+	.s_ctrl = mira220_set_ctrl,
+};
+
+static void mira220_update_pad_format(struct mira220 *mira220,
+				      struct v4l2_mbus_framefmt *fmt, u32 code)
+{
+	/* Bayer order varies with flips */
+	fmt->code = mira220_get_format_code(mira220, code);
+	/*
+	 * The mira220 sensor doesn't support binning/skipping but only
+	 * cropping to reduce the frame size so the correct API to configure
+	 * windowing is the .set_selection one, while format is fixed to
+	 * the full resolution 1600x1400 one.
+	 */
+	fmt->width = MIRA220_PIXEL_ARRAY_WIDTH;
+	fmt->height = MIRA220_PIXEL_ARRAY_HEIGHT;
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->colorspace = V4L2_COLORSPACE_RAW;
+	fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
+	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
+}
+
+static int mira220_set_pad_format(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state,
+				  struct v4l2_subdev_format *fmt)
+{
+	struct mira220 *mira220 = to_mira220(sd);
+	struct v4l2_rect *crop;
+	u32 min_vblank;
+	int ret;
+
+	mira220_update_pad_format(mira220, &fmt->format, fmt->format.code);
+	*v4l2_subdev_state_get_format(state, 0) = fmt->format;
+
+	crop = v4l2_subdev_state_get_crop(state, 0);
+	crop->width = fmt->format.width;
+	crop->height = fmt->format.height;
+	crop->left = MIRA220_PIXEL_ARRAY_LEFT;
+	crop->top = MIRA220_PIXEL_ARRAY_TOP;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	/* Update vblank based on new mode. */
+	min_vblank = mira220_calc_min_vblank(mira220);
+	ret = __v4l2_ctrl_modify_range(mira220->vblank, min_vblank,
+				       MIRA220_MAX_VBLANK, 1, min_vblank);
+	if (ret)
+		return ret;
+
+	return __v4l2_ctrl_s_ctrl(mira220->vblank, min_vblank);
+}
+
+static int mira220_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct mira220 *mira220 = to_mira220(sd);
+	bool mono = mira220_is_mono(mira220);
+	unsigned int num_formats;
+	unsigned int index;
+	const u32 *codes;
+
+	num_formats = mono ? ARRAY_SIZE(mira220_mbus_mono_formats) :
+			     (ARRAY_SIZE(mira220_mbus_color_formats) / 4);
+
+	if (code->index >= num_formats)
+		return -EINVAL;
+
+	index = mono ? code->index : (code->index * 4);
+	codes = mono ? mira220_mbus_mono_formats : mira220_mbus_color_formats;
+	code->code = mira220_get_format_code(mira220, codes[index]);
+
+	return 0;
+}
+
+static int mira220_enum_frame_size(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *state,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct mira220 *mira220 = to_mira220(sd);
+	u32 code;
+
+	if (fse->index)
+		return -EINVAL;
+
+	code = mira220_get_format_code(mira220, fse->code);
+	if (fse->code != code)
+		return -EINVAL;
+
+	fse->min_width = MIRA220_PIXEL_ARRAY_WIDTH;
+	fse->max_width = fse->min_width;
+	fse->min_height = MIRA220_PIXEL_ARRAY_HEIGHT;
+	fse->max_height = fse->min_height;
+
+	return 0;
+}
+
+static int mira220_init_state(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_state *state)
+{
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_TRY,
+		.pad = 0,
+		.format = {
+			.code = MEDIA_BUS_FMT_SGRBG12_1X12,
+			.width = MIRA220_PIXEL_ARRAY_WIDTH,
+			.height = MIRA220_PIXEL_ARRAY_HEIGHT,
+		},
+	};
+
+	mira220_set_pad_format(sd, state, &fmt);
+
+	return 0;
+}
+
+static int mira220_set_bus_config(struct mira220 *mira220)
+{
+	int ret = 0;
+
+	cci_write(mira220->regmap, MIRA220_MIPI_LANES_REG,
+		  mira220->lanes - 1, &ret);
+
+	cci_write(mira220->regmap, MIRA220_MIPI_CLK_MODE_REG,
+		  MIRA220_MIPI_CLK_CONTINUOUS, &ret);
+
+	return ret;
+}
+
+static int mira220_set_framefmt(struct mira220 *mira220,
+				struct v4l2_subdev_state *state)
+{
+	const struct v4l2_mbus_framefmt *format;
+	u32 top, left;
+	int ret = 0;
+
+	format = v4l2_subdev_state_get_format(state, 0);
+
+	/* Program the image format bit order, bit depth and CSI-2 data type */
+
+	ret = cci_write(mira220->regmap, MIRA220_BIT_ORDER_REG,
+			MIRA220_BIT_ORDER_NORMAL, NULL);
+	if (ret)
+		return ret;
+
+	switch (format->code) {
+	case MEDIA_BUS_FMT_Y8_1X8:
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+		cci_write(mira220->regmap, MIRA220_BIT_DEPTH_REG,
+			  MIRA220_BIT_DEPTH_8_BIT, &ret);
+		cci_write(mira220->regmap, MIRA220_CSI_DATA_TYPE_REG,
+			  MIRA220_CSI_DATA_TYPE_8_BIT, &ret);
+		break;
+	case MEDIA_BUS_FMT_Y10_1X10:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+		cci_write(mira220->regmap, MIRA220_BIT_DEPTH_REG,
+			  MIRA220_BIT_DEPTH_10_BIT, &ret);
+		cci_write(mira220->regmap, MIRA220_CSI_DATA_TYPE_REG,
+			  MIRA220_CSI_DATA_TYPE_10_BIT, &ret);
+
+		break;
+	case MEDIA_BUS_FMT_Y12_1X12:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+		cci_write(mira220->regmap, MIRA220_BIT_DEPTH_REG,
+			  MIRA220_BIT_DEPTH_12_BIT, &ret);
+		cci_write(mira220->regmap, MIRA220_CSI_DATA_TYPE_REG,
+			  MIRA220_CSI_DATA_TYPE_12_BIT, &ret);
+
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret)
+		return ret;
+
+	/* Program the sensor's row length. */
+	ret = cci_write(mira220->regmap, MIRA220_REG_ROW_LENGTH,
+			mira220->row_length, NULL);
+	if (ret)
+		return ret;
+
+	/*
+	 * Program the ROI area, centered in the sensor's pixel array.
+	 *
+	 * TODO: Use the crop rectangle sizes once the driver is ported to the
+	 * new RAW camera sensor model.
+	 */
+	top = (MIRA220_PIXEL_ARRAY_HEIGHT - format->height) / 2;
+	left = (MIRA220_PIXEL_ARRAY_WIDTH - format->width) / 2;
+
+	cci_write(mira220->regmap, MIRA220_VSTART_REG, top, &ret);
+	cci_write(mira220->regmap, MIRA220_HSTART_REG,
+		  left & MIRA220_HSTART_MASK, &ret);
+	cci_write(mira220->regmap, MIRA220_VSIZE_REG, format->height, &ret);
+	cci_write(mira220->regmap, MIRA220_HSIZE_REG,
+		  (format->width / 2) & MIRA220_HSIZE_MASK, &ret);
+	cci_write(mira220->regmap, MIRA220_MIPI_HSIZE_REG, format->width, &ret);
+
+	return ret;
+}
+
+static int mira220_get_selection(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *state,
+				 struct v4l2_subdev_selection *sel)
+{
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP:
+		sel->r = *v4l2_subdev_state_get_crop(state, 0);
+		return 0;
+
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+		sel->r.top = 0;
+		sel->r.left = 0;
+		sel->r.width = MIRA220_NATIVE_WIDTH;
+		sel->r.height = MIRA220_NATIVE_HEIGHT;
+		return 0;
+
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.top = MIRA220_PIXEL_ARRAY_TOP;
+		sel->r.left = MIRA220_PIXEL_ARRAY_LEFT;
+		sel->r.width = MIRA220_PIXEL_ARRAY_WIDTH;
+		sel->r.height = MIRA220_PIXEL_ARRAY_HEIGHT;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/* OTP power on */
+static int mira220_otp_power_on(struct mira220 *mira220)
+{
+	int ret = cci_write(mira220->regmap, MIRA220_OTP_CMD_REG,
+			    MIRA220_OTP_CMD_UP, NULL);
+	fsleep(100);
+
+	return ret;
+}
+
+/* OTP power off */
+static int mira220_otp_power_off(struct mira220 *mira220)
+{
+	return cci_write(mira220->regmap, MIRA220_OTP_CMD_REG,
+			 MIRA220_OTP_CMD_DOWN, NULL);
+}
+
+/* OTP power on */
+static int mira220_otp_read(struct mira220 *mira220, u8 addr, u8 offset,
+			    u8 *val, int *err)
+{
+	u64 readback;
+	int ret = 0;
+
+	if (err && *err)
+		return *err;
+
+	cci_write(mira220->regmap, CCI_REG8(0x0086), addr, &ret);
+	cci_write(mira220->regmap, CCI_REG8(0x0080), 0x02, &ret);
+	cci_read(mira220->regmap, CCI_REG8(0x0082 + offset), &readback, &ret);
+	if (ret)
+		goto out;
+
+	*val = readback & 0xFF;
+
+	return 0;
+
+out:
+	if (err)
+		*err = ret;
+	return ret;
+}
+
+/* Verify chip ID, module version, unique ID and variant */
+static int mira220_identify_module(struct mira220 *mira220)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mira220->sd);
+	u8 b0, b1, b2, b3, b4, b5, b6, b7;
+	u32 variant;
+	int ret;
+	u8 val;
+	u8 id;
+
+	ret = mira220_otp_power_on(mira220);
+	if (ret)
+		return ret;
+
+	/* Log module version checks */
+	mira220_otp_read(mira220, 0x0d, 0, &val, &ret);
+	mira220_otp_read(mira220, 0x1e, 0, &val, &ret);
+	if (ret)
+		goto err_power_off;
+
+	/* Check unique module hardware ID version */
+	ret = mira220_otp_read(mira220, 0x3a, 0, &id, NULL);
+	if (ret)
+		goto err_power_off;
+
+	if (id < 1 || id > 2) {
+		dev_err(&client->dev,
+			"Read OTP 0x3a, id must be 1 or 2, but got: 0x%02x\n", id);
+		ret = -EINVAL;
+		goto err_power_off;
+	}
+
+	/* Read Unique ID bytes sequentially using the correct 4-argument signature */
+	mira220_otp_read(mira220, 0x25, 0, &b0, &ret);
+	mira220_otp_read(mira220, 0x1e, 0, &b1, &ret);
+	mira220_otp_read(mira220, 0x1e, 1, &b2, &ret);
+	mira220_otp_read(mira220, 0x1e, 2, &b3, &ret);
+	mira220_otp_read(mira220, 0x1d, 0, &b4, &ret);
+	mira220_otp_read(mira220, 0x1d, 1, &b5, &ret);
+	mira220_otp_read(mira220, 0x1d, 2, &b6, &ret);
+	mira220_otp_read(mira220, 0x1d, 3, &b7, &ret);
+	if (ret)
+		goto err_power_off;
+
+	dev_dbg(&client->dev, "Unique ID: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		b7, b6, b5, b4, b3, b2, b1, b0);
+
+	mira220_otp_read(mira220, 0x3e, 0, &b0, &ret);
+	mira220_otp_read(mira220, 0x3e, 1, &b1, &ret);
+	mira220_otp_read(mira220, 0x3e, 2, &b2, &ret);
+	mira220_otp_read(mira220, 0x3e, 3, &b3, &ret);
+	if (ret)
+		goto err_power_off;
+
+	variant = b0 | b1 << 8 | b2 << 16 | b3 << 24;
+
+	switch (variant) {
+	case MIRA220_MONO_PLAIN_PF:
+	case MIRA220_MONO_PLAIN_NO_PF:
+	case MIRA220_MONO_AR_PF:
+		dev_dbg(&client->dev, "Mira220 MONO variant: %x\n", variant);
+		mira220->variant = MIRA220_VARIANT_MONO;
+		break;
+	case MIRA220_RGB_PLAIN_PF:
+	case MIRA220_RGB_PLAIN_NO_PF:
+	case MIRA220_RGB_AR_PF:
+		dev_dbg(&client->dev, "Mira220 RGB variant: %x\n", variant);
+		mira220->variant = MIRA220_VARIANT_RGB;
+		break;
+	default:
+		dev_info(&client->dev,
+			 "Unsupported mira220 variant %x; default to RGB\n",
+			 variant);
+		mira220->variant = MIRA220_VARIANT_RGB;
+		break;
+	}
+
+err_power_off:
+	mira220_otp_power_off(mira220);
+	return ret;
+}
+
+static int mira220_otp_restore(struct mira220 *mira220)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mira220->sd);
+	static const u16 reg_list[] = {
+		0x4015, 0x4016, 0x4017, 0x4018, 0x403B, 0x4040, 0x4041, 0x4042,
+		0x402a, 0x4029, 0x4009
+	};
+	u8 val;
+	int ret;
+
+	ret = mira220_otp_power_on(mira220);
+	if (ret)
+		return ret;
+
+	/* Write OTP to image sensor when programmed */
+	ret = mira220_otp_read(mira220, 0x1d, 0, &val, NULL);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read OTP programming status\n");
+		goto out;
+	}
+
+	if (val == 0xff) {
+		dev_info(&client->dev, "OTP not programmed, skipping calibration\n");
+		return mira220_otp_power_off(mira220);
+	}
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(reg_list); i++) {
+		ret = mira220_otp_read(mira220, i, 0, &val, NULL);
+		if (ret < 0) {
+			dev_err(&client->dev, "Failed to read OTP address %d\n", i);
+			goto out;
+		}
+		ret = cci_write(mira220->regmap, CCI_REG8(reg_list[i]), val, NULL);
+		if (ret < 0) {
+			dev_err(&client->dev,
+				"Failed to write register 0x%04x\n", reg_list[i]);
+			goto out;
+		}
+		dev_dbg(&client->dev, "OTP CALIBRATION: 0x%04x, val=0x%02x\n",
+			reg_list[i], val);
+	}
+
+	ret = mira220_otp_read(mira220, 0x0d, 0, &val, NULL);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read OTP address 0x0d\n");
+		goto out;
+	}
+
+	ret = cci_write(mira220->regmap, CCI_REG8(0x403e), val, NULL);
+	if (ret < 0)
+		dev_err(&client->dev, "Failed to write register 0x403e\n");
+
+out:
+	mira220_otp_power_off(mira220);
+	return ret;
+}
+
+static int mira220_enable_streams(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state, u32 pad,
+				  u64 streams_mask)
+{
+	struct mira220 *mira220 = to_mira220(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(&mira220->sd);
+	int ret;
+
+	ret = pm_runtime_resume_and_get(&client->dev);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Apply default values of current mode. Stop streaming before
+	 * uploading register sequence.
+	 */
+	ret = mira220_write_stop_streaming_regs(mira220);
+	if (ret)
+		goto err_rpm_put;
+
+	ret = cci_multi_reg_write(mira220->regmap, mira220_init_reg_list,
+				  ARRAY_SIZE(mira220_init_reg_list), NULL);
+	if (ret)
+		goto err_rpm_put;
+
+	ret = mira220_otp_restore(mira220);
+	if (ret)
+		goto err_rpm_put;
+
+	ret = mira220_set_bus_config(mira220);
+	if (ret)
+		goto err_rpm_put;
+
+	ret = mira220_set_framefmt(mira220, state);
+	if (ret)
+		goto err_rpm_put;
+
+	/* Apply customized values from user */
+	ret = __v4l2_ctrl_handler_setup(mira220->sd.ctrl_handler);
+	if (ret)
+		goto err_rpm_put;
+
+	ret = mira220_write_start_streaming_regs(mira220);
+	if (ret)
+		goto err_rpm_put;
+
+	/* vflip and hflip cannot change during streaming */
+	__v4l2_ctrl_grab(mira220->hflip, true);
+	__v4l2_ctrl_grab(mira220->vflip, true);
+
+	return 0;
+
+err_rpm_put:
+	pm_runtime_put_autosuspend(&client->dev);
+	return ret;
+}
+
+static int mira220_disable_streams(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *state, u32 pad,
+				   u64 streams_mask)
+{
+	struct mira220 *mira220 = to_mira220(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(&mira220->sd);
+
+	mira220_write_stop_streaming_regs(mira220);
+
+	__v4l2_ctrl_grab(mira220->hflip, false);
+	__v4l2_ctrl_grab(mira220->vflip, false);
+
+	pm_runtime_put_autosuspend(&client->dev);
+
+	return 0;
+}
+
+static int mira220_get_regulators(struct mira220 *mira220)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mira220->sd);
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(mira220_supplies); i++)
+		mira220->supplies[i].supply = mira220_supplies[i];
+
+	return devm_regulator_bulk_get(&client->dev,
+				       ARRAY_SIZE(mira220_supplies),
+				       mira220->supplies);
+}
+
+static const struct v4l2_subdev_video_ops mira220_video_ops = {
+	.s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops mira220_pad_ops = {
+	.enum_mbus_code = mira220_enum_mbus_code,
+	.get_fmt = v4l2_subdev_get_fmt,
+	.set_fmt = mira220_set_pad_format,
+	.get_selection = mira220_get_selection,
+	.enum_frame_size = mira220_enum_frame_size,
+	.enable_streams = mira220_enable_streams,
+	.disable_streams = mira220_disable_streams,
+};
+
+static const struct v4l2_subdev_ops mira220_subdev_ops = {
+	.video = &mira220_video_ops,
+	.pad = &mira220_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mira220_internal_ops = {
+	.init_state = mira220_init_state,
+};
+
+/* Initialize control handlers */
+static int mira220_init_controls(struct mira220 *mira220)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mira220->sd);
+	struct v4l2_ctrl_handler *ctrl_hdlr;
+	struct v4l2_fwnode_device_properties props;
+	struct v4l2_ctrl *ctrl;
+	u32 max_exposure = 0;
+	u32 min_vblank;
+	u32 hblank_val;
+	int ret;
+
+	ctrl_hdlr = &mira220->ctrl_handler;
+	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
+	if (ret)
+		return ret;
+
+	/* By default, PIXEL_RATE is read only */
+	v4l2_ctrl_new_std(ctrl_hdlr, &mira220_ctrl_ops, V4L2_CID_PIXEL_RATE,
+			  MIRA220_PIXEL_RATE, MIRA220_PIXEL_RATE, 1,
+			  MIRA220_PIXEL_RATE);
+
+	min_vblank = mira220_calc_min_vblank(mira220);
+	mira220->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &mira220_ctrl_ops,
+					    V4L2_CID_VBLANK,
+					    min_vblank, MIRA220_MAX_VBLANK, 1,
+					    min_vblank);
+
+	ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, NULL, V4L2_CID_LINK_FREQ,
+				      0, 0, &mira220_link_freqs[0]);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	/*
+	 * Scale hblank according to the number of enabled data lanes to match
+	 * row_length.
+	 */
+	hblank_val = MIRA220_LLP_1600x1400_304 * (2 / mira220->lanes)
+		   - MIRA220_PIXEL_ARRAY_WIDTH;
+	ctrl = v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_HBLANK, hblank_val,
+				 hblank_val, 1, hblank_val);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	/* Max exposure is determined by vblank + vsize and Tglob. */
+	max_exposure = mira220_calc_exposure(mira220,
+					     MIRA220_PIXEL_ARRAY_HEIGHT,
+					     min_vblank);
+
+	mira220->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &mira220_ctrl_ops,
+					      V4L2_CID_EXPOSURE,
+					      MIRA220_EXPOSURE_MIN,
+					      max_exposure, 1,
+					      MIRA220_DEFAULT_EXPOSURE);
+
+	v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_ANALOGUE_GAIN,
+			  MIRA220_ANALOG_GAIN_MIN, MIRA220_ANALOG_GAIN_MAX,
+			  MIRA220_ANALOG_GAIN_STEP,
+			  MIRA220_ANALOG_GAIN_DEFAULT);
+
+	mira220->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &mira220_ctrl_ops,
+					   V4L2_CID_HFLIP, 0, 1, 1, 0);
+	if (mira220->hflip)
+		mira220->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+	mira220->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &mira220_ctrl_ops,
+					   V4L2_CID_VFLIP, 0, 1, 1, 0);
+	if (mira220->vflip)
+		mira220->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &mira220_ctrl_ops,
+				     V4L2_CID_TEST_PATTERN,
+				     ARRAY_SIZE(mira220_test_pattern_menu) - 1,
+				     0, 0, mira220_test_pattern_menu);
+
+	if (ctrl_hdlr->error) {
+		ret = ctrl_hdlr->error;
+		goto error;
+	}
+
+	ret = v4l2_fwnode_device_parse(&client->dev, &props);
+	if (ret)
+		goto error;
+
+	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &mira220_ctrl_ops,
+					      &props);
+	if (ret)
+		goto error;
+
+	mira220->sd.ctrl_handler = ctrl_hdlr;
+
+	return 0;
+
+error:
+	v4l2_ctrl_handler_free(ctrl_hdlr);
+
+	return ret;
+}
+
+static int mira220_parse_endpoint(struct device *dev, struct mira220 *mira220)
+{
+	struct fwnode_handle *endpoint;
+	struct v4l2_fwnode_endpoint ep_cfg = {
+		.bus_type = V4L2_MBUS_CSI2_DPHY
+	};
+	int ret = 0;
+
+	endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
+	if (!endpoint) {
+		dev_err(dev, "Endpoint node not found\n");
+		return -EINVAL;
+	}
+
+	if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
+		ret = -EINVAL;
+		dev_err(dev, "Failed to parse endpoint\n");
+		goto error_out;
+	}
+
+	/* Non-continuous mode not implemented. */
+	if (ep_cfg.bus.mipi_csi2.flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK) {
+		dev_warn(dev, "clock non-continuous mode not supported\n");
+		ret = -EINVAL;
+		goto error_out;
+	}
+
+	if (ep_cfg.nr_of_link_frequencies > ARRAY_SIZE(mira220_link_freqs)) {
+		ret = -EINVAL;
+		dev_err(dev, "Unsupported number of link_frequencies: %u\n",
+			ep_cfg.nr_of_link_frequencies);
+		goto error_out;
+	}
+
+	if (ep_cfg.link_frequencies[0] != MIRA220_LINK_FREQ_750M) {
+		ret = -EINVAL;
+		dev_err(dev, "Unsupported link_frequency: %llu\n",
+			ep_cfg.link_frequencies[0]);
+		goto error_out;
+	}
+
+	/* Check the number of MIPI CSI2 data lanes */
+	if (ep_cfg.bus.mipi_csi2.num_data_lanes != 1 &&
+	    ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
+		ret = -EINVAL;
+		dev_err(dev, "%u data lanes are not supported\n",
+			ep_cfg.bus.mipi_csi2.num_data_lanes);
+		goto error_out;
+	}
+
+	mira220->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes;
+	mira220->row_length = MIRA220_ROW_LENGTH_MIN * (2 / mira220->lanes);
+
+error_out:
+	v4l2_fwnode_endpoint_free(&ep_cfg);
+	fwnode_handle_put(endpoint);
+
+	return ret;
+}
+
+static int mira220_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct mira220 *mira220;
+	int ret;
+
+	mira220 = devm_kzalloc(&client->dev, sizeof(*mira220), GFP_KERNEL);
+	if (!mira220)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&mira220->sd, client, &mira220_subdev_ops);
+	mira220->sd.internal_ops = &mira220_internal_ops;
+
+	ret = mira220_parse_endpoint(dev, mira220);
+	if (ret)
+		return ret;
+
+	mira220->regmap = devm_cci_regmap_init_i2c(client, 16);
+	if (IS_ERR(mira220->regmap))
+		return dev_err_probe(dev, PTR_ERR(mira220->regmap),
+				     "failed to initialize CCI\n");
+
+	/* Get system clock (xclk) */
+	mira220->xclk = devm_v4l2_sensor_clk_get(dev, NULL);
+	if (IS_ERR(mira220->xclk))
+		return dev_err_probe(dev, PTR_ERR(mira220->xclk),
+				     "failed to get xclk\n");
+
+	mira220->xclk_freq = clk_get_rate(mira220->xclk);
+	if (mira220->xclk_freq != MIRA220_SUPPORTED_XCLK_FREQ) {
+		dev_err(dev, "xclk frequency not supported: %d Hz\n",
+			mira220->xclk_freq);
+		return -EINVAL;
+	}
+
+	ret = mira220_get_regulators(mira220);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get regulators\n");
+
+	mira220->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						      GPIOD_OUT_HIGH);
+	if (IS_ERR(mira220->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(mira220->reset_gpio),
+				     "failed to get reset gpio\n");
+
+	ret = mira220_power_on(dev);
+	if (ret)
+		return ret;
+
+	/* Enable runtime PM and power on the device */
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	ret = mira220_identify_module(mira220);
+	if (ret)
+		goto error_power_off;
+
+	ret = mira220_init_controls(mira220);
+	if (ret)
+		goto error_power_off;
+
+	/* Initialize subdev */
+	mira220->sd.internal_ops = &mira220_internal_ops;
+	mira220->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	mira220->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+	/* Initialize source pads */
+	mira220->pad.flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&mira220->sd.entity, 1, &mira220->pad);
+	if (ret) {
+		dev_err_probe(dev, ret, "failed to init entity pads\n");
+		goto error_handler_free;
+	}
+
+	mira220->sd.state_lock = mira220->ctrl_handler.lock;
+	ret = v4l2_subdev_init_finalize(&mira220->sd);
+	if (ret < 0) {
+		dev_err_probe(dev, ret, "subdev init error\n");
+		goto error_media_entity;
+	}
+
+	ret = v4l2_async_register_subdev_sensor(&mira220->sd);
+	if (ret < 0) {
+		dev_err_probe(dev, ret,
+			      "failed to register sensor sub-device\n");
+		goto error_subdev_cleanup;
+	}
+
+	pm_runtime_idle(dev);
+	pm_runtime_set_autosuspend_delay(dev, 1000);
+	pm_runtime_use_autosuspend(dev);
+
+	return 0;
+
+error_subdev_cleanup:
+	v4l2_subdev_cleanup(&mira220->sd);
+error_media_entity:
+	media_entity_cleanup(&mira220->sd.entity);
+error_handler_free:
+	v4l2_ctrl_handler_free(mira220->sd.ctrl_handler);
+error_power_off:
+	pm_runtime_disable(dev);
+	mira220_power_off(dev);
+	pm_runtime_set_suspended(dev);
+	return ret;
+}
+
+static void mira220_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct mira220 *mira220 = to_mira220(sd);
+
+	v4l2_async_unregister_subdev(sd);
+	v4l2_subdev_cleanup(&mira220->sd);
+	media_entity_cleanup(&sd->entity);
+
+	v4l2_ctrl_handler_free(mira220->sd.ctrl_handler);
+
+	pm_runtime_disable(&client->dev);
+	if (!pm_runtime_status_suspended(&client->dev))
+		mira220_power_off(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct dev_pm_ops mira220_pm_ops = {
+	SET_RUNTIME_PM_OPS(mira220_power_off, mira220_power_on, NULL)
+};
+
+static const struct of_device_id mira220_dt_ids[] = {
+	{ .compatible = "ams,mira220" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mira220_dt_ids);
+
+static struct i2c_driver mira220_i2c_driver = {
+	.driver = {
+		.name = "mira220",
+		.of_match_table	= mira220_dt_ids,
+		.pm = pm_ptr(&mira220_pm_ops),
+	},
+	.probe = mira220_probe,
+	.remove = mira220_remove,
+};
+
+module_i2c_driver(mira220_i2c_driver);
+
+MODULE_AUTHOR("Philippe Baetens <philippe.baetens@ams-osram.com>");
+MODULE_DESCRIPTION("ams MIRA220 sensor driver");
+MODULE_LICENSE("GPL");

-- 
2.54.0


^ permalink raw reply related


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