Devicetree
 help / color / mirror / Atom feed
* [PATCH v6] dt-bindings: misc: convert lis302.txt to YAML
From: Jad Keskes @ 2026-06-19 13:14 UTC (permalink / raw)
  To: Eric Piel, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Jonathan Cameron, devicetree, linux-kernel, Jad Keskes

Replace the old lis302.txt with a YAML binding covering all four
compatibles (st,lis3lv02d, st,lis302dl-spi, st,lis331dlh,
st,lis33de) and their ~35 DT properties.

The old txt documented st,click-thresh-* and st,click-click-time-limit
but the code reads st,click-threshold-* and st,click-time-limit.
Keep the old names as deprecated so existing DTBs don't break.

Tested: dt_binding_check. dtbs_check against 7 omap/am335x DTBs
(am335x-evm, am335x-evmsk, am335x-pepper, am437x-sk-evm, omap3-n900,
omap3-n950, omap3-gta04a3) — no misc schema errors. Pre-existing
IIO schema errors on paired compatible nodes unchanged.

Signed-off-by: Jad Keskes <inasj268@gmail.com>
---

v6:
  - ACTUALLY commit the changes this time (git add before git commit --amend)
  - Remove redundant select block
  - Remove Vdd-supply/Vdd_IO-supply: false from SPI branch
  - Split allOf into two independent if/then branches
 .../devicetree/bindings/iio/accel/lis302.txt  | 119 ------
 .../bindings/misc/st,lis3lv02d.yaml           | 381 ++++++++++++++++++
 MAINTAINERS                                   |   1 +
 3 files changed, 382 insertions(+), 119 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/iio/accel/lis302.txt
 create mode 100644 Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml

diff --git a/Documentation/devicetree/bindings/iio/accel/lis302.txt b/Documentation/devicetree/bindings/iio/accel/lis302.txt
deleted file mode 100644
index 457539647f36..000000000000
--- a/Documentation/devicetree/bindings/iio/accel/lis302.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-LIS302 accelerometer devicetree bindings
-
-This device is matched via its bus drivers, and has a number of properties
-that apply in on the generic device (independent from the bus).
-
-
-Required properties for the SPI bindings:
- - compatible: 		should be set to "st,lis3lv02d-spi"
- - reg:			the chipselect index
- - spi-max-frequency:	maximal bus speed, should be set to 1000000 unless
-			constrained by external circuitry
- - interrupts:		the interrupt generated by the device
-
-Required properties for the I2C bindings:
- - compatible:		should be set to "st,lis3lv02d"
- - reg:			i2c slave address
- - Vdd-supply:		The input supply for Vdd
- - Vdd_IO-supply:	The input supply for Vdd_IO
-
-
-Optional properties for all bus drivers:
-
- - st,click-single-{x,y,z}:	if present, tells the device to issue an
-				interrupt on single click events on the
-				x/y/z axis.
- - st,click-double-{x,y,z}:	if present, tells the device to issue an
-				interrupt on double click events on the
-				x/y/z axis.
- - st,click-thresh-{x,y,z}:	set the x/y/z axis threshold
- - st,click-click-time-limit:	click time limit, from 0 to 127.5msec
-				with step of 0.5 msec
- - st,click-latency:		click latency, from 0 to 255 msec with
-				step of 1 msec.
- - st,click-window:		click window, from 0 to 255 msec with
-				step of 1 msec.
- - st,irq{1,2}-disable:		disable IRQ 1/2
- - st,irq{1,2}-ff-wu-1:		raise IRQ 1/2 on FF_WU_1 condition
- - st,irq{1,2}-ff-wu-2:		raise IRQ 1/2 on FF_WU_2 condition
- - st,irq{1,2}-data-ready:	raise IRQ 1/2 on data ready condition
- - st,irq{1,2}-click:		raise IRQ 1/2 on click condition
- - st,irq-open-drain:		consider IRQ lines open-drain
- - st,irq-active-low:		make IRQ lines active low
- - st,wu-duration-1:		duration register for Free-Fall/Wake-Up
-				interrupt 1
- - st,wu-duration-2:		duration register for Free-Fall/Wake-Up
-				interrupt 2
- - st,wakeup-{x,y,z}-{lo,hi}:	set wakeup condition on x/y/z axis for
-				upper/lower limit
- - st,wakeup-threshold:		set wakeup threshold
- - st,wakeup2-{x,y,z}-{lo,hi}:	set wakeup condition on x/y/z axis for
-				upper/lower limit for second wakeup
-				engine.
- - st,wakeup2-threshold:	set wakeup threshold for second wakeup
-				engine.
- - st,highpass-cutoff-hz=:	1, 2, 4 or 8 for 1Hz, 2Hz, 4Hz or 8Hz of
-				highpass cut-off frequency
- - st,hipass{1,2}-disable:	disable highpass 1/2.
- - st,default-rate=:		set the default rate
- - st,axis-{x,y,z}=:		set the axis to map to the three coordinates.
-				Negative values can be used for inverted axis.
- - st,{min,max}-limit-{x,y,z}	set the min/max limits for x/y/z axis
-				(used by self-test)
-
-
-Example for a SPI device node:
-
-	accelerometer@0 {
-		compatible = "st,lis302dl-spi";
-		reg = <0>;
-		spi-max-frequency = <1000000>;
-		interrupt-parent = <&gpio>;
-		interrupts = <104 0>;
-
-		st,click-single-x;
-		st,click-single-y;
-		st,click-single-z;
-		st,click-thresh-x = <10>;
-		st,click-thresh-y = <10>;
-		st,click-thresh-z = <10>;
-		st,irq1-click;
-		st,irq2-click;
-		st,wakeup-x-lo;
-		st,wakeup-x-hi;
-		st,wakeup-y-lo;
-		st,wakeup-y-hi;
-		st,wakeup-z-lo;
-		st,wakeup-z-hi;
-	};
-
-Example for a I2C device node:
-
-	lis331dlh: accelerometer@18 {
-		compatible = "st,lis331dlh", "st,lis3lv02d";
-		reg = <0x18>;
-		Vdd-supply = <&lis3_reg>;
-		Vdd_IO-supply = <&lis3_reg>;
-
-		st,click-single-x;
-		st,click-single-y;
-		st,click-single-z;
-		st,click-thresh-x = <10>;
-		st,click-thresh-y = <10>;
-		st,click-thresh-z = <10>;
-		st,irq1-click;
-		st,irq2-click;
-		st,wakeup-x-lo;
-		st,wakeup-x-hi;
-		st,wakeup-y-lo;
-		st,wakeup-y-hi;
-		st,wakeup-z-lo;
-		st,wakeup-z-hi;
-		st,min-limit-x = <120>;
-		st,min-limit-y = <120>;
-		st,min-limit-z = <140>;
-		st,max-limit-x = <550>;
-		st,max-limit-y = <550>;
-		st,max-limit-z = <750>;
-	};
-
diff --git a/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
new file mode 100644
index 000000000000..9c9280ec074e
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
@@ -0,0 +1,381 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/misc/st,lis3lv02d.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics LIS3LV02D and similar accelerometers (misc driver)
+
+maintainers:
+  - Eric Piel <eric.piel@tremplin-utc.net>
+
+description:
+  This binding describes the STMicroelectronics accelerometers supported by
+  the misc/lis3lv02d driver. This driver provides input (joystick) and
+  hardware monitoring support, in contrast to the IIO st-accel driver which
+  also supports some of these devices.
+  Refer to Documentation/devicetree/bindings/iio/st,st-sensors.yaml for the
+  IIO binding.
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - st,lis331dlh
+              - st,lis33de
+          - const: st,lis3lv02d
+      - const: st,lis331dlh
+      - const: st,lis3lv02d
+      - const: st,lis302dl-spi
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+
+  spi-max-frequency:
+    description: SPI bus frequency; should be set to 1000000 unless
+      constrained by external circuitry.
+    maximum: 1000000
+
+  Vdd-supply:
+    description: The input supply for Vdd.
+
+  Vdd_IO-supply:
+    description: The input supply for Vdd_IO.
+
+  st,click-single-x:
+    description: Issue an interrupt on single click events on the X axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-double-x:
+    description: Issue an interrupt on double click events on the X axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-single-y:
+    description: Issue an interrupt on single click events on the Y axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-double-y:
+    description: Issue an interrupt on double click events on the Y axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-single-z:
+    description: Issue an interrupt on single click events on the Z axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-double-z:
+    description: Issue an interrupt on double click events on the Z axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-thresh-x:
+    description: X axis click threshold (deprecated spelling, use st,click-threshold-x).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  st,click-thresh-y:
+    description: Y axis click threshold (deprecated spelling, use st,click-threshold-y).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  st,click-thresh-z:
+    description: Z axis click threshold (deprecated spelling, use st,click-threshold-z).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  st,click-threshold-x:
+    description: X axis click threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,click-threshold-y:
+    description: Y axis click threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,click-threshold-z:
+    description: Z axis click threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,click-click-time-limit:
+    description: Click time limit (deprecated spelling, use st,click-time-limit).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+    deprecated: true
+
+  st,click-time-limit:
+    description: Click time limit, from 0 to 127.5 msec with step of 0.5 msec.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,click-latency:
+    description: Click latency, from 0 to 255 msec with step of 1 msec.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,click-window:
+    description: Click window, from 0 to 255 msec with step of 1 msec.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,irq1-disable:
+    description: Disable IRQ 1.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-ff-wu-1:
+    description: Raise IRQ 1 on FF_WU_1 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-ff-wu-2:
+    description: Raise IRQ 1 on FF_WU_2 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-data-ready:
+    description: Raise IRQ 1 on data ready condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-click:
+    description: Raise IRQ 1 on click condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-disable:
+    description: Disable IRQ 2.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-ff-wu-1:
+    description: Raise IRQ 2 on FF_WU_1 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-ff-wu-2:
+    description: Raise IRQ 2 on FF_WU_2 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-data-ready:
+    description: Raise IRQ 2 on data ready condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-click:
+    description: Raise IRQ 2 on click condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq-open-drain:
+    description: Consider IRQ lines open-drain.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq-active-low:
+    description: Make IRQ lines active low.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wu-duration-1:
+    description: Duration register for Free-Fall/Wake-Up interrupt 1.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,wu-duration-2:
+    description: Duration register for Free-Fall/Wake-Up interrupt 2.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,wakeup-x-lo:
+    description: Set wakeup condition on X axis for lower limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-x-hi:
+    description: Set wakeup condition on X axis for upper limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-y-lo:
+    description: Set wakeup condition on Y axis for lower limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-y-hi:
+    description: Set wakeup condition on Y axis for upper limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-z-lo:
+    description: Set wakeup condition on Z axis for lower limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-z-hi:
+    description: Set wakeup condition on Z axis for upper limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-threshold:
+    description: Set wakeup threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,wakeup2-x-lo:
+    description: Set wakeup condition on X axis for lower limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-x-hi:
+    description: Set wakeup condition on X axis for upper limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-y-lo:
+    description: Set wakeup condition on Y axis for lower limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-y-hi:
+    description: Set wakeup condition on Y axis for upper limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-z-lo:
+    description: Set wakeup condition on Z axis for lower limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-z-hi:
+    description: Set wakeup condition on Z axis for upper limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-threshold:
+    description: Set wakeup threshold for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,highpass-cutoff-hz:
+    description: Highpass cut-off frequency. Valid values are 1, 2, 4 or 8.
+    enum: [1, 2, 4, 8]
+
+  st,hipass1-disable:
+    description: Disable highpass filter 1.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,hipass2-disable:
+    description: Disable highpass filter 2.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,default-rate:
+    description: Set the default output data rate.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,axis-x:
+    description: Set the X axis mapping. Negative values can be used for inverted axis.
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,axis-y:
+    description: Set the Y axis mapping. Negative values can be used for inverted axis.
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,axis-z:
+    description: Set the Z axis mapping. Negative values can be used for inverted axis.
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,min-limit-x:
+    description: Minimum limit for X axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,min-limit-y:
+    description: Minimum limit for Y axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,min-limit-z:
+    description: Minimum limit for Z axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,max-limit-x:
+    description: Maximum limit for X axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,max-limit-y:
+    description: Maximum limit for Y axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,max-limit-z:
+    description: Maximum limit for Z axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: st,lis302dl-spi
+    then:
+      required:
+        - spi-max-frequency
+        - interrupts
+  - if:
+      properties:
+        compatible:
+          not:
+            contains:
+              const: st,lis302dl-spi
+    then:
+      required:
+        - Vdd-supply
+        - Vdd_IO-supply
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        accelerometer@18 {
+            compatible = "st,lis331dlh", "st,lis3lv02d";
+            reg = <0x18>;
+            Vdd-supply = <&lis3_reg>;
+            Vdd_IO-supply = <&lis3_reg>;
+            interrupt-parent = <&gpio2>;
+            interrupts = <18 0>;
+
+            st,click-single-x;
+            st,click-single-y;
+            st,click-single-z;
+            st,click-threshold-x = <10>;
+            st,click-threshold-y = <10>;
+            st,click-threshold-z = <10>;
+            st,irq1-click;
+            st,irq2-click;
+            st,wakeup-x-lo;
+            st,wakeup-x-hi;
+            st,wakeup-y-lo;
+            st,wakeup-y-hi;
+            st,wakeup-z-lo;
+            st,wakeup-z-hi;
+            st,min-limit-x = <120>;
+            st,min-limit-y = <120>;
+            st,min-limit-z = <140>;
+            st,max-limit-x = <550>;
+            st,max-limit-y = <550>;
+            st,max-limit-z = <750>;
+        };
+    };
+  - |
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        accelerometer@0 {
+            compatible = "st,lis302dl-spi";
+            reg = <0>;
+            spi-max-frequency = <1000000>;
+            interrupt-parent = <&gpio>;
+            interrupts = <104 0>;
+
+            st,click-single-x;
+            st,click-single-y;
+            st,click-single-z;
+            st,click-threshold-x = <10>;
+            st,click-threshold-y = <10>;
+            st,click-threshold-z = <10>;
+            st,irq1-click;
+            st,irq2-click;
+            st,wakeup-x-lo;
+            st,wakeup-x-hi;
+            st,wakeup-y-lo;
+            st,wakeup-y-hi;
+            st,wakeup-z-lo;
+            st,wakeup-z-hi;
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ec290e38b44..4cffabbabf0e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14858,6 +14858,7 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/
 LIS3LV02D ACCELEROMETER DRIVER
 M:	Eric Piel <eric.piel@tremplin-utc.net>
 S:	Maintained
+F:	Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
 F:	Documentation/misc-devices/lis3lv02d.rst
 F:	drivers/misc/lis3lv02d/
 F:	drivers/platform/x86/hp/hp_accel.c
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH 0/6] arm64: dts: qcom: sc8280xp: set GPI DMA channels according to DSDT
From: Konrad Dybcio @ 2026-06-19 13:11 UTC (permalink / raw)
  To: Icenowy Zheng, Pengyu Luo
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <9434068bd7e69c92fed5382bff2479d4fc0e4bf4.camel@iscas.ac.cn>

On 6/19/26 2:50 PM, Icenowy Zheng wrote:
> 在 2026-06-19五的 14:27 +0200,Konrad Dybcio写道:
>> On 6/18/26 12:34 PM, Icenowy Zheng wrote:
>>> 在 2026-06-18四的 11:05 +0200,Konrad Dybcio写道:
>>>> On 6/18/26 11:04 AM, Konrad Dybcio wrote:
>>>>> On 6/9/26 5:54 PM, Icenowy Zheng wrote:
>>>>>> 在 2026-06-09二的 14:23 +0200,Konrad Dybcio写道:
>>>>>>> On 6/7/26 10:49 AM, Icenowy Zheng wrote:
>>>>>>>> 在 2026-06-06六的 21:51 +0800,Pengyu Luo写道:
>>>>>>>>> On Sat, Jun 6, 2026 at 9:21 PM Icenowy Zheng
>>>>>>>>> <zhengxingda@iscas.ac.cn> wrote:
>>>>>>>>>>
>>>>>>>>>> 在 2026-06-06六的 17:46 +0800,Pengyu Luo写道:
>>>>>>>>>>> On 2026-06-06 17:28:35+08:00, Icenowy Zheng wrote:
>>>>>>>>>>>> 在 2026-06-06六的 17:22 +0800,Pengyu Luo写道:
>>>>>>>>>>>>
>>>>>>>>>>>>> On 2026-06-02 21:21:27+08:00, Icenowy Zheng
>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> The magnetic keyboard (USB HID) can't be
>>>>>>>>>>>>> connected
>>>>>>>>>>>>> somehow,
>>>>>>>>>>>>> others
>>>>>>>>>>>>> are
>>>>>>>>>>>>> fine, such as the spi touchscreen (not upstream
>>>>>>>>>>>>> yet),
>>>>>>>>>>>>> which
>>>>>>>>>>>>> utilizes
>>>>>>>>>>>>> DMA definitely. My config is here
>>>>>>>>>>>>> https://pastebin.com/SdjuyJYk
>>>>>>>>>>>>
>>>>>>>>>>>> Is this a defconfig?
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Yes.
>>>>>>>>>>>
>>>>>>>>>>>> BTW it seems that CONFIG_ASYNC_TX_DMA needs to be
>>>>>>>>>>>> selected
>>>>>>>>>>>> too
>>>>>>>>>>>> for
>>>>>>>>>>>> exhibiting the problem (because there should be
>>>>>>>>>>>> "public"
>>>>>>>>>>>> GPI
>>>>>>>>>>>> DMA
>>>>>>>>>>>> consumers to trigger the stuck/reset).
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Is this still necessary? I checked the fedora
>>>>>>>>>>> discussion and
>>>>>>>>>>> your
>>>>>>>>>>> GPI
>>>>>>>>>>> DMA fix. And GPI DMA is only for the QUP-supported
>>>>>>>>>>> peripherals as
>>>>>>>>>>> the
>>>>>>>>>>> binding mentioned,
>>>>>>>>>>> devicetree/bindings/dma/qcom,gpi.yaml
>>>>>>>>>>
>>>>>>>>>> The devicetree without this fix seems to be still
>>>>>>>>>> incorrect,
>>>>>>>>>> because
>>>>>>>>>> with the device tree fix even if the GPI DMA driver
>>>>>>>>>> misbehaves
>>>>>>>>>> the
>>>>>>>>>> system won't be stuck (although it will iterate all
>>>>>>>>>> GPI
>>>>>>>>>> channels
>>>>>>>>>> and
>>>>>>>>>> then fail to function at all).
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Back to the start. You said some GPI interfaces aren't
>>>>>>>>> available
>>>>>>>>> to
>>>>>>>>> HLOS, your mask is 0xb(0b1011), so I use 0x4(0b100) did
>>>>>>>>> a
>>>>>>>>> quick
>>>>>>>>> test,
>>>>>>>>> and spi6 consumed it, no stuck or reset. Could you give
>>>>>>>>> me
>>>>>>>>> a
>>>>>>>>> unavailable channel?
>>>>>>>>
>>>>>>>> I think channel 0b10000 of gpi_dma2 could be an example?
>>>>>>>>
>>>>>>>> It seems that 4 channels are tried on gpi_dma2 before
>>>>>>>> hang on
>>>>>>>> my
>>>>>>>> gaokun3, but as gaokun3 has no known serial access, it's
>>>>>>>> possible
>>>>>>>> that
>>>>>>>> 0b100000 or 0b1000 is problematic.
>>>>>>>>
>>>>>>>> (The reason gpi_dma2 is checked first is because it's the
>>>>>>>> GPI
>>>>>>>> DMA
>>>>>>>> controller with the smallest address)
>>>>>>>>
>>>>>>>> BTW I just took the values from Windows DSDT, which is
>>>>>>>> quite
>>>>>>>> conservative.
>>>>>>>
>>>>>>> So, with DMA_PRIVATE set, is this series made redundant?
>>>>>>
>>>>>> I assume technically the trustzone is still protecting some
>>>>>> channels,
>>>>>> although the system stuck issue is fixed.
>>>>>>
>>>>>> This series should still be relevant, although not so
>>>>>> emergent.
>>>>>
>>>>> So now we're down to the case of the TZ reserving some of the
>>>>> GPI
>>>>> channels (presumably for locked down/TZ-driven QUPs) crashing
>>>>> the
>>>>> device on access, is that right?
>>>>
>>>> i.e. now, is requesting these channels through (wrongfully)
>>>> enabling
>>>> the devices in DT the only remaining concern?
>>>
>>> Yes, I think so; although I think few devices will use GPI on these
>>> devices (usually only one or two SPI controllers according to the
>>> DSDTs).
>>
>> IIRC there's a configuration table that lets OEMs decide which ones
>> should fall under the secure umbrella (although most never seem to
>> change the defaults).
> 
> Ah then what's the default value?
> 
> Radxa Dragon Q8B seems to have GPII0-5 enabled for all GPI controllers

This matches what I can find in the default config

Konrad

^ permalink raw reply

* Re: [PATCH v5] dt-bindings: misc: convert lis302.txt to YAML
From: sashiko-bot @ 2026-06-19 13:08 UTC (permalink / raw)
  To: Jad Keskes; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260619125902.893742-1-inasj268@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The YAML schema incorrectly forbids the `Vdd-supply` and `Vdd_IO-supply` properties for the SPI variant and contains a redundant `select` block.
--

commit 124e32c58b0e195eb97adbc2880712f6df5eb1b2
Author: Jad Keskes <inasj268@gmail.com>

dt-bindings: misc: convert lis302.txt to YAML

This commit converts the old lis302.txt dt-binding to YAML format,
supporting the st,lis3lv02d, st,lis302dl-spi, st,lis331dlh, and
st,lis33de compatibles. It retains old property names as deprecated
to maintain backward compatibility with existing device trees.

> diff --git a/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
> new file mode 100644
> index 0000000000000..c73371b754a1e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml

[ ... ]

> +description:
> +  This binding describes the STMicroelectronics accelerometers supported by
> +  the misc/lis3lv02d driver. This driver provides input (joystick) and
> +  hardware monitoring support, in contrast to the IIO st-accel driver which
> +  also supports some of these devices.
> +  Refer to Documentation/devicetree/bindings/iio/st,st-sensors.yaml for the
> +  IIO binding.
> +
> +select:
> +  anyOf:
> +    - properties:
> +        compatible:
> +          contains:
> +            const: st,lis302dl-spi
> +    - properties:
> +        compatible:
> +          contains:
> +            const: st,lis331dlh
> +    - properties:
> +        compatible:
> +          contains:
> +            const: st,lis33de
> +    - properties:
> +        compatible:
> +          contains:
> +            const: st,lis3lv02d
> +  required:
> +    - compatible
> +
> +properties:

[Severity: Medium]
Is this explicit select block necessary? The dt-schema tooling
automatically selects bindings based on the top-level compatible
property definition, making this manual select block redundant.

[ ... ]

> +allOf:
> +  - if:
> +      properties:
> +        compatible:
> +          not:
> +            contains:
> +              const: st,lis302dl-spi
> +    then:
> +      required:
> +        - Vdd-supply
> +        - Vdd_IO-supply
> +    else:
> +      properties:
> +        Vdd-supply: false
> +        Vdd_IO-supply: false

[Severity: Medium]
Does setting these properties to false incorrectly enforce a hardware
abstraction violation? The physical chip requires power to operate
regardless of whether it uses the SPI bus or I2C. Device tree bindings
should describe the hardware, not the current limitations of the driver code.

> +      required:
> +        - spi-max-frequency
> +        - interrupts
> +
> +required:

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

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: thermal: Add Qualcomm MBG thermal monitor support
From: Krzysztof Kozlowski @ 2026-06-19 13:06 UTC (permalink / raw)
  To: Sachin Gupta
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
	Stephen Boyd, Jishnu Prakash, Kamal Wadhwa, Amit Kucheria,
	Thara Gopinath, linux-arm-msm, devicetree, linux-kernel, linux-pm,
	Satya Priya Kakitapalli, Ajit Pandey, Imran Shaik, Taniya Das,
	Jagadeesh Kona
In-Reply-To: <4d643a18-a044-4350-b7f9-2c61f50cb792@oss.qualcomm.com>

On 19/06/2026 08:44, Sachin Gupta wrote:
>>> index 000000000000..a0ecc9f35cf6
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-mbg-tm.yaml
>>
>> Filename must match compatible.
>>
> 
> Thanks for the review. I can rename this to match the compatible naming, 
> but wanted your preference on scope:
> 
> Should I use a generic naming scheme (qcom,spmi-mbg-tm.yaml with 
> matching compatible), or make it PMIC-specific (qcom,pm8775-mbg-tm.yaml).

The second one, please.



Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH v3 1/5] dt-bindings: iio: adc: Add ltc2378
From: Marcelo Schmitt @ 2026-06-19 13:07 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Marcelo Schmitt, linux-iio, devicetree, linux-kernel, jic23,
	nuno.sa, Michael.Hennerich, dlechner, andy, robh, krzk+dt,
	conor+dt, pop.ioan-daniel
In-Reply-To: <20260617-oat-handclasp-ddd3135c5b84@spud>

On 06/17, Conor Dooley wrote:
> On Wed, Jun 17, 2026 at 02:14:32PM -0300, Marcelo Schmitt wrote:
> > On 06/17, Conor Dooley wrote:
> > > On Tue, Jun 16, 2026 at 11:03:11PM -0300, Marcelo Schmitt wrote:
> > > > Document how to describe LTC2378-20 and similar ADCs in device tree.
> > > > 
> > > > Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> > > > ---
> > > > Change log v2 -> v3:
> > > > - Re-added device tree fallback compatibles for LTC2378 chips, now with options
> > > >   to provide a single compatible string or a pair of single compatible string
> > > >   plus a fallback string to a slower sample rate spec in case a driver for the
> > > >   specific part is not found.
> > > > 
> > > >  .../bindings/iio/adc/adi,ltc2378.yaml         | 160 ++++++++++++++++++
> > > >  MAINTAINERS                                   |   7 +
> > > >  2 files changed, 167 insertions(+)
> > > >  create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml
> > > > new file mode 100644
> > > > index 000000000000..7d30a2cade8f
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml
> > > > @@ -0,0 +1,160 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/iio/adc/adi,ltc2378.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: Analog Devices LTC2378 and similar Analog to Digital Converters
> > > > +
> > > > +maintainers:
> > > > +  - Marcelo Schmitt <marcelo.schmitt@analog.com>
> > > > +
> > > > +description: |
> > > > +  Analog Devices LTC2378 series of ADCs.
> > > > +  Specifications can be found at:
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/233818fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/236416fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/236418f.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/236716fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/236718f.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/236816f.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/236818f.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/236918fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237016fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237616fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237618fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237620fb.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237716fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237718fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237720fb.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237816fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237818fa.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237820fb.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/237918fb.pdf
> > > > +    https://www.analog.com/media/en/technical-documentation/data-sheets/238016fb.pdf
> > > > +
> > > > +$ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    oneOf:
> > > > +      # Single compatible string match.
> > > > +      - enum:
> > > > +          - adi,ltc2338-18
> > > > +          - adi,ltc2364-16
> > > > +          - adi,ltc2364-18
> > > > +          - adi,ltc2367-16
> > > > +          - adi,ltc2367-18
> > > > +          - adi,ltc2368-16
> > > > +          - adi,ltc2368-18
> > > > +          - adi,ltc2369-18
> > > > +          - adi,ltc2370-16
> > > > +          - adi,ltc2376-16
> > > > +          - adi,ltc2376-18
> > > > +          - adi,ltc2376-20
> > > > +          - adi,ltc2377-16
> > > > +          - adi,ltc2377-18
> > > > +          - adi,ltc2377-20
> > > > +          - adi,ltc2378-16
> > > > +          - adi,ltc2378-18
> > > > +          - adi,ltc2378-20
> > > > +          - adi,ltc2379-18
> > > > +          - adi,ltc2380-16
> > > > +
> > > > +      # Low sample rate fallback for 16-bit unipolar sensors.
> > > > +      - items:
> > > > +          - enum:
> > > > +              - adi,ltc2370-16 # 2 MSPS
> > > > +              - adi,ltc2368-16 # 1 MSPS
> > > > +              - adi,ltc2367-16 # 500 kSPS
> > > > +          - const: adi,ltc2364-16 # fallback (250 kSPS)
> > > 
...
> > > What actually is the impact of the sample rate on the programming model?
> > If the user tries to set a sample rate beyond the maximum supported, software
> > can throw an error to indicate that.
> 
> I think you have misunderstood this. I was asking how the driver
> interacts with the hardware. Do all devices come out of reset with the
> minimum sampling rate? Or a per-device default rate? Do the faster
> devices support all slower rates? If they do, do the registers have the
> same meaning and the same value sets 2370-16 device to 1 MSPS as
> 2368-16.

Ah, the sampling rate is indirectly dictated both by how fast the CNV pin is
toggled and how fast SPI transfers run. Each rising edge of CNV starts a new
ADC conversion. Software may take spi-max-frequency as default but it will also
need to set a pace for CNV, and there is no default for that. The CNV pin may
also toggled on demand (e.g. single-shot read) and so I'd say all devices
support all slower sample rates. What software ought to do is orchestrate CNV
and SPI transfers to meet the timing requirements. No configuration registers
to be set.

> > 
> > With the code being proposed in this patch set, there is no benefit in matching
> > the ltc2364-16 fallback if there is a faster ltc2370-16 device connected because
> > device driver supports that. Though, other operating systems and/or platforms
> > might not support all device variants and so the fallback might be useful.
> > 
> > > +static const struct ltc2378_chip_info ltc2370_16_chip_info = {
> > > +	.name = "ltc2370-16",
> > > +	.resolution = 16,
> > In a later patch ...
> > +	.max_sample_rate_hz = 2 * HZ_PER_MHZ,
> > +	.tconv_ns = 322,
> > > +	.bipolar = false,
> > > +};
> > > 
> > > +static const struct ltc2378_chip_info ltc2368_16_chip_info = {
> > > +	.name = "ltc2368-16",
> > > +	.resolution = 16,
> > +	.max_sample_rate_hz = HZ_PER_MHZ,
> > +	.tconv_ns = 527
> > > +	.bipolar = false,
> > > +};
> > > 
> > > +static const struct ltc2378_chip_info ltc2367_16_chip_info = {
> > > +	.name = "ltc2367-16",
> > > +	.resolution = 16,
> > +	.max_sample_rate_hz = 500 * HZ_PER_KHZ,
> > +	.tconv_ns = 1500,
> > > +	.bipolar = false,
> > > +};
> > > 
> > > +static const struct ltc2378_chip_info ltc2364_16_chip_info = {
> > > +	.name = "ltc2364-16",
> > > +	.resolution = 16,
> > +	.max_sample_rate_hz = 250 * HZ_PER_KHZ,
> > +	.tconv_ns = 3000,
> > > +	.bipolar = false,
> > > +};
> > > 
> > ...
> > > > +      # Low sample rate fallback for 20-bit bipolar sensors.
> > > > +      - items:
> > > > +          - enum:
> > > > +              - adi,ltc2378-20 # 1 MSPS
> > > > +              - adi,ltc2377-20 # 500 kSPS
> > > > +          - const: adi,ltc2376-20 # fallback (250 kSPS)
> > > 
> > > I didn't check these, but I assume they are the same.
> > 
> > Yes, except for small variations on input (unipolar/bipolar) and precision bits,
> > these devices are pretty much equal.
> 
> What I meant here was that 2378-20, 2377-20 and 2376-20 would follow the
> same pattern of having identical match data (pre patch 4).

Yes, devices that have same input type and precision bits have the same match
data configuration (except for name). That's because the initial support patch
only supports single-shot data read.

^ permalink raw reply

* Re: [PATCH v2 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add Sony IMX576 front camera support
From: sashiko-bot @ 2026-06-19 13:05 UTC (permalink / raw)
  To: Himanshu Bhavani; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260619125439.55311-4-himanshu.bhavani@siliconsignals.io>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The patch references an undeclared `camss` label in the device tree, which will cause a fatal Device Tree Compiler (DTC) error.
--

commit e341e6cf8035ff51f6898a2a0611940c2e725195
Author: Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>

arm64: dts: qcom: sm7225-fairphone-fp4: Add Sony IMX576 front camera support

This commit adds device tree support for the Sony IMX576 front camera
sensor. It connects the sensor to the CAMSS node via CSIPHY3.

> diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
> index 3964aae47fd4e..1cacd17e7c476 100644
> --- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
> +++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts

[ ... ]

> @@ -547,6 +548,29 @@ vreg_bob: bob {
>  	};
>  };
>  
> +&camss {

[Severity: Low]
Is the &camss label defined in the base device tree for this platform?

Looking at the base SoC device trees (sm6350.dtsi and sm7225.dtsi), it
doesn't appear that a camss node label has been defined yet. Extending it
here might cause a Device Tree Compiler error due to an undefined node.

Could the camss node and its label be missing from the base dtsi?

> +	vdd-csiphy0-0p9-supply = <&vreg_l18a>;
> +	vdd-csiphy0-1p25-supply = <&vreg_l22a>;
> +	vdd-csiphy1-0p9-supply = <&vreg_l18a>;

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260619125439.55311-1-himanshu.bhavani@siliconsignals.io?part=3

^ permalink raw reply

* Re: [PATCH v2 2/3] media: i2c: add imx576 image sensor driver
From: sashiko-bot @ 2026-06-19 13:04 UTC (permalink / raw)
  To: Himanshu Bhavani; +Cc: robh, devicetree, conor+dt
In-Reply-To: <20260619125439.55311-3-himanshu.bhavani@siliconsignals.io>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Calculation of pixel_rate overflows on 32-bit platforms, causing wildly incorrect pixel rate control.
- [High] Sensor is permanently left in register HOLD mode if an intermediate control write fails.
- [Low] Unconditional assignment of dev_pm_ops produces dead code when CONFIG_PM is disabled.
--

commit 511969ab2e888f822293c83a79b2a96d1becf3a2
Author: Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>

media: i2c: add imx576 image sensor driver

Add a v4l2 subdevice driver for the Sony imx576 sensor.
The Sony IMX576 image sensor with an active array size of 5760 x 4312.
The following features are supported: manual exposure and gain control,
vblank/hblank control, and 2880 x 2156 30fps (SRGGB10) resolution.

> diff --git a/drivers/media/i2c/imx576.c b/drivers/media/i2c/imx576.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/media/i2c/imx576.c
[ ... ]
> +static int imx576_set_ctrl(struct v4l2_ctrl *ctrl)
> +{
[ ... ]
> +	switch (ctrl->id) {
> +	case V4L2_CID_VBLANK: {
> +		u64 vmax = fmt->height + ctrl->val;
> +
> +		cci_write(imx576->regmap, IMX576_REG_VTS, vmax, &ret);
> +		break;
> +	}
> +	case V4L2_CID_EXPOSURE:
> +		cci_write(imx576->regmap, IMX576_REG_EXPOSURE, ctrl->val, &ret);
> +		break;
> +	case V4L2_CID_ANALOGUE_GAIN:
> +		cci_write(imx576->regmap, IMX576_REG_ANALOG_GAIN,
> +			  ctrl->val, &ret);
> +		break;
> +	default:
> +		dev_err(imx576->dev, "Invalid control %d\n", ctrl->id);
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	cci_write(imx576->regmap, IMX576_REG_HOLD, 0, &ret);

[Severity: High]
Does this leave the sensor permanently in register HOLD mode if an
intermediate control write fails?

Looking at cci_write(), it immediately returns without performing any I2C
write if the error pointer (ret) already contains a non-zero error code. If an
intermediate control write in the switch block fails, ret will hold an error
code like -EIO.

The final cci_write() will see this error and instantly skip clearing the
HOLD register, leaving the camera hardware in a stuck state where no further
register updates take effect.

[ ... ]
> +static int imx576_init_controls(struct imx576 *imx576)
> +{
[ ... ]
> +	imx576->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx576_ctrl_ops,
> +					   V4L2_CID_VBLANK, vblank_def,
> +					   IMX576_VBLANK_MAX, 1,
> +					   vblank_def);
> +
> +	/* pixel_rate = link_frequency * 2 * nr_of_lanes / bits_per_sample */
> +	pixel_rate = div_u64(IMX576_LINK_FREQ_600MHZ * 2 * IMX576_NUM_DATA_LANES, 10);

[Severity: High]
Does this calculation overflow on 32-bit platforms before the result gets
passed to div_u64()?

IMX576_LINK_FREQ_600MHZ is defined as (600 * HZ_PER_MHZ), and since
HZ_PER_MHZ is an unsigned long, the entire multiplication is evaluated as a
32-bit unsigned long on 32-bit architectures.

The result of 600,000,000 * 8 is 4,800,000,000, which exceeds the maximum
32-bit unsigned integer value and overflows to 505,032,704 before div_u64()
implicitly casts it to u64.

Could this be explicitly cast to u64 before the multiplication to ensure the
correct pixel rate is calculated?

[ ... ]
> +static struct i2c_driver imx576_driver = {
> +	.driver = {
> +		.name = "imx576",
> +		.pm = &imx576_pm_ops,

[Severity: Low]
Will this unconditional assignment produce dead code when CONFIG_PM is
disabled?

Assigning the dev_pm_ops structure directly prevents the compiler from
eliminating the imx576_pm_ops structure when power management support
is disabled.

Should this be wrapped with pm_ptr() to allow the compiler to discard the
unused structure?

> +		.of_match_table = imx576_of_match,
> +	},
> +	.probe = imx576_probe,
> +	.remove = imx576_remove,
> +};

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260619125439.55311-1-himanshu.bhavani@siliconsignals.io?part=2

^ permalink raw reply

* Re: [PATCH v2 1/3] dt-bindings: media: i2c: Add imx576 sensor
From: sashiko-bot @ 2026-06-19 13:04 UTC (permalink / raw)
  To: Himanshu Bhavani; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260619125439.55311-2-himanshu.bhavani@siliconsignals.io>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The `port` node does not mark `endpoint` as a required property.
--

commit 8d8a44d3691b781ed1f0eae46f632d337e365e3b
Author: Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>

dt-bindings: media: i2c: Add imx576 sensor

This commit adds device tree bindings for the Sony IMX576 CMOS active pixel
digital image sensor.

> diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml
> new file mode 100644
> index 0000000000000..52575ea2cbe1b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml

[ ... ]

> +  port:
> +    description: MIPI CSI-2 transmitter port
> +    $ref: /schemas/graph.yaml#/$defs/port-base
> +    additionalProperties: false
> +
> +    properties:
> +      endpoint:

[Severity: Low]
Should the port node mark the endpoint property as required?

Without specifying that the endpoint is required, an empty port node will
pass schema validation, even though the hardware requires an endpoint for
the MIPI CSI-2 interface to function.

> +        $ref: /schemas/media/video-interfaces.yaml#
> +        unevaluatedProperties: false

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260619125439.55311-1-himanshu.bhavani@siliconsignals.io?part=1

^ permalink raw reply

* Re: [PATCH 1/2] arm64: dts: qcom: sc8280xp: Add camera MCLK pinctrl
From: Konrad Dybcio @ 2026-06-19 13:03 UTC (permalink / raw)
  To: Vladimir Zapolskiy, Pengyu Luo
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <12a89ab8-dc43-4b55-9c95-36d44c75dcab@linaro.org>

On 6/19/26 2:59 PM, Vladimir Zapolskiy wrote:
> On 6/19/26 15:35, Konrad Dybcio wrote:
>> On 6/11/26 7:29 AM, Pengyu Luo wrote:
>>> On Tue, Jun 9, 2026 at 8:17 PM Konrad Dybcio
>>> <konrad.dybcio@oss.qualcomm.com> wrote:
>>>>
>>>> On 6/7/26 6:04 PM, Pengyu Luo wrote:
>>>>> Define pinctrl definitions to enable camera master clocks on sc8280xp.
>>>>>
>>>>> Suggested-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
>>>>> Signed-off-by: Pengyu Luo <mitltlatltl@gmail.com>
>>>>> ---
>>>>>   arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 56 ++++++++++++++++++++++++++
>>>>>   1 file changed, 56 insertions(+)
>>>>>
>>>>> diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
>>>>> index a2bd6b10e475..0dbcd3069a3b 100644
>>>>> --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
>>>>> +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
>>>>> @@ -5484,6 +5484,62 @@ tlmm: pinctrl@f100000 {
>>>>>                        gpio-ranges = <&tlmm 0 0 230>;
>>>>>                        wakeup-parent = <&pdc>;
>>>>>
>>>>> +                     cam_mclk0_default: cam-mclk0-default-state {
>>>>> +                             pins = "gpio119";
>>>>> +                             function = "cam_mclk";
>>>>> +                             drive-strength = <6>;
>>>>
>>>> Other platforms set this to 2 by default.
>>>>
>>>> What's the value set on Windows when the camera is in use?
>>>>
>>>
>>> It is 6mA.
>>>
>>> Let us get ctl_reg first on Windows
>>>
>>> lkd> !dd f111000 L8
>>> # f111000 00000284 00000002 000000e2 00000000
>>> # f111010 00000001 00000801 00000000 00000000
>>>
>>> ctl_reg => 0x284
>>>
>>> in msm_gpio_dbg_show_one()
>>> ...
>>> drive = (ctl_reg >> g->drv_bit) & 7; // (0x284 >> 6) & 7 == 2
>>> ...
>>> seq_printf(s, " %dmA", msm_regval_to_drive(drive)); // (drive + 1) * 2 == 6;
>>> ...
>>>
>>> x13s should be the same as gaokun3 in this part.
>>
>> I confirmed as much and I'm willing to believe this is a default for
>> all 8280 devices
>>
>> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>>
>> for the second patch, please mention in the commit message that the value
>> will now match windows and please add a fixes tag
>>
> 
> I believe the second change cannot be tagged as Fixes in sense that it
> strictly depends on a not going to be backported non-fix commit, and thus
> backporting of just 2/2 change as is will break the matter. Reordering of
> the commits placing the fix commit as the first one should be fine though.

The Fixes tag makes the patch eligible for backporting through AUTOSEL
but is itself not the same as "please backport"

Konrad

^ permalink raw reply

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

On Fri, Jun 19, 2026 at 12:40:54PM +0100, Conor Dooley wrote:
> On Fri, Jun 19, 2026 at 12:36:55PM +0100, Conor Dooley wrote:
> > On Fri, Jun 19, 2026 at 12:33:11PM +0200, Janani Sunil wrote:
> > > 
> > > On 6/14/26 21:44, Jonathan Cameron wrote:
> > > > On Tue, 9 Jun 2026 16:47:23 +0200
> > > > Janani Sunil <jan.sun97@gmail.com> wrote:
> > > > 
> > > > > On 5/26/26 15:11, Rodrigo Alencar wrote:
> > > > > > On 26/05/19 05:42PM, Janani Sunil wrote:
> > > > > > > Devicetree bindings for AD5529R 16 channel 12/16 bit high voltage,
> > > > > > > buffered voltage output digital-to-analog converter (DAC) with an
> > > > > > > integrated precision reference.
> > > > > > ...
> > > > > > Probably others may comment on that, but...
> > > > > > 
> > > > > > This parent node may support device addressing for multi-device support through
> > > > > > those ID pins. I suppose that each device may have its own power supplies or
> > > > > > other resources like the toggle pins or reset and enable.
> > > > > > 
> > > > > > That way I suppose that an example would look like...
> > > > > > > +
> > > > > > > +patternProperties:
> > > > > > > +  "^channel@([0-9]|1[0-5])$":
> > > > > > > +    type: object
> > > > > > > +    description: Child nodes for individual channel configuration
> > > > > > > +
> > > > > > > +    properties:
> > > > > > > +      reg:
> > > > > > > +        description: Channel number.
> > > > > > > +        minimum: 0
> > > > > > > +        maximum: 15
> > > > > > > +
> > > > > > > +      adi,output-range-microvolt:
> > > > > > > +        description: |
> > > > > > > +          Output voltage range for this channel as [min, max] in microvolts.
> > > > > > > +          If not specified, defaults to 0V to 5V range.
> > > > > > > +        oneOf:
> > > > > > > +          - items:
> > > > > > > +              - const: 0
> > > > > > > +              - enum: [5000000, 10000000, 20000000, 40000000]
> > > > > > > +          - items:
> > > > > > > +              - const: -5000000
> > > > > > > +              - const: 5000000
> > > > > > > +          - items:
> > > > > > > +              - const: -10000000
> > > > > > > +              - const: 10000000
> > > > > > > +          - items:
> > > > > > > +              - const: -15000000
> > > > > > > +              - const: 15000000
> > > > > > > +          - items:
> > > > > > > +              - const: -20000000
> > > > > > > +              - const: 20000000
> > > > > > > +
> > > > > > > +    required:
> > > > > > > +      - reg
> > > > > > > +
> > > > > > > +    additionalProperties: false
> > > > > > > +
> > > > > > > +required:
> > > > > > > +  - compatible
> > > > > > > +  - reg
> > > > > > > +  - vdd-supply
> > > > > > > +  - avdd-supply
> > > > > > > +  - hvdd-supply
> > > > > > > +
> > > > > > > +dependencies:
> > > > > > > +  spi-cpha: [ spi-cpol ]
> > > > > > > +  spi-cpol: [ spi-cpha ]
> > > > > > > +
> > > > > > > +allOf:
> > > > > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > > > +
> > > > > > > +unevaluatedProperties: false
> > > > > > > +
> > > > > > > +examples:
> > > > > > > +  - |
> > > > > > > +    #include <dt-bindings/gpio/gpio.h>
> > > > > > > +
> > > > > > > +    spi {
> > > > > > > +        #address-cells = <1>;
> > > > > > > +        #size-cells = <0>;
> > > > > > > +
> > > > > > > +        dac@0 {
> > > > > > > +            compatible = "adi,ad5529r-16";
> > > > > > > +            reg = <0>;
> > > > > > > +            spi-max-frequency = <25000000>;
> > > > > > > +
> > > > > > > +            vdd-supply = <&vdd_regulator>;
> > > > > > > +            avdd-supply = <&avdd_regulator>;
> > > > > > > +            hvdd-supply = <&hvdd_regulator>;
> > > > > > > +            hvss-supply = <&hvss_regulator>;
> > > > > > > +
> > > > > > > +            reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
> > > > > > > +
> > > > > > > +            #address-cells = <1>;
> > > > > > > +            #size-cells = <0>;
> > > > > > > +
> > > > > > > +            channel@0 {
> > > > > > > +                reg = <0>;
> > > > > > > +                adi,output-range-microvolt = <0 5000000>;
> > > > > > > +            };
> > > > > > > +
> > > > > > > +            channel@1 {
> > > > > > > +                reg = <1>;
> > > > > > > +                adi,output-range-microvolt = <(-10000000) 10000000>;
> > > > > > > +            };
> > > > > > > +
> > > > > > > +            channel@2 {
> > > > > > > +                reg = <2>;
> > > > > > > +                adi,output-range-microvolt = <0 40000000>;
> > > > > > > +            };
> > > > > > > +        };
> > > > > > > +    };
> > > > > > ...
> > > > > > 
> > > > > > 	spi {
> > > > > > 		#address-cells = <1>;
> > > > > > 		#size-cells = <0>;
> > > > > > 
> > > > > > 		multi-dac@0 {
> > > > > > 			compatible = "adi,ad5529r-16";
> > > > > > 			reg = <0>;
> > > > > > 			spi-max-frequency = <25000000>;
> > > > > > 
> > > > > > 			#address-cells = <1>;
> > > > > > 			#size-cells = <0>;
> > > > > > 
> > > > > > 			dac@0 {
> > > > > > 				reg = <0>;
> > > > > > 				vdd-supply = <&vdd_regulator>;
> > > > > > 				avdd-supply = <&avdd_regulator>;
> > > > > > 				hvdd-supply = <&hvdd_regulator>;
> > > > > > 				hvss-supply = <&hvss_regulator>;
> > > > > > 
> > > > > > 				reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
> > > > > > 
> > > > > > 				#address-cells = <1>;
> > > > > > 				#size-cells = <0>;
> > > > > > 
> > > > > > 				channel@0 {
> > > > > > 					reg = <0>;
> > > > > > 					adi,output-range-microvolt = <0 5000000>;
> > > > > > 				};
> > > > > > 
> > > > > > 				channel@1 {
> > > > > > 					reg = <1>;
> > > > > > 					adi,output-range-microvolt = <(-10000000) 10000000>;
> > > > > > 				};
> > > > > > 
> > > > > > 				channel@2 {
> > > > > > 					reg = <2>;
> > > > > > 					adi,output-range-microvolt = <0 40000000>;
> > > > > > 				};
> > > > > > 			}
> > > > > > 
> > > > > > 			dac@1 {
> > > > > > 				reg = <1>;
> > > > > > 				vdd-supply = <&vdd_regulator>;
> > > > > > 				avdd-supply = <&avdd_regulator>;
> > > > > > 				hvdd-supply = <&hvdd_regulator>;
> > > > > > 				hvss-supply = <&hvss_regulator>;
> > > > > > 
> > > > > > 				reset-gpios = <&gpio0 88 GPIO_ACTIVE_LOW>;
> > > > > > 
> > > > > > 				#address-cells = <1>;
> > > > > > 				#size-cells = <0>;
> > > > > > 
> > > > > > 				channel@0 {
> > > > > > 					reg = <0>;
> > > > > > 					adi,output-range-microvolt = <0 5000000>;
> > > > > > 				};
> > > > > > 
> > > > > > 				channel@1 {
> > > > > > 					reg = <1>;
> > > > > > 					adi,output-range-microvolt = <(-10000000) 10000000>;
> > > > > > 				};
> > > > > > 			}
> > > > > > 		};
> > > > > > 	};
> > > > > > 
> > > > > > then you might need something like:
> > > > > > 
> > > > > > 	patternProperties:
> > > > > > 		"^dac@[0-3]$":
> > > > > > 
> > > > > > and put most of the things under this node pattern.
> > > > > > 
> > > > > > So the main driver that you're putting together might need to handle up to four instances.
> > > > > > Even if your current driver cannot handle this, the dt-bindings might need cover that.
> > > > > > 
> > > > > > Need to double check if each dac node needs a separate compatible, so you would maybe populate
> > > > > > a platform data to be shared with the child nodes, which would be a separate driver.
> > > > > > (not sure if it would make sense to mix and match ad5529r-16 and ad5529r-12).
> > > > > Hi Rodrigo,
> > > > > 
> > > > > Thank you for looking at this.
> > > > > 
> > > > > For now, I would prefer to keep the binding scoped to a single AD5529R device instance. The current
> > > > > hardware/use case we have only needs one device node and the driver is written around that model as well.
> > > > > While the device addressing pins could allow multi-device topology, we do not have an actual platform using
> > > > > that configuration at the moment, so I would prefer not to introduce an extra parent/child binding structure
> > > > > speculatively without a validating use case.
> > > > Interesting feature - kind of similar to address control on a typical i2c bus device, or
> > > > looking at it another way a kind of distributed SPI mux.
> > > > 
> > > > Challenge of a binding is we need to anticipate the future.  So I think we do need something
> > > > like Rodrigo is suggesting even if we only (for now) support a single instance in the driver.
> > > > That would leave the path open to supporting the addressing at a later date.
> > > > An alternative might be to look at it like a chained device setup. In those we pretend there
> > > > is just one device with a lot of channels etc.  The snag is that here things are more loosely
> > > > coupled whereas for those devices it tends to be you have to read / write the same register
> > > > in all devices in the chain as one big SPI message.
> > > > 
> > > > +CC Mark Brown as he may know of some precedence for this feature. For his reference..
> > > > - Each of these device has 2 ID pins.  The SPI transfers have to contain the 2 bit
> > > > value that matches that or they are ignored.  Thus a single bus + 1 chip select can
> > > > be used to talk to 4 devices.  Question is what that looks like in device tree + I guess
> > > > longer term how to support it cleanly in SPI.
> > 
> > I'd swear I have seen this before, from some Microchip devices. Let me
> > see if I can find what I am thinking of...
> 
> 
> microchip,mcp3911 and microchip,mcp3564 both seem to do this with
> slightly different properties.
> 
>   microchip,device-addr:
>     description: Device address when multiple MCP3911 chips are present on the same SPI bus.
>     $ref: /schemas/types.yaml#/definitions/uint32
>     enum: [0, 1, 2, 3]
>     default: 0
> 
> and
> 
> 
>   microchip,hw-device-address:
>     $ref: /schemas/types.yaml#/definitions/uint32
>     minimum: 0
>     maximum: 3
>     description:
>       The address is set on a per-device basis by fuses in the factory,
>       configured on request. If not requested, the fuses are set for 0x1.
>       The device address is part of the device markings to avoid
>       potential confusion. This address is coded on two bits, so four possible
>       addresses are available when multiple devices are present on the same
>       SPI bus with only one Chip Select line for all devices.
>       Each device communication starts by a CS falling edge, followed by the
>       clocking of the device address (BITS[7:6] - top two bits of COMMAND BYTE
>       which is first one on the wire).
> 
> This sounds exactly like the sort of feature that you're dealing with
> here?
> 

The core idea yes but for this chip, things are a bit more annoying (but
Janani can correct me if I'm wrong). Here, each device can, in theory,
have it's own supplies, pins and at the very least, channels with maybe
different scales. That is why Janani is proposing dac nodes. Given I
honestly don't like much of that "adi,ad5529r-bus" compatible I wondered
about solving this at the spi level.

Ah and to make it more annoying, we can also mix 12 and 16 bits variants
together in the same bus.

- Nuno Sá



^ permalink raw reply

* Re: [PATCH 1/2] arm64: dts: qcom: sc8280xp: Add camera MCLK pinctrl
From: Vladimir Zapolskiy @ 2026-06-19 12:59 UTC (permalink / raw)
  To: Konrad Dybcio, Pengyu Luo
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <423b4e86-3837-4d69-8f56-d8259be53ff5@oss.qualcomm.com>

On 6/19/26 15:35, Konrad Dybcio wrote:
> On 6/11/26 7:29 AM, Pengyu Luo wrote:
>> On Tue, Jun 9, 2026 at 8:17 PM Konrad Dybcio
>> <konrad.dybcio@oss.qualcomm.com> wrote:
>>>
>>> On 6/7/26 6:04 PM, Pengyu Luo wrote:
>>>> Define pinctrl definitions to enable camera master clocks on sc8280xp.
>>>>
>>>> Suggested-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
>>>> Signed-off-by: Pengyu Luo <mitltlatltl@gmail.com>
>>>> ---
>>>>   arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 56 ++++++++++++++++++++++++++
>>>>   1 file changed, 56 insertions(+)
>>>>
>>>> diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
>>>> index a2bd6b10e475..0dbcd3069a3b 100644
>>>> --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
>>>> +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
>>>> @@ -5484,6 +5484,62 @@ tlmm: pinctrl@f100000 {
>>>>                        gpio-ranges = <&tlmm 0 0 230>;
>>>>                        wakeup-parent = <&pdc>;
>>>>
>>>> +                     cam_mclk0_default: cam-mclk0-default-state {
>>>> +                             pins = "gpio119";
>>>> +                             function = "cam_mclk";
>>>> +                             drive-strength = <6>;
>>>
>>> Other platforms set this to 2 by default.
>>>
>>> What's the value set on Windows when the camera is in use?
>>>
>>
>> It is 6mA.
>>
>> Let us get ctl_reg first on Windows
>>
>> lkd> !dd f111000 L8
>> # f111000 00000284 00000002 000000e2 00000000
>> # f111010 00000001 00000801 00000000 00000000
>>
>> ctl_reg => 0x284
>>
>> in msm_gpio_dbg_show_one()
>> ...
>> drive = (ctl_reg >> g->drv_bit) & 7; // (0x284 >> 6) & 7 == 2
>> ...
>> seq_printf(s, " %dmA", msm_regval_to_drive(drive)); // (drive + 1) * 2 == 6;
>> ...
>>
>> x13s should be the same as gaokun3 in this part.
> 
> I confirmed as much and I'm willing to believe this is a default for
> all 8280 devices
> 
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> for the second patch, please mention in the commit message that the value
> will now match windows and please add a fixes tag
> 

I believe the second change cannot be tagged as Fixes in sense that it
strictly depends on a not going to be backported non-fix commit, and thus
backporting of just 2/2 change as is will break the matter. Reordering of
the commits placing the fix commit as the first one should be fine though.

-- 
Best wishes,
Vladimir

^ permalink raw reply

* [PATCH v5] dt-bindings: misc: convert lis302.txt to YAML
From: Jad Keskes @ 2026-06-19 12:59 UTC (permalink / raw)
  To: Eric Piel, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Jonathan Cameron, devicetree, linux-kernel, Jad Keskes

Replace the old lis302.txt with a YAML binding covering all four
compatibles (st,lis3lv02d, st,lis302dl-spi, st,lis331dlh,
st,lis33de) and their ~35 DT properties.

The old txt documented st,click-thresh-* and st,click-click-time-limit
but the code reads st,click-threshold-* and st,click-time-limit.
Keep the old names as deprecated so existing DTBs don't break.

Tested: dt_binding_check. dtbs_check against 7 omap/am335x DTBs
(am335x-evm, am335x-evmsk, am335x-pepper, am437x-sk-evm, omap3-n900,
omap3-n950, omap3-gta04a3) — no misc schema errors. Pre-existing
IIO schema errors on paired compatible nodes unchanged.

Signed-off-by: Jad Keskes <inasj268@gmail.com>
---

v5:
  - Remove Vdd-supply/Vdd_IO-supply: false from SPI branch (hardware needs power regardless of bus)
  - Split if/then into two branches: SPI requires spi-max-frequency + interrupts,
    I2C requires Vdd-supply + Vdd_IO-supply (both optional on the other bus)
v4:
  - Drop explicit select block (redundant)
  - Fix commit message: select does not prevent IIO validation
v3:
  - Add st,lis3lv02d to select block
  - Drop Patch 2 entirely, single patch, no IIO changes
v2:
  - Rebase onto Linux 7.1-rc6, drop IIO changes
 .../devicetree/bindings/iio/accel/lis302.txt  | 119 ------
 .../bindings/misc/st,lis3lv02d.yaml           | 400 ++++++++++++++++++
 MAINTAINERS                                   |   1 +
 3 files changed, 401 insertions(+), 119 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/iio/accel/lis302.txt
 create mode 100644 Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml

diff --git a/Documentation/devicetree/bindings/iio/accel/lis302.txt b/Documentation/devicetree/bindings/iio/accel/lis302.txt
deleted file mode 100644
index 457539647f36..000000000000
--- a/Documentation/devicetree/bindings/iio/accel/lis302.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-LIS302 accelerometer devicetree bindings
-
-This device is matched via its bus drivers, and has a number of properties
-that apply in on the generic device (independent from the bus).
-
-
-Required properties for the SPI bindings:
- - compatible: 		should be set to "st,lis3lv02d-spi"
- - reg:			the chipselect index
- - spi-max-frequency:	maximal bus speed, should be set to 1000000 unless
-			constrained by external circuitry
- - interrupts:		the interrupt generated by the device
-
-Required properties for the I2C bindings:
- - compatible:		should be set to "st,lis3lv02d"
- - reg:			i2c slave address
- - Vdd-supply:		The input supply for Vdd
- - Vdd_IO-supply:	The input supply for Vdd_IO
-
-
-Optional properties for all bus drivers:
-
- - st,click-single-{x,y,z}:	if present, tells the device to issue an
-				interrupt on single click events on the
-				x/y/z axis.
- - st,click-double-{x,y,z}:	if present, tells the device to issue an
-				interrupt on double click events on the
-				x/y/z axis.
- - st,click-thresh-{x,y,z}:	set the x/y/z axis threshold
- - st,click-click-time-limit:	click time limit, from 0 to 127.5msec
-				with step of 0.5 msec
- - st,click-latency:		click latency, from 0 to 255 msec with
-				step of 1 msec.
- - st,click-window:		click window, from 0 to 255 msec with
-				step of 1 msec.
- - st,irq{1,2}-disable:		disable IRQ 1/2
- - st,irq{1,2}-ff-wu-1:		raise IRQ 1/2 on FF_WU_1 condition
- - st,irq{1,2}-ff-wu-2:		raise IRQ 1/2 on FF_WU_2 condition
- - st,irq{1,2}-data-ready:	raise IRQ 1/2 on data ready condition
- - st,irq{1,2}-click:		raise IRQ 1/2 on click condition
- - st,irq-open-drain:		consider IRQ lines open-drain
- - st,irq-active-low:		make IRQ lines active low
- - st,wu-duration-1:		duration register for Free-Fall/Wake-Up
-				interrupt 1
- - st,wu-duration-2:		duration register for Free-Fall/Wake-Up
-				interrupt 2
- - st,wakeup-{x,y,z}-{lo,hi}:	set wakeup condition on x/y/z axis for
-				upper/lower limit
- - st,wakeup-threshold:		set wakeup threshold
- - st,wakeup2-{x,y,z}-{lo,hi}:	set wakeup condition on x/y/z axis for
-				upper/lower limit for second wakeup
-				engine.
- - st,wakeup2-threshold:	set wakeup threshold for second wakeup
-				engine.
- - st,highpass-cutoff-hz=:	1, 2, 4 or 8 for 1Hz, 2Hz, 4Hz or 8Hz of
-				highpass cut-off frequency
- - st,hipass{1,2}-disable:	disable highpass 1/2.
- - st,default-rate=:		set the default rate
- - st,axis-{x,y,z}=:		set the axis to map to the three coordinates.
-				Negative values can be used for inverted axis.
- - st,{min,max}-limit-{x,y,z}	set the min/max limits for x/y/z axis
-				(used by self-test)
-
-
-Example for a SPI device node:
-
-	accelerometer@0 {
-		compatible = "st,lis302dl-spi";
-		reg = <0>;
-		spi-max-frequency = <1000000>;
-		interrupt-parent = <&gpio>;
-		interrupts = <104 0>;
-
-		st,click-single-x;
-		st,click-single-y;
-		st,click-single-z;
-		st,click-thresh-x = <10>;
-		st,click-thresh-y = <10>;
-		st,click-thresh-z = <10>;
-		st,irq1-click;
-		st,irq2-click;
-		st,wakeup-x-lo;
-		st,wakeup-x-hi;
-		st,wakeup-y-lo;
-		st,wakeup-y-hi;
-		st,wakeup-z-lo;
-		st,wakeup-z-hi;
-	};
-
-Example for a I2C device node:
-
-	lis331dlh: accelerometer@18 {
-		compatible = "st,lis331dlh", "st,lis3lv02d";
-		reg = <0x18>;
-		Vdd-supply = <&lis3_reg>;
-		Vdd_IO-supply = <&lis3_reg>;
-
-		st,click-single-x;
-		st,click-single-y;
-		st,click-single-z;
-		st,click-thresh-x = <10>;
-		st,click-thresh-y = <10>;
-		st,click-thresh-z = <10>;
-		st,irq1-click;
-		st,irq2-click;
-		st,wakeup-x-lo;
-		st,wakeup-x-hi;
-		st,wakeup-y-lo;
-		st,wakeup-y-hi;
-		st,wakeup-z-lo;
-		st,wakeup-z-hi;
-		st,min-limit-x = <120>;
-		st,min-limit-y = <120>;
-		st,min-limit-z = <140>;
-		st,max-limit-x = <550>;
-		st,max-limit-y = <550>;
-		st,max-limit-z = <750>;
-	};
-
diff --git a/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
new file mode 100644
index 000000000000..c73371b754a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
@@ -0,0 +1,400 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/misc/st,lis3lv02d.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics LIS3LV02D and similar accelerometers (misc driver)
+
+maintainers:
+  - Eric Piel <eric.piel@tremplin-utc.net>
+
+description:
+  This binding describes the STMicroelectronics accelerometers supported by
+  the misc/lis3lv02d driver. This driver provides input (joystick) and
+  hardware monitoring support, in contrast to the IIO st-accel driver which
+  also supports some of these devices.
+  Refer to Documentation/devicetree/bindings/iio/st,st-sensors.yaml for the
+  IIO binding.
+
+select:
+  anyOf:
+    - properties:
+        compatible:
+          contains:
+            const: st,lis302dl-spi
+    - properties:
+        compatible:
+          contains:
+            const: st,lis331dlh
+    - properties:
+        compatible:
+          contains:
+            const: st,lis33de
+    - properties:
+        compatible:
+          contains:
+            const: st,lis3lv02d
+  required:
+    - compatible
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - st,lis331dlh
+              - st,lis33de
+          - const: st,lis3lv02d
+      - const: st,lis331dlh
+      - const: st,lis3lv02d
+      - const: st,lis302dl-spi
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+
+  spi-max-frequency:
+    description: SPI bus frequency; should be set to 1000000 unless
+      constrained by external circuitry.
+    maximum: 1000000
+
+  Vdd-supply:
+    description: The input supply for Vdd.
+
+  Vdd_IO-supply:
+    description: The input supply for Vdd_IO.
+
+  st,click-single-x:
+    description: Issue an interrupt on single click events on the X axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-double-x:
+    description: Issue an interrupt on double click events on the X axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-single-y:
+    description: Issue an interrupt on single click events on the Y axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-double-y:
+    description: Issue an interrupt on double click events on the Y axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-single-z:
+    description: Issue an interrupt on single click events on the Z axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-double-z:
+    description: Issue an interrupt on double click events on the Z axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-thresh-x:
+    description: X axis click threshold (deprecated spelling, use st,click-threshold-x).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  st,click-thresh-y:
+    description: Y axis click threshold (deprecated spelling, use st,click-threshold-y).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  st,click-thresh-z:
+    description: Z axis click threshold (deprecated spelling, use st,click-threshold-z).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  st,click-threshold-x:
+    description: X axis click threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,click-threshold-y:
+    description: Y axis click threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,click-threshold-z:
+    description: Z axis click threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,click-click-time-limit:
+    description: Click time limit (deprecated spelling, use st,click-time-limit).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+    deprecated: true
+
+  st,click-time-limit:
+    description: Click time limit, from 0 to 127.5 msec with step of 0.5 msec.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,click-latency:
+    description: Click latency, from 0 to 255 msec with step of 1 msec.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,click-window:
+    description: Click window, from 0 to 255 msec with step of 1 msec.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,irq1-disable:
+    description: Disable IRQ 1.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-ff-wu-1:
+    description: Raise IRQ 1 on FF_WU_1 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-ff-wu-2:
+    description: Raise IRQ 1 on FF_WU_2 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-data-ready:
+    description: Raise IRQ 1 on data ready condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-click:
+    description: Raise IRQ 1 on click condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-disable:
+    description: Disable IRQ 2.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-ff-wu-1:
+    description: Raise IRQ 2 on FF_WU_1 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-ff-wu-2:
+    description: Raise IRQ 2 on FF_WU_2 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-data-ready:
+    description: Raise IRQ 2 on data ready condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-click:
+    description: Raise IRQ 2 on click condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq-open-drain:
+    description: Consider IRQ lines open-drain.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq-active-low:
+    description: Make IRQ lines active low.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wu-duration-1:
+    description: Duration register for Free-Fall/Wake-Up interrupt 1.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,wu-duration-2:
+    description: Duration register for Free-Fall/Wake-Up interrupt 2.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,wakeup-x-lo:
+    description: Set wakeup condition on X axis for lower limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-x-hi:
+    description: Set wakeup condition on X axis for upper limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-y-lo:
+    description: Set wakeup condition on Y axis for lower limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-y-hi:
+    description: Set wakeup condition on Y axis for upper limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-z-lo:
+    description: Set wakeup condition on Z axis for lower limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-z-hi:
+    description: Set wakeup condition on Z axis for upper limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-threshold:
+    description: Set wakeup threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,wakeup2-x-lo:
+    description: Set wakeup condition on X axis for lower limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-x-hi:
+    description: Set wakeup condition on X axis for upper limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-y-lo:
+    description: Set wakeup condition on Y axis for lower limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-y-hi:
+    description: Set wakeup condition on Y axis for upper limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-z-lo:
+    description: Set wakeup condition on Z axis for lower limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-z-hi:
+    description: Set wakeup condition on Z axis for upper limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-threshold:
+    description: Set wakeup threshold for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,highpass-cutoff-hz:
+    description: Highpass cut-off frequency. Valid values are 1, 2, 4 or 8.
+    enum: [1, 2, 4, 8]
+
+  st,hipass1-disable:
+    description: Disable highpass filter 1.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,hipass2-disable:
+    description: Disable highpass filter 2.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,default-rate:
+    description: Set the default output data rate.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,axis-x:
+    description: Set the X axis mapping. Negative values can be used for inverted axis.
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,axis-y:
+    description: Set the Y axis mapping. Negative values can be used for inverted axis.
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,axis-z:
+    description: Set the Z axis mapping. Negative values can be used for inverted axis.
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,min-limit-x:
+    description: Minimum limit for X axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,min-limit-y:
+    description: Minimum limit for Y axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,min-limit-z:
+    description: Minimum limit for Z axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,max-limit-x:
+    description: Maximum limit for X axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,max-limit-y:
+    description: Maximum limit for Y axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,max-limit-z:
+    description: Maximum limit for Z axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          not:
+            contains:
+              const: st,lis302dl-spi
+    then:
+      required:
+        - Vdd-supply
+        - Vdd_IO-supply
+    else:
+      properties:
+        Vdd-supply: false
+        Vdd_IO-supply: false
+      required:
+        - spi-max-frequency
+        - interrupts
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        accelerometer@18 {
+            compatible = "st,lis331dlh", "st,lis3lv02d";
+            reg = <0x18>;
+            Vdd-supply = <&lis3_reg>;
+            Vdd_IO-supply = <&lis3_reg>;
+            interrupt-parent = <&gpio2>;
+            interrupts = <18 0>;
+
+            st,click-single-x;
+            st,click-single-y;
+            st,click-single-z;
+            st,click-threshold-x = <10>;
+            st,click-threshold-y = <10>;
+            st,click-threshold-z = <10>;
+            st,irq1-click;
+            st,irq2-click;
+            st,wakeup-x-lo;
+            st,wakeup-x-hi;
+            st,wakeup-y-lo;
+            st,wakeup-y-hi;
+            st,wakeup-z-lo;
+            st,wakeup-z-hi;
+            st,min-limit-x = <120>;
+            st,min-limit-y = <120>;
+            st,min-limit-z = <140>;
+            st,max-limit-x = <550>;
+            st,max-limit-y = <550>;
+            st,max-limit-z = <750>;
+        };
+    };
+  - |
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        accelerometer@0 {
+            compatible = "st,lis302dl-spi";
+            reg = <0>;
+            spi-max-frequency = <1000000>;
+            interrupt-parent = <&gpio>;
+            interrupts = <104 0>;
+
+            st,click-single-x;
+            st,click-single-y;
+            st,click-single-z;
+            st,click-threshold-x = <10>;
+            st,click-threshold-y = <10>;
+            st,click-threshold-z = <10>;
+            st,irq1-click;
+            st,irq2-click;
+            st,wakeup-x-lo;
+            st,wakeup-x-hi;
+            st,wakeup-y-lo;
+            st,wakeup-y-hi;
+            st,wakeup-z-lo;
+            st,wakeup-z-hi;
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ec290e38b44..4cffabbabf0e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14858,6 +14858,7 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/
 LIS3LV02D ACCELEROMETER DRIVER
 M:	Eric Piel <eric.piel@tremplin-utc.net>
 S:	Maintained
+F:	Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
 F:	Documentation/misc-devices/lis3lv02d.rst
 F:	drivers/misc/lis3lv02d/
 F:	drivers/platform/x86/hp/hp_accel.c
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add Sony IMX576 front camera support
From: Himanshu Bhavani @ 2026-06-19 12:54 UTC (permalink / raw)
  To: sakari.ailus, luca.weiss
  Cc: Hardevsinh Palaniya, Himanshu Bhavani, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Hans Verkuil, Hans de Goede, Vladimir Zapolskiy,
	Mehdi Djait, Elgin Perumbilly, Laurent Pinchart,
	Walter Werner Schneider, Kate Hsuan, Svyatoslav Ryhel,
	linux-media, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <20260619125439.55311-1-himanshu.bhavani@siliconsignals.io>

From: Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>

Add device tree support for the Sony IMX576 front camera
sensor and connect it to CAMSS via CSIPHY3.

Signed-off-by: Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>
Signed-off-by: Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>
---
 arch/arm64/boot/dts/qcom/sm6350.dtsi          |  7 +++
 .../boot/dts/qcom/sm7225-fairphone-fp4.dts    | 53 ++++++++++++++++++-
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi
index 4f5934cf290a..ad8e8b450afc 100644
--- a/arch/arm64/boot/dts/qcom/sm6350.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi
@@ -2848,6 +2848,13 @@ cci2_sleep: cci2-sleep-state {
 				bias-pull-down;
 			};

+			cam_mclk1_default: cam-mclk1-default-state {
+				pins = "gpio30";
+				function = "cam_mclk1";
+				drive-strength = <2>;
+				bias-disable;
+			};
+
 			sdc2_off_state: sdc2-off-state {
 				clk-pins {
 					pins = "sdc2_clk";
diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
index 3964aae47fd4..1cacd17e7c47 100644
--- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
+++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
@@ -17,6 +17,7 @@
 #include <dt-bindings/iio/qcom,spmi-adc7-pmk8350.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/leds/common.h>
+#include <dt-bindings/media/video-interfaces.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 #include <dt-bindings/sound/qcom,q6asm.h>
@@ -547,6 +548,29 @@ vreg_bob: bob {
 	};
 };

+&camss {
+	vdd-csiphy0-0p9-supply = <&vreg_l18a>;
+	vdd-csiphy0-1p25-supply = <&vreg_l22a>;
+	vdd-csiphy1-0p9-supply = <&vreg_l18a>;
+	vdd-csiphy1-1p25-supply = <&vreg_l22a>;
+	vdd-csiphy2-0p9-supply = <&vreg_l18a>;
+	vdd-csiphy2-1p25-supply = <&vreg_l22a>;
+	vdd-csiphy3-0p9-supply = <&vreg_l18a>;
+	vdd-csiphy3-1p25-supply = <&vreg_l22a>;
+
+	status = "okay";
+
+	ports {
+		port@3 {
+			csiphy3_ep: endpoint {
+				data-lanes = <0 1 2 3>;
+				bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
+				remote-endpoint = <&camera_imx576_ep>;
+			};
+		};
+	};
+};
+
 &cci0 {
 	status = "okay";
 };
@@ -581,7 +605,34 @@ &cci1 {
 };

 &cci1_i2c0 {
-	/* Front cam (Sony IMX576) @ 0x10 */
+	camera@10 {
+		compatible = "sony,imx576";
+		reg = <0x10>;
+
+		vana-supply = <&vreg_l3p>;
+		vif-supply = <&vreg_l6p>;
+		vdig-supply = <&vreg_32m_cam_dvdd_1p05>;
+
+		clocks = <&camcc CAMCC_MCLK1_CLK>;
+		assigned-clocks = <&camcc CAMCC_MCLK1_CLK>;
+		assigned-clock-rates = <24000000>;
+
+		reset-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>;
+		pinctrl-0 = <&cam_mclk1_default>;
+		pinctrl-names = "default";
+
+		orientation = <0>; /* Front facing */
+		rotation = <90>;
+
+		port {
+			camera_imx576_ep: endpoint {
+				data-lanes = <1 2 3 4>;
+				bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
+				link-frequencies = /bits/ 64 <600000000>;
+				remote-endpoint = <&csiphy3_ep>;
+			};
+		};
+	};

 	eeprom@50 {
 		compatible = "giantec,gt24p64a", "atmel,24c64";
--
2.34.1


^ permalink raw reply related

* [PATCH v2 2/3] media: i2c: add imx576 image sensor driver
From: Himanshu Bhavani @ 2026-06-19 12:54 UTC (permalink / raw)
  To: sakari.ailus, luca.weiss
  Cc: Himanshu Bhavani, Hardevsinh Palaniya, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Hans Verkuil, Hans de Goede, Vladimir Zapolskiy,
	Elgin Perumbilly, Laurent Pinchart, Walter Werner Schneider,
	Kate Hsuan, Svyatoslav Ryhel, linux-media, devicetree,
	linux-kernel, linux-arm-msm
In-Reply-To: <20260619125439.55311-1-himanshu.bhavani@siliconsignals.io>

Add a v4l2 subdevice driver for the Sony imx576 sensor.

The Sony IMX576 image sensor with an active
array size of 5760 x 4312

The following features are supported:
- Manual exposure an gain control support
- vblank/hblank control support
- Supported resolution: 2880 x 2156 30fps (SRGGB10)

Signed-off-by: Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>
---
 MAINTAINERS                |    1 +
 drivers/media/i2c/Kconfig  |   10 +
 drivers/media/i2c/Makefile |    1 +
 drivers/media/i2c/imx576.c | 1034 ++++++++++++++++++++++++++++++++++++
 4 files changed, 1046 insertions(+)
 create mode 100644 drivers/media/i2c/imx576.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 1b15fa355e8b..768a1eb3627a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24862,6 +24862,7 @@ M:	Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>
 L:	linux-media@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml
+F:	drivers/media/i2c/imx576.c

 SONY MEMORYSTICK SUBSYSTEM
 M:	Maxim Levitsky <maximlevitsky@gmail.com>
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index fc2954098eaf..05d1e69c2f33 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -288,6 +288,16 @@ config VIDEO_IMX415
 	  To compile this driver as a module, choose M here: the
 	  module will be called imx415.

+config VIDEO_IMX576
+        tristate "Sony IMX576 sensor support"
+        select V4L2_CCI_I2C
+        help
+          This is a Video4Linux2 sensor driver for the Sony
+          IMX576 camera.
+
+          To compile this driver as a module, choose M here: the
+          module will be called imx576.
+
 config VIDEO_MAX9271_LIB
 	tristate

diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 90b276a7417a..e96c083e03d9 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o
 obj-$(CONFIG_VIDEO_IMX355) += imx355.o
 obj-$(CONFIG_VIDEO_IMX412) += imx412.o
 obj-$(CONFIG_VIDEO_IMX415) += imx415.o
+obj-$(CONFIG_VIDEO_IMX576) += imx576.o
 obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o
 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
diff --git a/drivers/media/i2c/imx576.c b/drivers/media/i2c/imx576.c
new file mode 100644
index 000000000000..3da7b5663355
--- /dev/null
+++ b/drivers/media/i2c/imx576.c
@@ -0,0 +1,1034 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * V4L2 Support for the IMX576
+ *
+ * Copyright (C) 2026 Silicon Signals Pvt. Ltd.
+ *
+ * Copyright (C) 2024 Luca Weiss <luca.weiss@fairphone.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/container_of.h>
+#include <linux/delay.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/units.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>
+
+#define IMX576_INCLK_RATE		(24 * HZ_PER_MHZ)
+
+#define IMX576_REG_CHIP_ID		CCI_REG16(0x0016)
+#define IMX576_CHIP_ID			0x0576
+
+#define IMX576_REG_MODE_SELECT		CCI_REG8(0x0100)
+#define IMX576_MODE_STANDBY		0x00
+#define IMX576_MODE_STREAMING		0x01
+
+#define IMX576_REG_HOLD			CCI_REG8(0x0104)
+
+#define IMX576_REG_EXPOSURE		CCI_REG16(0x0202)
+#define IMX576_EXPOSURE_MIN		8
+#define IMX576_EXPOSURE_OFFSET		22
+#define IMX576_EXPOSURE_STEP		1
+#define IMX576_EXPOSURE_DEFAULT		0x0648
+
+#define IMX576_REG_ANALOG_GAIN		CCI_REG16(0x0204)
+#define IMX576_ANA_GAIN_MIN		0
+#define IMX576_ANA_GAIN_MAX		978
+#define IMX576_ANA_GAIN_STEP		1
+#define IMX576_ANA_GAIN_DEFAULT		0
+
+#define IMX576_REG_VTS			CCI_REG16(0x0340)
+#define IMX576_REG_HTS			CCI_REG16(0x0342)
+
+/* FIXME: Exact VBLANK limit unknown (no datasheet). */
+#define IMX576_VBLANK_MAX		32420
+
+#define IMX576_LINK_FREQ_600MHZ		(600 * HZ_PER_MHZ)
+#define IMX576_NUM_DATA_LANES		4
+
+/* IMX576 native and active pixel array size */
+static const struct v4l2_rect imx576_native_area = {
+	.top = 0,
+	.left = 0,
+	.width = 5792,
+	.height = 4464,
+};
+
+static const struct v4l2_rect imx576_active_area = {
+	.top = 136,
+	.left = 16,
+	.width = 5760,
+	.height = 4312,
+};
+
+static const char * const imx576_supply_names[] = {
+	"vana",		/* Analog Power */
+	"vif",		/* Interface Power */
+	"vdig",		/* Digital Power */
+};
+
+static const struct cci_reg_sequence imx576_common_regs[] = {
+	{ CCI_REG8(0x0136), 0x18 },
+	{ CCI_REG8(0x0137), 0x00 },
+	{ CCI_REG8(0x3c7e), 0x05 },
+	{ CCI_REG8(0x3c7f), 0x07 },
+	{ CCI_REG8(0x380d), 0x80 },
+	{ CCI_REG8(0x3c00), 0x1a },
+	{ CCI_REG8(0x3c01), 0x1a },
+	{ CCI_REG8(0x3c02), 0x1a },
+	{ CCI_REG8(0x3c03), 0x1a },
+	{ CCI_REG8(0x3c04), 0x1a },
+	{ CCI_REG8(0x3c05), 0x01 },
+	{ CCI_REG8(0x3c08), 0xff },
+	{ CCI_REG8(0x3c09), 0xff },
+	{ CCI_REG8(0x3c0a), 0x01 },
+	{ CCI_REG8(0x3c0d), 0xff },
+	{ CCI_REG8(0x3c0e), 0xff },
+	{ CCI_REG8(0x3c0f), 0x20 },
+	{ CCI_REG8(0x3f89), 0x01 },
+	{ CCI_REG8(0x4b8e), 0x18 },
+	{ CCI_REG8(0x4b8f), 0x10 },
+	{ CCI_REG8(0x4ba8), 0x08 },
+	{ CCI_REG8(0x4baa), 0x08 },
+	{ CCI_REG8(0x4bab), 0x08 },
+	{ CCI_REG8(0x4bc9), 0x10 },
+	{ CCI_REG8(0x5511), 0x01 },
+	{ CCI_REG8(0x560b), 0x5b },
+	{ CCI_REG8(0x56a7), 0x60 },
+	{ CCI_REG8(0x5b3b), 0x60 },
+	{ CCI_REG8(0x5ba7), 0x60 },
+	{ CCI_REG8(0x6002), 0x00 },
+	{ CCI_REG8(0x6014), 0x01 },
+	{ CCI_REG8(0x6118), 0x0a },
+	{ CCI_REG8(0x6122), 0x0a },
+	{ CCI_REG8(0x6128), 0x0a },
+	{ CCI_REG8(0x6132), 0x0a },
+	{ CCI_REG8(0x6138), 0x0a },
+	{ CCI_REG8(0x6142), 0x0a },
+	{ CCI_REG8(0x6148), 0x0a },
+	{ CCI_REG8(0x6152), 0x0a },
+	{ CCI_REG8(0x617b), 0x04 },
+	{ CCI_REG8(0x617e), 0x04 },
+	{ CCI_REG8(0x6187), 0x04 },
+	{ CCI_REG8(0x618a), 0x04 },
+	{ CCI_REG8(0x6193), 0x04 },
+	{ CCI_REG8(0x6196), 0x04 },
+	{ CCI_REG8(0x619f), 0x04 },
+	{ CCI_REG8(0x61a2), 0x04 },
+	{ CCI_REG8(0x61ab), 0x04 },
+	{ CCI_REG8(0x61ae), 0x04 },
+	{ CCI_REG8(0x61b7), 0x04 },
+	{ CCI_REG8(0x61ba), 0x04 },
+	{ CCI_REG8(0x61c3), 0x04 },
+	{ CCI_REG8(0x61c6), 0x04 },
+	{ CCI_REG8(0x61cf), 0x04 },
+	{ CCI_REG8(0x61d2), 0x04 },
+	{ CCI_REG8(0x61db), 0x04 },
+	{ CCI_REG8(0x61de), 0x04 },
+	{ CCI_REG8(0x61e7), 0x04 },
+	{ CCI_REG8(0x61ea), 0x04 },
+	{ CCI_REG8(0x61f3), 0x04 },
+	{ CCI_REG8(0x61f6), 0x04 },
+	{ CCI_REG8(0x61ff), 0x04 },
+	{ CCI_REG8(0x6202), 0x04 },
+	{ CCI_REG8(0x620b), 0x04 },
+	{ CCI_REG8(0x620e), 0x04 },
+	{ CCI_REG8(0x6217), 0x04 },
+	{ CCI_REG8(0x621a), 0x04 },
+	{ CCI_REG8(0x6223), 0x04 },
+	{ CCI_REG8(0x6226), 0x04 },
+	{ CCI_REG8(0x6b0b), 0x02 },
+	{ CCI_REG8(0x6b0c), 0x01 },
+	{ CCI_REG8(0x6b0d), 0x05 },
+	{ CCI_REG8(0x6b0f), 0x04 },
+	{ CCI_REG8(0x6b10), 0x02 },
+	{ CCI_REG8(0x6b11), 0x06 },
+	{ CCI_REG8(0x6b12), 0x03 },
+	{ CCI_REG8(0x6b13), 0x07 },
+	{ CCI_REG8(0x6b14), 0x0d },
+	{ CCI_REG8(0x6b15), 0x09 },
+	{ CCI_REG8(0x6b16), 0x0c },
+	{ CCI_REG8(0x6b17), 0x08 },
+	{ CCI_REG8(0x6b18), 0x0e },
+	{ CCI_REG8(0x6b19), 0x0a },
+	{ CCI_REG8(0x6b1a), 0x0f },
+	{ CCI_REG8(0x6b1b), 0x0b },
+	{ CCI_REG8(0x6b1c), 0x01 },
+	{ CCI_REG8(0x6b1d), 0x05 },
+	{ CCI_REG8(0x6b1f), 0x04 },
+	{ CCI_REG8(0x6b20), 0x02 },
+	{ CCI_REG8(0x6b21), 0x06 },
+	{ CCI_REG8(0x6b22), 0x03 },
+	{ CCI_REG8(0x6b23), 0x07 },
+	{ CCI_REG8(0x6b24), 0x0d },
+	{ CCI_REG8(0x6b25), 0x09 },
+	{ CCI_REG8(0x6b26), 0x0c },
+	{ CCI_REG8(0x6b27), 0x08 },
+	{ CCI_REG8(0x6b28), 0x0e },
+	{ CCI_REG8(0x6b29), 0x0a },
+	{ CCI_REG8(0x6b2a), 0x0f },
+	{ CCI_REG8(0x6b2b), 0x0b },
+	{ CCI_REG8(0x7948), 0x01 },
+	{ CCI_REG8(0x7949), 0x06 },
+	{ CCI_REG8(0x794b), 0x04 },
+	{ CCI_REG8(0x794c), 0x04 },
+	{ CCI_REG8(0x794d), 0x3a },
+	{ CCI_REG8(0x7951), 0x00 },
+	{ CCI_REG8(0x7952), 0x01 },
+	{ CCI_REG8(0x7955), 0x00 },
+	{ CCI_REG8(0x9004), 0x10 },
+	{ CCI_REG8(0x9200), 0xa0 },
+	{ CCI_REG8(0x9201), 0xa7 },
+	{ CCI_REG8(0x9202), 0xa0 },
+	{ CCI_REG8(0x9203), 0xaa },
+	{ CCI_REG8(0x9204), 0xa0 },
+	{ CCI_REG8(0x9205), 0xad },
+	{ CCI_REG8(0x9206), 0xa0 },
+	{ CCI_REG8(0x9207), 0xb0 },
+	{ CCI_REG8(0x9208), 0xa0 },
+	{ CCI_REG8(0x9209), 0xb3 },
+	{ CCI_REG8(0x920a), 0xb7 },
+	{ CCI_REG8(0x920b), 0x34 },
+	{ CCI_REG8(0x920c), 0xb7 },
+	{ CCI_REG8(0x920d), 0x36 },
+	{ CCI_REG8(0x920e), 0xb7 },
+	{ CCI_REG8(0x920f), 0x37 },
+	{ CCI_REG8(0x9210), 0xb7 },
+	{ CCI_REG8(0x9211), 0x38 },
+	{ CCI_REG8(0x9212), 0xb7 },
+	{ CCI_REG8(0x9213), 0x39 },
+	{ CCI_REG8(0x9214), 0xb7 },
+	{ CCI_REG8(0x9215), 0x3a },
+	{ CCI_REG8(0x9216), 0xb7 },
+	{ CCI_REG8(0x9217), 0x3c },
+	{ CCI_REG8(0x9218), 0xb7 },
+	{ CCI_REG8(0x9219), 0x3d },
+	{ CCI_REG8(0x921a), 0xb7 },
+	{ CCI_REG8(0x921b), 0x3e },
+	{ CCI_REG8(0x921c), 0xb7 },
+	{ CCI_REG8(0x921d), 0x3f },
+	{ CCI_REG8(0x921e), 0x7f },
+	{ CCI_REG8(0x921f), 0x77 },
+	{ CCI_REG8(0x99af), 0x0f },
+	{ CCI_REG8(0x99b0), 0x0f },
+	{ CCI_REG8(0x99b1), 0x0f },
+	{ CCI_REG8(0x99b2), 0x0f },
+	{ CCI_REG8(0x99b3), 0x0f },
+	{ CCI_REG8(0x99e1), 0x0f },
+	{ CCI_REG8(0x99e2), 0x0f },
+	{ CCI_REG8(0x99e3), 0x0f },
+	{ CCI_REG8(0x99e4), 0x0f },
+	{ CCI_REG8(0x99e5), 0x0f },
+	{ CCI_REG8(0x99e6), 0x0f },
+	{ CCI_REG8(0x99e7), 0x0f },
+	{ CCI_REG8(0x99e8), 0x0f },
+	{ CCI_REG8(0x99e9), 0x0f },
+	{ CCI_REG8(0x99ea), 0x0f },
+	{ CCI_REG8(0xe286), 0x31 },
+	{ CCI_REG8(0xe2a6), 0x32 },
+	{ CCI_REG8(0xe2c6), 0x33 },
+	{ CCI_REG8(0x4038), 0x00 },
+	{ CCI_REG8(0x9856), 0xa0 },
+	{ CCI_REG8(0x9857), 0x78 },
+	{ CCI_REG8(0x9858), 0x64 },
+	{ CCI_REG8(0x986e), 0x64 },
+	{ CCI_REG8(0x9870), 0x3c },
+	{ CCI_REG8(0x993a), 0x0e },
+	{ CCI_REG8(0x993b), 0x0e },
+	{ CCI_REG8(0x9953), 0x08 },
+	{ CCI_REG8(0x9954), 0x08 },
+	{ CCI_REG8(0x996b), 0x0f },
+	{ CCI_REG8(0x996d), 0x0f },
+	{ CCI_REG8(0x996f), 0x0f },
+	{ CCI_REG8(0x998e), 0x0f },
+	{ CCI_REG8(0xa101), 0x01 },
+	{ CCI_REG8(0xa103), 0x01 },
+	{ CCI_REG8(0xa105), 0x01 },
+	{ CCI_REG8(0xa107), 0x01 },
+	{ CCI_REG8(0xa109), 0x01 },
+	{ CCI_REG8(0xa10b), 0x01 },
+	{ CCI_REG8(0xa10d), 0x01 },
+	{ CCI_REG8(0xa10f), 0x01 },
+	{ CCI_REG8(0xa111), 0x01 },
+	{ CCI_REG8(0xa113), 0x01 },
+	{ CCI_REG8(0xa115), 0x01 },
+	{ CCI_REG8(0xa117), 0x01 },
+	{ CCI_REG8(0xa119), 0x01 },
+	{ CCI_REG8(0xa11b), 0x01 },
+	{ CCI_REG8(0xa11d), 0x01 },
+	{ CCI_REG8(0xaa58), 0x00 },
+	{ CCI_REG8(0xaa59), 0x01 },
+	{ CCI_REG8(0xab03), 0x10 },
+	{ CCI_REG8(0xab04), 0x10 },
+	{ CCI_REG8(0xab05), 0x10 },
+	{ CCI_REG8(0xad6a), 0x03 },
+	{ CCI_REG8(0xad6b), 0xff },
+	{ CCI_REG8(0xad77), 0x00 },
+	{ CCI_REG8(0xad82), 0x03 },
+	{ CCI_REG8(0xad83), 0xff },
+	{ CCI_REG8(0xae06), 0x04 },
+	{ CCI_REG8(0xae07), 0x16 },
+	{ CCI_REG8(0xae08), 0xff },
+	{ CCI_REG8(0xae09), 0x04 },
+	{ CCI_REG8(0xae0a), 0x16 },
+	{ CCI_REG8(0xae0b), 0xff },
+	{ CCI_REG8(0xaf01), 0x04 },
+	{ CCI_REG8(0xaf03), 0x0a },
+	{ CCI_REG8(0xaf05), 0x18 },
+	{ CCI_REG8(0xb048), 0x0a },
+};
+
+static const struct cci_reg_sequence mode_2880x2156_regs[] = {
+	{ CCI_REG8(0x0112), 0x0a },
+	{ CCI_REG8(0x0113), 0x0a },
+	{ CCI_REG8(0x0114), 0x03 },
+	{ CCI_REG8(0x0342), 0x0c },
+	{ CCI_REG8(0x0343), 0x5d },
+	{ CCI_REG8(0x0344), 0x00 },
+	{ CCI_REG8(0x0345), 0x00 },
+	{ CCI_REG8(0x0346), 0x00 },
+	{ CCI_REG8(0x0347), 0x00 },
+	{ CCI_REG8(0x0348), 0x16 },
+	{ CCI_REG8(0x0349), 0x7f },
+	{ CCI_REG8(0x034a), 0x10 },
+	{ CCI_REG8(0x034b), 0xd7 },
+	{ CCI_REG8(0x0220), 0x62 },
+	{ CCI_REG8(0x0900), 0x01 },
+	{ CCI_REG8(0x0901), 0x22 },
+	{ CCI_REG8(0x0902), 0x08 },
+	{ CCI_REG8(0x3140), 0x00 },
+	{ CCI_REG8(0x3246), 0x81 },
+	{ CCI_REG8(0x3247), 0x81 },
+	{ CCI_REG8(0x0401), 0x00 },
+	{ CCI_REG8(0x0404), 0x00 },
+	{ CCI_REG8(0x0405), 0x10 },
+	{ CCI_REG8(0x0408), 0x00 },
+	{ CCI_REG8(0x0409), 0x00 },
+	{ CCI_REG8(0x040a), 0x00 },
+	{ CCI_REG8(0x040b), 0x00 },
+	{ CCI_REG8(0x040c), 0x0b },
+	{ CCI_REG8(0x040d), 0x40 },
+	{ CCI_REG8(0x040e), 0x08 },
+	{ CCI_REG8(0x040f), 0x6c },
+	{ CCI_REG8(0x034c), 0x0b },
+	{ CCI_REG8(0x034d), 0x40 },
+	{ CCI_REG8(0x034e), 0x08 },
+	{ CCI_REG8(0x034f), 0x6c },
+	{ CCI_REG8(0x0301), 0x05 },
+	{ CCI_REG8(0x0303), 0x04 },
+	{ CCI_REG8(0x0305), 0x04 },
+	{ CCI_REG8(0x0306), 0x00 },
+	{ CCI_REG8(0x0307), 0xaf },
+	{ CCI_REG8(0x030b), 0x02 },
+	{ CCI_REG8(0x030d), 0x04 },
+	{ CCI_REG8(0x030e), 0x00 },
+	{ CCI_REG8(0x030f), 0xd1 },
+	{ CCI_REG8(0x0310), 0x01 },
+	{ CCI_REG8(0x0b06), 0x01 },
+	{ CCI_REG8(0x3620), 0x00 },
+	{ CCI_REG8(0x3f0c), 0x00 },
+	{ CCI_REG8(0x3f14), 0x01 },
+	{ CCI_REG8(0x3f80), 0x03 },
+	{ CCI_REG8(0x3f81), 0xe8 },
+	{ CCI_REG8(0x3ffc), 0x00 },
+	{ CCI_REG8(0x3ffd), 0x26 },
+	{ CCI_REG8(0x0202), 0x07 },
+	{ CCI_REG8(0x0203), 0xd0 },
+	{ CCI_REG8(0x0224), 0x01 },
+	{ CCI_REG8(0x0225), 0xf4 },
+	{ CCI_REG8(0x3fe0), 0x03 },
+	{ CCI_REG8(0x3fe1), 0xe8 },
+	{ CCI_REG8(0x0204), 0x00 },
+	{ CCI_REG8(0x0205), 0x00 },
+	{ CCI_REG8(0x0216), 0x00 },
+	{ CCI_REG8(0x0217), 0x00 },
+	{ CCI_REG8(0x0218), 0x01 },
+	{ CCI_REG8(0x0219), 0x00 },
+	{ CCI_REG8(0x020e), 0x01 },
+	{ CCI_REG8(0x020f), 0x00 },
+	{ CCI_REG8(0x3fe2), 0x00 },
+	{ CCI_REG8(0x3fe3), 0x00 },
+	{ CCI_REG8(0x3fe4), 0x01 },
+	{ CCI_REG8(0x3fe5), 0x00 },
+};
+
+struct imx576 {
+	struct device *dev;
+	struct regmap *regmap;
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	struct gpio_desc *reset_gpio;
+	struct clk *inclk;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(imx576_supply_names)];
+
+	/* V4L2 Controls */
+	struct v4l2_ctrl_handler handler;
+	struct v4l2_ctrl *link_freq;
+	struct v4l2_ctrl *hblank;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *exposure;
+	struct v4l2_ctrl *gain;
+
+	u32 link_freq_index;
+};
+
+struct imx576_reg_list {
+	u32 num_of_regs;
+	const struct cci_reg_sequence *regs;
+};
+
+struct imx576_mode {
+	u32 width;
+	u32 height;
+	u32 hts;
+	u32 vts;
+	struct imx576_reg_list reg_list;
+};
+
+static const struct imx576_mode supported_modes_10bit[] = {
+	{
+		.width = 2880,
+		.height = 2156,
+		.hts = 3165,
+		.vts = 2172,
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mode_2880x2156_regs),
+			.regs = mode_2880x2156_regs,
+		},
+	},
+};
+
+static const s64 link_frequencies[] = {
+	IMX576_LINK_FREQ_600MHZ,
+};
+
+static const u32 imx576_mbus_codes[] = {
+	MEDIA_BUS_FMT_SRGGB10_1X10,
+};
+
+static inline struct imx576 *to_imx576(struct v4l2_subdev *sd)
+{
+	return container_of_const(sd, struct imx576, sd);
+}
+
+static int imx576_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct imx576 *imx576 = container_of_const(ctrl->handler,
+						   struct imx576, handler);
+	struct v4l2_subdev_state *state;
+	struct v4l2_mbus_framefmt *fmt;
+	int ret = 0;
+
+	state = v4l2_subdev_get_locked_active_state(&imx576->sd);
+	fmt = v4l2_subdev_state_get_format(state, 0);
+
+	if (ctrl->id == V4L2_CID_VBLANK) {
+		/* Honour the VBLANK limits when setting exposure */
+		ret = __v4l2_ctrl_modify_range(imx576->exposure,
+					       IMX576_EXPOSURE_MIN,
+					       fmt->height + ctrl->val -
+					       IMX576_EXPOSURE_OFFSET,
+					       IMX576_EXPOSURE_STEP,
+					       IMX576_EXPOSURE_DEFAULT);
+		if (ret)
+			return ret;
+	}
+
+	if (pm_runtime_get_if_active(imx576->dev) == 0)
+		return 0;
+
+	cci_write(imx576->regmap, IMX576_REG_HOLD, 1, &ret);
+
+	switch (ctrl->id) {
+	case V4L2_CID_VBLANK: {
+		u64 vmax = fmt->height + ctrl->val;
+
+		cci_write(imx576->regmap, IMX576_REG_VTS, vmax, &ret);
+		break;
+	}
+	case V4L2_CID_EXPOSURE:
+		cci_write(imx576->regmap, IMX576_REG_EXPOSURE, ctrl->val, &ret);
+		break;
+	case V4L2_CID_ANALOGUE_GAIN:
+		cci_write(imx576->regmap, IMX576_REG_ANALOG_GAIN,
+			  ctrl->val, &ret);
+		break;
+	default:
+		dev_err(imx576->dev, "Invalid control %d\n", ctrl->id);
+		ret = -EINVAL;
+		break;
+	}
+
+	cci_write(imx576->regmap, IMX576_REG_HOLD, 0, &ret);
+
+	pm_runtime_put(imx576->dev);
+
+	return ret;
+}
+
+static int imx576_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *sd_state,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index >= ARRAY_SIZE(imx576_mbus_codes))
+		return -EINVAL;
+
+	code->code = imx576_mbus_codes[code->index];
+
+	return 0;
+}
+
+static int imx576_set_pad_format(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *sd_state,
+				 struct v4l2_subdev_format *fmt)
+{
+	const struct imx576_mode *mode = &supported_modes_10bit[0];
+	struct imx576 *imx576 = to_imx576(sd);
+	struct v4l2_mbus_framefmt *format;
+	int ret;
+
+	fmt->format.width = mode->width;
+	fmt->format.height = mode->height;
+	fmt->format.code = imx576_mbus_codes[0];
+	fmt->format.field = V4L2_FIELD_NONE;
+	fmt->format.colorspace = V4L2_COLORSPACE_RAW;
+	fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	fmt->format.quantization = V4L2_QUANTIZATION_DEFAULT;
+	fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
+
+	format = v4l2_subdev_state_get_format(sd_state, 0);
+
+	*format = fmt->format;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		u32 vblank_def = mode->vts - mode->height;
+
+		ret = __v4l2_ctrl_modify_range(imx576->vblank, vblank_def,
+					       IMX576_VBLANK_MAX, 1, vblank_def);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int imx576_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_state *sd_state,
+				struct v4l2_subdev_selection *sel)
+{
+	switch (sel->target) {
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r = imx576_native_area;
+		return 0;
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		sel->r = imx576_active_area;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int imx576_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_frame_size_enum *fsize)
+{
+	if (fsize->index >= ARRAY_SIZE(supported_modes_10bit))
+		return -EINVAL;
+
+	if (fsize->code != imx576_mbus_codes[0])
+		return -EINVAL;
+
+	fsize->min_width = supported_modes_10bit[fsize->index].width;
+	fsize->max_width = fsize->min_width;
+	fsize->min_height = supported_modes_10bit[fsize->index].height;
+	fsize->max_height = fsize->min_height;
+
+	return 0;
+}
+
+static int imx576_enable_streams(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *state,
+				 u32 pad, u64 streams_mask)
+{
+	const struct imx576_reg_list *reg_list;
+	struct imx576 *imx576 = to_imx576(sd);
+	const struct v4l2_mbus_framefmt *fmt;
+	const struct imx576_mode *mode;
+	int ret;
+
+	fmt = v4l2_subdev_state_get_format(state, 0);
+	mode = v4l2_find_nearest_size(supported_modes_10bit,
+				      ARRAY_SIZE(supported_modes_10bit), width,
+				      height, fmt->width, fmt->height);
+
+	ret = pm_runtime_resume_and_get(imx576->dev);
+	if (ret < 0)
+		return ret;
+
+	/* Write common registers */
+	ret = cci_multi_reg_write(imx576->regmap, imx576_common_regs,
+				  ARRAY_SIZE(imx576_common_regs), NULL);
+	if (ret) {
+		dev_err(imx576->dev, "failed to write common registers\n");
+		goto err_rpm_put;
+	}
+
+	/* Write sensor mode registers */
+	reg_list = &mode->reg_list;
+	ret = cci_multi_reg_write(imx576->regmap, reg_list->regs,
+				  reg_list->num_of_regs, NULL);
+	if (ret) {
+		dev_err(imx576->dev, "fail to write initial registers\n");
+		goto err_rpm_put;
+	}
+
+	/* Apply customized user controls */
+	ret =  __v4l2_ctrl_handler_setup(imx576->sd.ctrl_handler);
+	if (ret) {
+		dev_err(imx576->dev, "fail to setup handler\n");
+		goto err_rpm_put;
+	}
+
+	/* T7: delay before sending stream command */
+	usleep_range(8000, 9000);
+
+	/* Start streaming */
+	ret = cci_write(imx576->regmap, IMX576_REG_MODE_SELECT,
+			IMX576_MODE_STREAMING, NULL);
+	if (ret) {
+		dev_err(imx576->dev, "fail to start streaming\n");
+		goto err_rpm_put;
+	}
+
+	return 0;
+
+err_rpm_put:
+	pm_runtime_put(imx576->dev);
+
+	return ret;
+}
+
+static int imx576_disable_streams(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state,
+				  u32 pad, u64 streams_mask)
+{
+	struct imx576 *imx576 = to_imx576(sd);
+	int ret;
+
+	ret = cci_write(imx576->regmap, IMX576_REG_MODE_SELECT,
+			IMX576_MODE_STANDBY, NULL);
+	if (ret)
+		dev_err(imx576->dev, "failed to set stream off\n");
+
+	pm_runtime_put(imx576->dev);
+
+	return 0;
+}
+
+static int imx576_init_state(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_TRY,
+		.pad = 0,
+		.format = {
+			.code = imx576_mbus_codes[0],
+			.width = supported_modes_10bit[0].width,
+			.height = supported_modes_10bit[0].height,
+		},
+	};
+
+	return imx576_set_pad_format(sd, sd_state, &fmt);
+}
+
+static const struct v4l2_subdev_video_ops imx576_video_ops = {
+	.s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops imx576_pad_ops = {
+	.enum_mbus_code = imx576_enum_mbus_code,
+	.enum_frame_size = imx576_enum_frame_size,
+	.get_fmt = v4l2_subdev_get_fmt,
+	.set_fmt = imx576_set_pad_format,
+	.get_selection = imx576_get_selection,
+	.enable_streams = imx576_enable_streams,
+	.disable_streams = imx576_disable_streams,
+};
+
+static const struct v4l2_subdev_internal_ops imx576_internal_ops = {
+	.init_state = imx576_init_state,
+};
+
+static const struct v4l2_subdev_ops imx576_subdev_ops = {
+	.video = &imx576_video_ops,
+	.pad = &imx576_pad_ops,
+};
+
+static const struct v4l2_ctrl_ops imx576_ctrl_ops = {
+	.s_ctrl = imx576_set_ctrl,
+};
+
+static int imx576_detect(struct imx576 *imx576)
+{
+	int ret;
+	u64 val;
+
+	ret = cci_read(imx576->regmap, IMX576_REG_CHIP_ID, &val, NULL);
+	if (ret)
+		return dev_err_probe(imx576->dev, ret,
+				     "failed to read chip id %x\n",
+				     IMX576_CHIP_ID);
+
+	if (val != IMX576_CHIP_ID)
+		return dev_err_probe(imx576->dev, -EIO,
+				     "chip id mismatch: %x!=%llx\n",
+				     IMX576_CHIP_ID, val);
+
+	return 0;
+}
+
+static int imx576_power_on(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct imx576 *imx576 = to_imx576(sd);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(imx576_supply_names),
+				    imx576->supplies);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable regulators\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(imx576->inclk);
+	if (ret) {
+		dev_err(imx576->dev, "fail to enable inclk\n");
+		goto err_regulator_off;
+	}
+
+	gpiod_set_value_cansleep(imx576->reset_gpio, 0);
+
+	/* T6: Wait for internal init before CCI access */
+	usleep_range(1000, 1200);
+
+	return 0;
+
+err_regulator_off:
+	regulator_bulk_disable(ARRAY_SIZE(imx576_supply_names),
+			       imx576->supplies);
+
+	return ret;
+}
+
+static int imx576_power_off(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct imx576 *imx576 = to_imx576(sd);
+
+	clk_disable_unprepare(imx576->inclk);
+
+	gpiod_set_value_cansleep(imx576->reset_gpio, 1);
+
+	regulator_bulk_disable(ARRAY_SIZE(imx576_supply_names),
+			       imx576->supplies);
+
+	return 0;
+}
+
+static int imx576_parse_endpoint(struct imx576 *imx576)
+{
+	struct v4l2_fwnode_endpoint bus_cfg = {
+		.bus_type = V4L2_MBUS_CSI2_DPHY,
+	};
+	unsigned long link_freq_bitmap;
+	struct fwnode_handle *ep;
+	int ret;
+
+	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(imx576->dev), 0, 0, 0);
+	if (!ep)
+		return dev_err_probe(imx576->dev, -ENXIO,
+				     "Failed to get next endpoint\n");
+
+	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+	fwnode_handle_put(ep);
+	if (ret)
+		return ret;
+
+	if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX576_NUM_DATA_LANES) {
+		ret = dev_err_probe(imx576->dev, -EINVAL,
+				    "only 4 data lanes are supported\n");
+		goto error_out;
+	}
+
+	ret = v4l2_link_freq_to_bitmap(imx576->dev, bus_cfg.link_frequencies,
+				       bus_cfg.nr_of_link_frequencies,
+				       link_frequencies, ARRAY_SIZE(link_frequencies),
+				       &link_freq_bitmap);
+	if (ret) {
+		ret = dev_err_probe(imx576->dev, -EINVAL,
+				    "only 600MHz frequency is available\n");
+		goto error_out;
+	}
+
+	imx576->link_freq_index = __ffs(link_freq_bitmap);
+
+error_out:
+	v4l2_fwnode_endpoint_free(&bus_cfg);
+
+	return ret;
+}
+
+static int imx576_init_controls(struct imx576 *imx576)
+{
+	const struct imx576_mode *mode = &supported_modes_10bit[0];
+	struct v4l2_fwnode_device_properties props;
+	u64 vblank_def, hblank_def, pixel_rate;
+	struct v4l2_ctrl_handler *ctrl_hdlr;
+	u32 lpfr;
+	int ret;
+
+	ret = v4l2_fwnode_device_parse(imx576->dev, &props);
+	if (ret)
+		return ret;
+
+	ctrl_hdlr = &imx576->handler;
+	v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+
+	vblank_def = mode->vts - mode->height;
+	lpfr = vblank_def + mode->height;
+	imx576->exposure = v4l2_ctrl_new_std(ctrl_hdlr,
+					     &imx576_ctrl_ops,
+					     V4L2_CID_EXPOSURE,
+					     IMX576_EXPOSURE_MIN,
+					     lpfr - IMX576_EXPOSURE_OFFSET,
+					     IMX576_EXPOSURE_STEP,
+					     IMX576_EXPOSURE_DEFAULT);
+
+	imx576->gain = v4l2_ctrl_new_std(ctrl_hdlr, &imx576_ctrl_ops,
+					 V4L2_CID_ANALOGUE_GAIN,
+					 IMX576_ANA_GAIN_MIN,
+					 IMX576_ANA_GAIN_MAX,
+					 IMX576_ANA_GAIN_STEP,
+					 IMX576_ANA_GAIN_DEFAULT);
+
+	imx576->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx576_ctrl_ops,
+					   V4L2_CID_VBLANK, vblank_def,
+					   IMX576_VBLANK_MAX, 1,
+					   vblank_def);
+
+	/* pixel_rate = link_frequency * 2 * nr_of_lanes / bits_per_sample */
+	pixel_rate = div_u64(IMX576_LINK_FREQ_600MHZ * 2 * IMX576_NUM_DATA_LANES, 10);
+	v4l2_ctrl_new_std(ctrl_hdlr, &imx576_ctrl_ops, V4L2_CID_PIXEL_RATE,
+			  pixel_rate, pixel_rate, 1, pixel_rate);
+
+	imx576->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx576_ctrl_ops,
+						   V4L2_CID_LINK_FREQ,
+						   ARRAY_SIZE(link_frequencies) - 1,
+						   imx576->link_freq_index,
+						   link_frequencies);
+
+	hblank_def = mode->hts - mode->width;
+	imx576->hblank = v4l2_ctrl_new_std(ctrl_hdlr,
+					   &imx576_ctrl_ops,
+					   V4L2_CID_HBLANK,
+					   hblank_def,
+					   hblank_def,
+					   1, hblank_def);
+
+	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx576_ctrl_ops, &props);
+	if (ret)
+		goto err_handler_free;
+
+	if (ctrl_hdlr->error) {
+		ret = ctrl_hdlr->error;
+		goto err_handler_free;
+	}
+
+	imx576->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	imx576->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	imx576->sd.ctrl_handler = ctrl_hdlr;
+
+	return 0;
+
+err_handler_free:
+	v4l2_ctrl_handler_free(ctrl_hdlr);
+
+	return ret;
+}
+
+static int imx576_probe(struct i2c_client *client)
+{
+	struct imx576 *imx576;
+	unsigned int inclk_freq;
+	int ret;
+
+	imx576 = devm_kzalloc(&client->dev, sizeof(*imx576), GFP_KERNEL);
+	if (!imx576)
+		return -ENOMEM;
+
+	imx576->dev = &client->dev;
+
+	/* Initialize subdev */
+	v4l2_i2c_subdev_init(&imx576->sd, client, &imx576_subdev_ops);
+	imx576->sd.internal_ops = &imx576_internal_ops;
+
+	imx576->regmap = devm_cci_regmap_init_i2c(client, 16);
+	if (IS_ERR(imx576->regmap))
+		return dev_err_probe(imx576->dev, PTR_ERR(imx576->regmap),
+				     "failed to initialize CCI\n");
+
+	ret = imx576_parse_endpoint(imx576);
+	if (ret)
+		return dev_err_probe(imx576->dev, ret,
+				     "failed to parse endpoint configuration\n");
+
+	/* Get sensor input clock */
+	imx576->inclk = devm_v4l2_sensor_clk_get(imx576->dev, NULL);
+	if (IS_ERR(imx576->inclk))
+		return dev_err_probe(imx576->dev, PTR_ERR(imx576->inclk),
+				     "failed to get inclk\n");
+
+	inclk_freq = clk_get_rate(imx576->inclk);
+	if (inclk_freq != IMX576_INCLK_RATE)
+		return dev_err_probe(imx576->dev, -EINVAL,
+				     "inclk frequency not supported: %u Hz\n",
+				     inclk_freq);
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(imx576_supply_names); i++)
+		imx576->supplies[i].supply = imx576_supply_names[i];
+
+	ret = devm_regulator_bulk_get(imx576->dev,
+				      ARRAY_SIZE(imx576_supply_names),
+				      imx576->supplies);
+	if (ret)
+		return dev_err_probe(imx576->dev, ret,
+				     "failed to get regulators\n");
+
+	imx576->reset_gpio = devm_gpiod_get_optional(imx576->dev, "reset",
+						     GPIOD_OUT_HIGH);
+	if (IS_ERR(imx576->reset_gpio))
+		return dev_err_probe(imx576->dev, PTR_ERR(imx576->reset_gpio),
+				     "failed to get reset GPIO\n");
+
+	ret = imx576_power_on(imx576->dev);
+	if (ret)
+		return ret;
+
+	ret = imx576_detect(imx576);
+	if (ret)
+		goto error_power_off;
+
+	ret = imx576_init_controls(imx576);
+	if (ret) {
+		dev_err_probe(imx576->dev, ret, "failed to init controls");
+		goto error_power_off;
+	}
+
+	/* Initialize subdev */
+	imx576->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	imx576->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	imx576->pad.flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&imx576->sd.entity, 1, &imx576->pad);
+	if (ret) {
+		dev_err_probe(imx576->dev, ret, "failed to init entity pads");
+		goto error_handler_free;
+	}
+
+	imx576->sd.state_lock = imx576->handler.lock;
+	ret = v4l2_subdev_init_finalize(&imx576->sd);
+	if (ret < 0) {
+		dev_err_probe(imx576->dev, ret, "subdev init error\n");
+		goto error_media_entity;
+	}
+
+	pm_runtime_set_active(imx576->dev);
+	pm_runtime_enable(imx576->dev);
+
+	ret = v4l2_async_register_subdev_sensor(&imx576->sd);
+	if (ret < 0) {
+		dev_err_probe(imx576->dev, ret,
+			      "failed to register imx576 sub-device\n");
+		goto error_subdev_cleanup;
+	}
+
+	pm_runtime_idle(imx576->dev);
+
+	return 0;
+
+error_subdev_cleanup:
+	v4l2_subdev_cleanup(&imx576->sd);
+	pm_runtime_disable(imx576->dev);
+	pm_runtime_set_suspended(imx576->dev);
+
+error_media_entity:
+	media_entity_cleanup(&imx576->sd.entity);
+
+error_handler_free:
+	v4l2_ctrl_handler_free(imx576->sd.ctrl_handler);
+
+error_power_off:
+	imx576_power_off(imx576->dev);
+
+	return ret;
+}
+
+static void imx576_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct imx576 *imx576 = to_imx576(sd);
+
+	v4l2_async_unregister_subdev(sd);
+	v4l2_subdev_cleanup(&imx576->sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(imx576->sd.ctrl_handler);
+
+	pm_runtime_disable(&client->dev);
+	if (!pm_runtime_status_suspended(&client->dev)) {
+		imx576_power_off(&client->dev);
+		pm_runtime_set_suspended(&client->dev);
+	}
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(imx576_pm_ops,
+				 imx576_power_off, imx576_power_on, NULL);
+
+static const struct of_device_id imx576_of_match[] = {
+	{ .compatible = "sony,imx576" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx576_of_match);
+
+static struct i2c_driver imx576_driver = {
+	.driver = {
+		.name = "imx576",
+		.pm = &imx576_pm_ops,
+		.of_match_table = imx576_of_match,
+	},
+	.probe = imx576_probe,
+	.remove = imx576_remove,
+};
+module_i2c_driver(imx576_driver);
+
+MODULE_DESCRIPTION("IMX576 Camera Sensor Driver");
+MODULE_AUTHOR("Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>");
+MODULE_AUTHOR("Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>");
+MODULE_LICENSE("GPL");
--
2.34.1


^ permalink raw reply related

* [PATCH v2 1/3] dt-bindings: media: i2c: Add imx576 sensor
From: Himanshu Bhavani @ 2026-06-19 12:54 UTC (permalink / raw)
  To: sakari.ailus, luca.weiss
  Cc: Hardevsinh Palaniya, Himanshu Bhavani, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Hans Verkuil, Hans de Goede, Vladimir Zapolskiy,
	Elgin Perumbilly, Xiaolei Wang, Laurent Pinchart,
	Walter Werner Schneider, Kate Hsuan, Svyatoslav Ryhel,
	linux-media, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <20260619125439.55311-1-himanshu.bhavani@siliconsignals.io>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=yes, Size: 4141 bytes --]

From: Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>

Add bindings for Sony IMX576 sensor

Signed-off-by: Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>
Signed-off-by: Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>
---
 .../bindings/media/i2c/sony,imx576.yaml       | 111 ++++++++++++++++++
 MAINTAINERS                                   |   7 ++
 2 files changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml

diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml
new file mode 100644
index 000000000000..52575ea2cbe1
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml
@@ -0,0 +1,111 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/sony,imx576.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony IMX576 Image Sensor
+
+maintainers:
+  - Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>
+
+description:
+  IMX576 sensor is a Sony CMOS active pixel digital image sensor with an active
+  array size of 5760(H) × 4312(V). It is programmable through an I2C interface.
+  Image data is transmitted through MIPI CSI-2. It supports RAW10/RAW8, COMP8
+  output formats.
+
+allOf:
+  - $ref: /schemas/media/video-interface-devices.yaml#
+
+properties:
+  compatible:
+    const: sony,imx576
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: INCLK clock
+
+  vana-supply:
+    description: Analog Supply Voltage (2.8v)
+
+  vdig-supply:
+    description: Digital Supply Voltage (1.05v)
+
+  vif-supply:
+    description: Interface Supply Voltage (1.8v)
+
+  reset-gpios:
+    maxItems: 1
+    description: Reset Pin GPIO Control (active low)
+
+  port:
+    description: MIPI CSI-2 transmitter port
+    $ref: /schemas/graph.yaml#/$defs/port-base
+    additionalProperties: false
+
+    properties:
+      endpoint:
+        $ref: /schemas/media/video-interfaces.yaml#
+        unevaluatedProperties: false
+
+        properties:
+          data-lanes:
+            oneOf:
+              - items:
+                  - const: 1
+                  - const: 2
+                  - const: 3
+                  - const: 4
+              - items:
+                  - const: 1
+                  - const: 2
+        required:
+          - data-lanes
+          - link-frequencies
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - vana-supply
+  - vif-supply
+  - vdig-supply
+  - port
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/media/video-interfaces.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        camera-sensor@10 {
+            compatible = "sony,imx576";
+            reg = <0x10>;
+            clocks = <&imx576_clk>;
+            reset-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>;
+
+            vana-supply = <&vreg_l3p>;
+            vif-supply = <&vreg_l6p>;
+            vdig-supply = <&vreg_32m_cam_dvdd_1p05>;
+
+            orientation = <0>;
+            rotation = <90>;
+
+            port {
+                cam_out: endpoint {
+                   remote-endpoint = <&csiphy3_ep>;
+                   data-lanes = <1 2 3 4>;
+                   link-frequencies = /bits/ 64 <600000000>;
+                };
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index ff935e197c21..1b15fa355e8b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24856,6 +24856,13 @@ T:	git git://linuxtv.org/media.git
 F:	Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml
 F:	drivers/media/i2c/imx415.c
 
+SONY IMX576 SENSOR DRIVER
+M:	Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>
+M:	Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml
+
 SONY MEMORYSTICK SUBSYSTEM
 M:	Maxim Levitsky <maximlevitsky@gmail.com>
 M:	Alex Dubov <oakad@yahoo.com>
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 0/3] media: i2c: Add imx576 camera sensor driver
From: Himanshu Bhavani @ 2026-06-19 12:54 UTC (permalink / raw)
  To: sakari.ailus, luca.weiss
  Cc: Himanshu Bhavani, Hardevsinh Palaniya, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Hans Verkuil, Hans de Goede, Vladimir Zapolskiy,
	Elgin Perumbilly, Xiaolei Wang, Walter Werner Schneider,
	Kate Hsuan, Laurent Pinchart, Svyatoslav Ryhel, linux-media,
	devicetree, linux-kernel, linux-arm-msm

The following features are supported:
- Manual exposure an gain control support.
- vblank/hblank control support.
- Supported resolution: 2880 x 2156 30fps (SRGGB10)

This series depends on the SM6350 CAMSS support series
https://lore.kernel.org/linux-arm-msm/20260216-sm6350-camss-v4-0-b9df35f87edb@fairphone.com/

The driver has been tested on the mainline v7.0-rc6 kernel on the Fairphone 4 running postmarketOS.

fairphone-fp4:~$ v4l2-compliance -d /dev/v4l-subdev21
v4l2-compliance 1.32.0, 64 bits, 64-bit time_t

Compliance test for device /dev/v4l-subdev21:

Driver Info:
        Driver version   : 7.0.0
        Capabilities     : 0x00000000
        Client Capabilities: 0x0000000000000002
interval-uses-which
Required ioctls:
        test VIDIOC_SUDBEV_QUERYCAP: OK
        test invalid ioctls: OK

Allow for multiple opens:
        test second /dev/v4l-subdev21 open: OK
        test VIDIOC_SUBDEV_QUERYCAP: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

Control ioctls:
        test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
        test VIDIOC_QUERYCTRL: OK
        test VIDIOC_G/S_CTRL: OK
        test VIDIOC_G/S/TRY_EXT_CTRLS: OK
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 12 Private Controls: 0

Format ioctls:
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK (Not Supported)
        test VIDIOC_TRY_FMT: OK (Not Supported)
        test VIDIOC_S_FMT: OK (Not Supported)
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

Codec ioctls:
        test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
        test VIDIOC_G_ENC_INDEX: OK (Not Supported)
        test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
        test CREATE_BUFS maximum buffers: OK
        test VIDIOC_REMOVE_BUFS: OK
        test VIDIOC_EXPBUF: OK (Not Supported)
        test Requests: OK (Not Supported)
        test blocking wait: OK (Not Supported)

Total for device /dev/v4l-subdev21: 46, Succeeded: 46, Failed: 0, Warnings: 0

V1 -> V2

In Patch 1/3
- Rename regulator supplies to (vana, vdig, vif).

In Patch 2/3
- Rename link_freq array to avoid confusion with the link_freq control.
- Use IMX576_EXPOSURE_STEP in exposure control range update.
- Make cci_write() error handling consistent.
- Return imx576_set_pad_format() result instead of return 0.
- Initialize link_freq_index before creating the link frequency control.
- Replace dev_err() with dev_err_probe().
- Remove redundant comment.

In Patch 3/3
- Added the remaining supplies CSIPHYs (0-3).
- Add comment for camera orientation property.
- Move cam_mclk1_default{..} pinctrl definition to SoC SM6350 dtsi.

Hardevsinh Palaniya (2):
  dt-bindings: media: i2c: Add imx576 sensor
  arm64: dts: qcom: sm7225-fairphone-fp4: Add Sony IMX576 front camera
    support

Himanshu Bhavani (1):
  media: i2c: add imx576 image sensor driver

 .../bindings/media/i2c/sony,imx576.yaml       |  111 ++
 MAINTAINERS                                   |    8 +
 arch/arm64/boot/dts/qcom/sm6350.dtsi          |    7 +
 .../boot/dts/qcom/sm7225-fairphone-fp4.dts    |   53 +-
 drivers/media/i2c/Kconfig                     |   10 +
 drivers/media/i2c/Makefile                    |    1 +
 drivers/media/i2c/imx576.c                    | 1034 +++++++++++++++++
 7 files changed, 1223 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx576.yaml
 create mode 100644 drivers/media/i2c/imx576.c

--
2.34.1

^ permalink raw reply

* Re: [PATCH v4] dt-bindings: misc: convert lis302.txt to YAML
From: sashiko-bot @ 2026-06-19 12:53 UTC (permalink / raw)
  To: Jad Keskes; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260619124426.882626-1-inasj268@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The YAML binding erroneously forbids `Vdd-supply` and `Vdd_IO-supply` for the SPI variant by setting them to `false`.
--

commit 286d4c20f34dbb3740102063ad8a21275e5828b2
Author: Jad Keskes <inasj268@gmail.com>
dt-bindings: misc: convert lis302.txt to YAML

This commit converts the old LIS302 accelerometer plain text binding into a
YAML schema. It covers both I2C and SPI variants and retains deprecated
property names for backwards compatibility.

> diff --git a/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
> new file mode 100644
> index 0000000000000..c73371b754a1e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml

[ ... ]

> +allOf:
> +  - if:
> +      properties:
> +        compatible:
> +          not:
> +            contains:
> +              const: st,lis302dl-spi
> +    then:
> +      required:
> +        - Vdd-supply
> +        - Vdd_IO-supply
> +    else:
> +      properties:
> +        Vdd-supply: false
> +        Vdd_IO-supply: false

[Severity: Medium]
Does forbidding these power supplies for the SPI variant prevent accurate
hardware description?

The hardware physically requires Vdd and Vdd_IO power supplies to function,
regardless of whether it is accessed via I2C or SPI. Setting these
properties to false in the else branch explicitly forbids device tree
writers from modeling the physical regulators powering the SPI device,
which will cause valid hardware descriptions to fail dtbs_check schema
validation.

> +      required:
> +        - spi-max-frequency
> +        - interrupts

[ ... ]

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

^ permalink raw reply

* Re: [PATCH 0/6] arm64: dts: qcom: sc8280xp: set GPI DMA channels according to DSDT
From: Icenowy Zheng @ 2026-06-19 12:50 UTC (permalink / raw)
  To: Konrad Dybcio, Pengyu Luo
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <5621f70b-984e-4a65-add8-a9bf42e6c0c2@oss.qualcomm.com>

在 2026-06-19五的 14:27 +0200,Konrad Dybcio写道:
> On 6/18/26 12:34 PM, Icenowy Zheng wrote:
> > 在 2026-06-18四的 11:05 +0200,Konrad Dybcio写道:
> > > On 6/18/26 11:04 AM, Konrad Dybcio wrote:
> > > > On 6/9/26 5:54 PM, Icenowy Zheng wrote:
> > > > > 在 2026-06-09二的 14:23 +0200,Konrad Dybcio写道:
> > > > > > On 6/7/26 10:49 AM, Icenowy Zheng wrote:
> > > > > > > 在 2026-06-06六的 21:51 +0800,Pengyu Luo写道:
> > > > > > > > On Sat, Jun 6, 2026 at 9:21 PM Icenowy Zheng
> > > > > > > > <zhengxingda@iscas.ac.cn> wrote:
> > > > > > > > > 
> > > > > > > > > 在 2026-06-06六的 17:46 +0800,Pengyu Luo写道:
> > > > > > > > > > On 2026-06-06 17:28:35+08:00, Icenowy Zheng wrote:
> > > > > > > > > > > 在 2026-06-06六的 17:22 +0800,Pengyu Luo写道:
> > > > > > > > > > > 
> > > > > > > > > > > > On 2026-06-02 21:21:27+08:00, Icenowy Zheng
> > > > > > > > > > > > wrote:
> > > > > > > > > > > > 
> > > > > > > > > > > > The magnetic keyboard (USB HID) can't be
> > > > > > > > > > > > connected
> > > > > > > > > > > > somehow,
> > > > > > > > > > > > others
> > > > > > > > > > > > are
> > > > > > > > > > > > fine, such as the spi touchscreen (not upstream
> > > > > > > > > > > > yet),
> > > > > > > > > > > > which
> > > > > > > > > > > > utilizes
> > > > > > > > > > > > DMA definitely. My config is here
> > > > > > > > > > > > https://pastebin.com/SdjuyJYk
> > > > > > > > > > > 
> > > > > > > > > > > Is this a defconfig?
> > > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > Yes.
> > > > > > > > > > 
> > > > > > > > > > > BTW it seems that CONFIG_ASYNC_TX_DMA needs to be
> > > > > > > > > > > selected
> > > > > > > > > > > too
> > > > > > > > > > > for
> > > > > > > > > > > exhibiting the problem (because there should be
> > > > > > > > > > > "public"
> > > > > > > > > > > GPI
> > > > > > > > > > > DMA
> > > > > > > > > > > consumers to trigger the stuck/reset).
> > > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > Is this still necessary? I checked the fedora
> > > > > > > > > > discussion and
> > > > > > > > > > your
> > > > > > > > > > GPI
> > > > > > > > > > DMA fix. And GPI DMA is only for the QUP-supported
> > > > > > > > > > peripherals as
> > > > > > > > > > the
> > > > > > > > > > binding mentioned,
> > > > > > > > > > devicetree/bindings/dma/qcom,gpi.yaml
> > > > > > > > > 
> > > > > > > > > The devicetree without this fix seems to be still
> > > > > > > > > incorrect,
> > > > > > > > > because
> > > > > > > > > with the device tree fix even if the GPI DMA driver
> > > > > > > > > misbehaves
> > > > > > > > > the
> > > > > > > > > system won't be stuck (although it will iterate all
> > > > > > > > > GPI
> > > > > > > > > channels
> > > > > > > > > and
> > > > > > > > > then fail to function at all).
> > > > > > > > > 
> > > > > > > > 
> > > > > > > > Back to the start. You said some GPI interfaces aren't
> > > > > > > > available
> > > > > > > > to
> > > > > > > > HLOS, your mask is 0xb(0b1011), so I use 0x4(0b100) did
> > > > > > > > a
> > > > > > > > quick
> > > > > > > > test,
> > > > > > > > and spi6 consumed it, no stuck or reset. Could you give
> > > > > > > > me
> > > > > > > > a
> > > > > > > > unavailable channel?
> > > > > > > 
> > > > > > > I think channel 0b10000 of gpi_dma2 could be an example?
> > > > > > > 
> > > > > > > It seems that 4 channels are tried on gpi_dma2 before
> > > > > > > hang on
> > > > > > > my
> > > > > > > gaokun3, but as gaokun3 has no known serial access, it's
> > > > > > > possible
> > > > > > > that
> > > > > > > 0b100000 or 0b1000 is problematic.
> > > > > > > 
> > > > > > > (The reason gpi_dma2 is checked first is because it's the
> > > > > > > GPI
> > > > > > > DMA
> > > > > > > controller with the smallest address)
> > > > > > > 
> > > > > > > BTW I just took the values from Windows DSDT, which is
> > > > > > > quite
> > > > > > > conservative.
> > > > > > 
> > > > > > So, with DMA_PRIVATE set, is this series made redundant?
> > > > > 
> > > > > I assume technically the trustzone is still protecting some
> > > > > channels,
> > > > > although the system stuck issue is fixed.
> > > > > 
> > > > > This series should still be relevant, although not so
> > > > > emergent.
> > > > 
> > > > So now we're down to the case of the TZ reserving some of the
> > > > GPI
> > > > channels (presumably for locked down/TZ-driven QUPs) crashing
> > > > the
> > > > device on access, is that right?
> > > 
> > > i.e. now, is requesting these channels through (wrongfully)
> > > enabling
> > > the devices in DT the only remaining concern?
> > 
> > Yes, I think so; although I think few devices will use GPI on these
> > devices (usually only one or two SPI controllers according to the
> > DSDTs).
> 
> IIRC there's a configuration table that lets OEMs decide which ones
> should fall under the secure umbrella (although most never seem to
> change the defaults).

Ah then what's the default value?

Radxa Dragon Q8B seems to have GPII0-5 enabled for all GPI controllers
[1].

Thanks,
Icenowy

[1]
https://github.com/strongtz/linux-radxa-qcom/commit/99878a41264ef4f2a77783676de36a80de7103ba

> 
> I don't think we need to care too much about the mask being ultra-
> correct,
> since as we've established only QUPs are "valid" consumers and we're
> not
> going to enable them globally by default, since there are conflicting
> pin
> assignments (i.e. there are many more QUPs than allocated GPIOs)
> 
> Konrad


^ permalink raw reply

* [PATCH v4] dt-bindings: misc: convert lis302.txt to YAML
From: Jad Keskes @ 2026-06-19 12:44 UTC (permalink / raw)
  To: Eric Piel, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Jonathan Cameron, devicetree, linux-kernel, Jad Keskes
In-Reply-To: <20260619115649.840676-1-inasj268@gmail.com>

Replace the old lis302.txt with a YAML binding covering all four
compatibles (st,lis3lv02d, st,lis302dl-spi, st,lis331dlh,
st,lis33de) and their ~35 DT properties.

The old txt documented st,click-thresh-* and st,click-click-time-limit
but the code reads st,click-threshold-* and st,click-time-limit.
Keep the old names as deprecated so existing DTBs don't break.

Tested: dt_binding_check. dtbs_check against 7 omap/am335x DTBs
(am335x-evm, am335x-evmsk, am335x-pepper, am437x-sk-evm, omap3-n900,
omap3-n950, omap3-gta04a3) — no misc schema errors. Pre-existing
IIO schema errors on paired compatible nodes unchanged.

Signed-off-by: Jad Keskes <inasj268@gmail.com>
---

v4:
  - Drop explicit select block (redundant — dt-schema generates it from the compatible list automatically)
  - Fix commit message: select block does not prevent IIO schema validation
v3:
  - Add st,lis3lv02d to select block
  - Drop Patch 2 entirely, single patch with no IIO changes
v2:
  - Rebase onto Linux 7.1-rc6
  - Drop IIO changes
 .../devicetree/bindings/iio/accel/lis302.txt  | 119 ------
 .../bindings/misc/st,lis3lv02d.yaml           | 400 ++++++++++++++++++
 MAINTAINERS                                   |   1 +
 3 files changed, 401 insertions(+), 119 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/iio/accel/lis302.txt
 create mode 100644 Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml

diff --git a/Documentation/devicetree/bindings/iio/accel/lis302.txt b/Documentation/devicetree/bindings/iio/accel/lis302.txt
deleted file mode 100644
index 457539647f36..000000000000
--- a/Documentation/devicetree/bindings/iio/accel/lis302.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-LIS302 accelerometer devicetree bindings
-
-This device is matched via its bus drivers, and has a number of properties
-that apply in on the generic device (independent from the bus).
-
-
-Required properties for the SPI bindings:
- - compatible: 		should be set to "st,lis3lv02d-spi"
- - reg:			the chipselect index
- - spi-max-frequency:	maximal bus speed, should be set to 1000000 unless
-			constrained by external circuitry
- - interrupts:		the interrupt generated by the device
-
-Required properties for the I2C bindings:
- - compatible:		should be set to "st,lis3lv02d"
- - reg:			i2c slave address
- - Vdd-supply:		The input supply for Vdd
- - Vdd_IO-supply:	The input supply for Vdd_IO
-
-
-Optional properties for all bus drivers:
-
- - st,click-single-{x,y,z}:	if present, tells the device to issue an
-				interrupt on single click events on the
-				x/y/z axis.
- - st,click-double-{x,y,z}:	if present, tells the device to issue an
-				interrupt on double click events on the
-				x/y/z axis.
- - st,click-thresh-{x,y,z}:	set the x/y/z axis threshold
- - st,click-click-time-limit:	click time limit, from 0 to 127.5msec
-				with step of 0.5 msec
- - st,click-latency:		click latency, from 0 to 255 msec with
-				step of 1 msec.
- - st,click-window:		click window, from 0 to 255 msec with
-				step of 1 msec.
- - st,irq{1,2}-disable:		disable IRQ 1/2
- - st,irq{1,2}-ff-wu-1:		raise IRQ 1/2 on FF_WU_1 condition
- - st,irq{1,2}-ff-wu-2:		raise IRQ 1/2 on FF_WU_2 condition
- - st,irq{1,2}-data-ready:	raise IRQ 1/2 on data ready condition
- - st,irq{1,2}-click:		raise IRQ 1/2 on click condition
- - st,irq-open-drain:		consider IRQ lines open-drain
- - st,irq-active-low:		make IRQ lines active low
- - st,wu-duration-1:		duration register for Free-Fall/Wake-Up
-				interrupt 1
- - st,wu-duration-2:		duration register for Free-Fall/Wake-Up
-				interrupt 2
- - st,wakeup-{x,y,z}-{lo,hi}:	set wakeup condition on x/y/z axis for
-				upper/lower limit
- - st,wakeup-threshold:		set wakeup threshold
- - st,wakeup2-{x,y,z}-{lo,hi}:	set wakeup condition on x/y/z axis for
-				upper/lower limit for second wakeup
-				engine.
- - st,wakeup2-threshold:	set wakeup threshold for second wakeup
-				engine.
- - st,highpass-cutoff-hz=:	1, 2, 4 or 8 for 1Hz, 2Hz, 4Hz or 8Hz of
-				highpass cut-off frequency
- - st,hipass{1,2}-disable:	disable highpass 1/2.
- - st,default-rate=:		set the default rate
- - st,axis-{x,y,z}=:		set the axis to map to the three coordinates.
-				Negative values can be used for inverted axis.
- - st,{min,max}-limit-{x,y,z}	set the min/max limits for x/y/z axis
-				(used by self-test)
-
-
-Example for a SPI device node:
-
-	accelerometer@0 {
-		compatible = "st,lis302dl-spi";
-		reg = <0>;
-		spi-max-frequency = <1000000>;
-		interrupt-parent = <&gpio>;
-		interrupts = <104 0>;
-
-		st,click-single-x;
-		st,click-single-y;
-		st,click-single-z;
-		st,click-thresh-x = <10>;
-		st,click-thresh-y = <10>;
-		st,click-thresh-z = <10>;
-		st,irq1-click;
-		st,irq2-click;
-		st,wakeup-x-lo;
-		st,wakeup-x-hi;
-		st,wakeup-y-lo;
-		st,wakeup-y-hi;
-		st,wakeup-z-lo;
-		st,wakeup-z-hi;
-	};
-
-Example for a I2C device node:
-
-	lis331dlh: accelerometer@18 {
-		compatible = "st,lis331dlh", "st,lis3lv02d";
-		reg = <0x18>;
-		Vdd-supply = <&lis3_reg>;
-		Vdd_IO-supply = <&lis3_reg>;
-
-		st,click-single-x;
-		st,click-single-y;
-		st,click-single-z;
-		st,click-thresh-x = <10>;
-		st,click-thresh-y = <10>;
-		st,click-thresh-z = <10>;
-		st,irq1-click;
-		st,irq2-click;
-		st,wakeup-x-lo;
-		st,wakeup-x-hi;
-		st,wakeup-y-lo;
-		st,wakeup-y-hi;
-		st,wakeup-z-lo;
-		st,wakeup-z-hi;
-		st,min-limit-x = <120>;
-		st,min-limit-y = <120>;
-		st,min-limit-z = <140>;
-		st,max-limit-x = <550>;
-		st,max-limit-y = <550>;
-		st,max-limit-z = <750>;
-	};
-
diff --git a/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
new file mode 100644
index 000000000000..c73371b754a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
@@ -0,0 +1,400 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/misc/st,lis3lv02d.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics LIS3LV02D and similar accelerometers (misc driver)
+
+maintainers:
+  - Eric Piel <eric.piel@tremplin-utc.net>
+
+description:
+  This binding describes the STMicroelectronics accelerometers supported by
+  the misc/lis3lv02d driver. This driver provides input (joystick) and
+  hardware monitoring support, in contrast to the IIO st-accel driver which
+  also supports some of these devices.
+  Refer to Documentation/devicetree/bindings/iio/st,st-sensors.yaml for the
+  IIO binding.
+
+select:
+  anyOf:
+    - properties:
+        compatible:
+          contains:
+            const: st,lis302dl-spi
+    - properties:
+        compatible:
+          contains:
+            const: st,lis331dlh
+    - properties:
+        compatible:
+          contains:
+            const: st,lis33de
+    - properties:
+        compatible:
+          contains:
+            const: st,lis3lv02d
+  required:
+    - compatible
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - st,lis331dlh
+              - st,lis33de
+          - const: st,lis3lv02d
+      - const: st,lis331dlh
+      - const: st,lis3lv02d
+      - const: st,lis302dl-spi
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+
+  spi-max-frequency:
+    description: SPI bus frequency; should be set to 1000000 unless
+      constrained by external circuitry.
+    maximum: 1000000
+
+  Vdd-supply:
+    description: The input supply for Vdd.
+
+  Vdd_IO-supply:
+    description: The input supply for Vdd_IO.
+
+  st,click-single-x:
+    description: Issue an interrupt on single click events on the X axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-double-x:
+    description: Issue an interrupt on double click events on the X axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-single-y:
+    description: Issue an interrupt on single click events on the Y axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-double-y:
+    description: Issue an interrupt on double click events on the Y axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-single-z:
+    description: Issue an interrupt on single click events on the Z axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-double-z:
+    description: Issue an interrupt on double click events on the Z axis.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,click-thresh-x:
+    description: X axis click threshold (deprecated spelling, use st,click-threshold-x).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  st,click-thresh-y:
+    description: Y axis click threshold (deprecated spelling, use st,click-threshold-y).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  st,click-thresh-z:
+    description: Z axis click threshold (deprecated spelling, use st,click-threshold-z).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  st,click-threshold-x:
+    description: X axis click threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,click-threshold-y:
+    description: Y axis click threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,click-threshold-z:
+    description: Z axis click threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,click-click-time-limit:
+    description: Click time limit (deprecated spelling, use st,click-time-limit).
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+    deprecated: true
+
+  st,click-time-limit:
+    description: Click time limit, from 0 to 127.5 msec with step of 0.5 msec.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,click-latency:
+    description: Click latency, from 0 to 255 msec with step of 1 msec.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,click-window:
+    description: Click window, from 0 to 255 msec with step of 1 msec.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,irq1-disable:
+    description: Disable IRQ 1.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-ff-wu-1:
+    description: Raise IRQ 1 on FF_WU_1 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-ff-wu-2:
+    description: Raise IRQ 1 on FF_WU_2 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-data-ready:
+    description: Raise IRQ 1 on data ready condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq1-click:
+    description: Raise IRQ 1 on click condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-disable:
+    description: Disable IRQ 2.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-ff-wu-1:
+    description: Raise IRQ 2 on FF_WU_1 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-ff-wu-2:
+    description: Raise IRQ 2 on FF_WU_2 condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-data-ready:
+    description: Raise IRQ 2 on data ready condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq2-click:
+    description: Raise IRQ 2 on click condition.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq-open-drain:
+    description: Consider IRQ lines open-drain.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,irq-active-low:
+    description: Make IRQ lines active low.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wu-duration-1:
+    description: Duration register for Free-Fall/Wake-Up interrupt 1.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,wu-duration-2:
+    description: Duration register for Free-Fall/Wake-Up interrupt 2.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,wakeup-x-lo:
+    description: Set wakeup condition on X axis for lower limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-x-hi:
+    description: Set wakeup condition on X axis for upper limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-y-lo:
+    description: Set wakeup condition on Y axis for lower limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-y-hi:
+    description: Set wakeup condition on Y axis for upper limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-z-lo:
+    description: Set wakeup condition on Z axis for lower limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-z-hi:
+    description: Set wakeup condition on Z axis for upper limit.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup-threshold:
+    description: Set wakeup threshold.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,wakeup2-x-lo:
+    description: Set wakeup condition on X axis for lower limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-x-hi:
+    description: Set wakeup condition on X axis for upper limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-y-lo:
+    description: Set wakeup condition on Y axis for lower limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-y-hi:
+    description: Set wakeup condition on Y axis for upper limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-z-lo:
+    description: Set wakeup condition on Z axis for lower limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-z-hi:
+    description: Set wakeup condition on Z axis for upper limit for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,wakeup2-threshold:
+    description: Set wakeup threshold for second wakeup engine.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+
+  st,highpass-cutoff-hz:
+    description: Highpass cut-off frequency. Valid values are 1, 2, 4 or 8.
+    enum: [1, 2, 4, 8]
+
+  st,hipass1-disable:
+    description: Disable highpass filter 1.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,hipass2-disable:
+    description: Disable highpass filter 2.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  st,default-rate:
+    description: Set the default output data rate.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  st,axis-x:
+    description: Set the X axis mapping. Negative values can be used for inverted axis.
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,axis-y:
+    description: Set the Y axis mapping. Negative values can be used for inverted axis.
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,axis-z:
+    description: Set the Z axis mapping. Negative values can be used for inverted axis.
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,min-limit-x:
+    description: Minimum limit for X axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,min-limit-y:
+    description: Minimum limit for Y axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,min-limit-z:
+    description: Minimum limit for Z axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,max-limit-x:
+    description: Maximum limit for X axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,max-limit-y:
+    description: Maximum limit for Y axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+  st,max-limit-z:
+    description: Maximum limit for Z axis (used by self-test).
+    $ref: /schemas/types.yaml#/definitions/int32
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          not:
+            contains:
+              const: st,lis302dl-spi
+    then:
+      required:
+        - Vdd-supply
+        - Vdd_IO-supply
+    else:
+      properties:
+        Vdd-supply: false
+        Vdd_IO-supply: false
+      required:
+        - spi-max-frequency
+        - interrupts
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        accelerometer@18 {
+            compatible = "st,lis331dlh", "st,lis3lv02d";
+            reg = <0x18>;
+            Vdd-supply = <&lis3_reg>;
+            Vdd_IO-supply = <&lis3_reg>;
+            interrupt-parent = <&gpio2>;
+            interrupts = <18 0>;
+
+            st,click-single-x;
+            st,click-single-y;
+            st,click-single-z;
+            st,click-threshold-x = <10>;
+            st,click-threshold-y = <10>;
+            st,click-threshold-z = <10>;
+            st,irq1-click;
+            st,irq2-click;
+            st,wakeup-x-lo;
+            st,wakeup-x-hi;
+            st,wakeup-y-lo;
+            st,wakeup-y-hi;
+            st,wakeup-z-lo;
+            st,wakeup-z-hi;
+            st,min-limit-x = <120>;
+            st,min-limit-y = <120>;
+            st,min-limit-z = <140>;
+            st,max-limit-x = <550>;
+            st,max-limit-y = <550>;
+            st,max-limit-z = <750>;
+        };
+    };
+  - |
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        accelerometer@0 {
+            compatible = "st,lis302dl-spi";
+            reg = <0>;
+            spi-max-frequency = <1000000>;
+            interrupt-parent = <&gpio>;
+            interrupts = <104 0>;
+
+            st,click-single-x;
+            st,click-single-y;
+            st,click-single-z;
+            st,click-threshold-x = <10>;
+            st,click-threshold-y = <10>;
+            st,click-threshold-z = <10>;
+            st,irq1-click;
+            st,irq2-click;
+            st,wakeup-x-lo;
+            st,wakeup-x-hi;
+            st,wakeup-y-lo;
+            st,wakeup-y-hi;
+            st,wakeup-z-lo;
+            st,wakeup-z-hi;
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ec290e38b44..4cffabbabf0e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14858,6 +14858,7 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/
 LIS3LV02D ACCELEROMETER DRIVER
 M:	Eric Piel <eric.piel@tremplin-utc.net>
 S:	Maintained
+F:	Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
 F:	Documentation/misc-devices/lis3lv02d.rst
 F:	drivers/misc/lis3lv02d/
 F:	drivers/platform/x86/hp/hp_accel.c
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH v10 2/2] media: i2c: add Himax HM1246 image sensor driver
From: sashiko-bot @ 2026-06-19 12:42 UTC (permalink / raw)
  To: Matthias Fend; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260619-hm1246-v10-2-d88e431a6c11@emfend.at>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Incorrect validation of `pm_runtime_get_if_active()` return value allows unpowered hardware access and causes an unbalanced `pm_runtime_put()` decrement.
- [High] The driver fails to update the active subdev state format when flip controls change the Bayer layout.
- [High] Integer overflow in 32-bit PLL VCO computation results in erroneously validating broken hardware configurations.
- [Medium] Flawed nested loops in PLL calculation prevent finding valid dividers by breaking prematurely.
- [Medium] Logic error in PLL multiplier calculation skips valid configurations.
- [Medium] Unprotected concurrent access to clustered control values during TRY pad operations.
--

commit a1e846fd762489ac057abc081793eb13dea90d9f
Author: Matthias Fend <matthias.fend@emfend.at>

media: i2c: add Himax HM1246 image sensor driver

This commit adds a V4L2 sub-device driver for the Himax HM1246-AWD image
sensor. It operates the sensor in raw mode and bypasses the internal ISP.

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

[ ... ]

> +/* Get the format code of the mode considering current flip setting. */
> +static u32 hm1246_get_format_code(struct hm1246 *hm1246,
> +				  const struct hm1246_mode *hm1246_mode)
> +{
> +	return hm1246_mode->codes[FLIP_FORMAT_INDEX(hm1246->vflip_ctrl->val,
> +						    hm1246->hflip_ctrl->val)];
> +}

[Severity: Medium]
Could this result in unprotected concurrent access to clustered control values?

When invoked during pad operations (like VIDIOC_SUBDEV_ENUM_MBUS_CODE) acting
on the V4L2_SUBDEV_FORMAT_TRY state, the lock held is the file handle's TRY
state lock, not the control handler lock.

Accessing hm1246->vflip_ctrl->val and hm1246->hflip_ctrl->val directly
without holding v4l2_ctrl_lock(hm1246->ctrls.lock) allows a data race with
concurrent VIDIOC_S_CTRL calls, potentially resulting in reading a
torn/inconsistent set of flip values and exposing incorrect Bayer patterns.

[ ... ]

> +	/* Find suitable PCLK and SYSCLK dividers. */
> +	for (pclk_div_index = 0; pclk_div_index < ARRAY_SIZE(pclk_div_table);
> +	     pclk_div_index++) {
> +		for (sysclk_div_index = 0;
> +		     sysclk_div_index < ARRAY_SIZE(sysclk_div_table);
> +		     sysclk_div_index++) {
> +			if (sysclk_div_table[sysclk_div_index] *
> +				    sysclk_pclk_ratio ==
> +			    pclk_div_table[pclk_div_index]) {
> +				sysclk_pclk_ratio_found = true;
> +				break;
> +			}
> +		}
> +		if (sysclk_pclk_ratio_found)
> +			break;

[Severity: Medium]
Will this break prematurely without checking other valid combinations?

Breaking immediately upon finding the first valid sysclk_pclk_ratio locks
pclk_div to the first match. If this specific divider cannot satisfy the
subsequent VCO constraint limits (vco_out between 360M and 680M), the
function returns -EINVAL instead of trying other valid pclk_div combinations.

> +	}
> +
> +	if (!sysclk_pclk_ratio_found)
> +		return -EINVAL;
> +
> +	/* Determine an appropriate post divider. */
> +	for (post_div_index = 0; post_div_index < ARRAY_SIZE(post_div_table);
> +	     post_div_index++) {
> +		vco_out = pclk * pclk_div_table[pclk_div_index] *
> +			  post_div_table[post_div_index];

[Severity: High]
Can this overflow the 32-bit vco_out variable?

For higher link frequencies (e.g., link_freq = 96M giving pclk = 192M),
combined with a pclk_div of 6 and a post_div of 8, the mathematical product
is 9,216,000,000. This exceeds the 32-bit limit and overflows to 626,065,408.

Because 626M happens to fall within the valid VCO constraints [360M, 680M],
the driver improperly accepts this completely invalid setup.

> +
> +		if (vco_out >= HM1246_PLL_VCO_MIN &&
> +		    vco_out <= HM1246_PLL_VCO_MAX)
> +			break;
> +	}
> +	if (post_div_index >= ARRAY_SIZE(post_div_table))
> +		return -EINVAL;
> +
> +	/* Find pre-divider and multiplier values. */
> +	for (u32 div = DIV_ROUND_UP(xclk, HM1246_PLL_INCLK_MAX);
> +	     div <= xclk / HM1246_PLL_INCLK_MIN; div++) {
> +		u32 multi, multi_h, multi_l, vco;
> +
> +		multi = DIV_ROUND_CLOSEST_ULL((u64)vco_out * div, xclk);
> +		if (multi < HM1246_PLL_MULTI_MIN ||
> +		    multi > HM1246_PLL_MULTI_MAX)
> +			continue;
> +
> +		multi_h = multi / (HM1246_PLL_MULTI_H_MIN *
> +				   HM1246_PLL_MULTI_L_MAX) +
> +			  2;
> +		multi_l = multi / multi_h;

[Severity: Medium]
Does this logic mistakenly skip valid configurations when multi is exactly 512?

If the required overall multiplier multi is exactly 512, this formula
calculates multi_h as 512 / 512 + 2 = 3. It then sets multi_l = 512 / 3 = 170.
The product is 3 * 170 = 510, which triggers the if (vco != vco_out)
rejection.

However, a multiplier of exactly 512 is valid and achievable with multi_h = 2
and multi_l = 256.

[ ... ]

> +	if (ctrl->id == V4L2_CID_VBLANK) {
> +		s64 exposure_max;
> +
> +		exposure_max =
> +			format->height + ctrl->val - HM1246_COARSE_INTG_MARGIN;
> +		ret = __v4l2_ctrl_modify_range(hm1246->exposure_ctrl,
> +					       hm1246->exposure_ctrl->minimum,
> +					       exposure_max,
> +					       hm1246->exposure_ctrl->step,
> +					       exposure_max);
> +
> +		if (ret) {
> +			dev_err(hm1246->dev, "exposure ctrl range update failed\n");
> +			return ret;
> +		}
> +	}
> +
> +	if (!pm_runtime_get_if_active(hm1246->dev))
> +		return 0;

[Severity: High]
Does this check allow execution to continue on negative error codes?

pm_runtime_get_if_active() returns 1 if the device is active, 0 if it is not
active, and a negative error code (e.g., -EINVAL) if Runtime PM is disabled.

Because of the logical NOT, negative error codes evaluate to false, allowing
execution to bypass the return 0 check. This allows the driver to proceed
with hardware accesses while the device may be unpowered, and leads to an
unmatched pm_runtime_put() at the end of the function.

> +
> +	ret = 0;
> +	switch (ctrl->id) {
> +	case V4L2_CID_EXPOSURE:
> +		cci_write(hm1246->regmap, HM1246_COARSE_INTG_REG, ctrl->val,
> +			  &ret);
> +		break;
> +
> +	case V4L2_CID_ANALOGUE_GAIN:
> +		cci_write(hm1246->regmap, HM1246_ANALOG_GLOBAL_GAIN_REG,
> +			  ctrl->val, &ret);
> +		break;
> +
> +	case V4L2_CID_VBLANK:
> +		val = format->height + ctrl->val;
> +		cci_write(hm1246->regmap, HM1246_FRAME_LENGTH_LINES_REG, val,
> +			  &ret);
> +		break;
> +
> +	case V4L2_CID_HFLIP:
> +	case V4L2_CID_VFLIP:

[Severity: High]
Does this omission break format negotiation and video pipeline link validation?

The driver registers the V4L2_CID_HFLIP and V4L2_CID_VFLIP controls with the
V4L2_CTRL_FLAG_MODIFY_LAYOUT flag. While the hardware orientation registers
are updated, the format code in the subdevice's active state is not updated
to reflect the new Bayer pattern.

Subsequent calls to the VIDIOC_SUBDEV_G_FMT ioctl will return the stale
Bayer format preserved in the state.

> +		val = 0;
> +		if (hm1246->hflip_ctrl->val)
> +			val |= HM1246_IMAGE_ORIENTATION_HFLIP;
> +		if (hm1246->vflip_ctrl->val)
> +			val |= HM1246_IMAGE_ORIENTATION_VFLIP;
> +
> +		cci_write(hm1246->regmap, HM1246_IMAGE_ORIENTATION_REG, val,
> +			  &ret);
> +		break;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260619-hm1246-v10-0-d88e431a6c11@emfend.at?part=2

^ permalink raw reply

* Re: [PATCH v3] dt-bindings: misc: convert lis302.txt to YAML
From: sashiko-bot @ 2026-06-19 12:39 UTC (permalink / raw)
  To: Jad Keskes; +Cc: robh, conor+dt, devicetree
In-Reply-To: <20260619122446.867091-1-inasj268@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Redundant 'select' block fails its stated purpose in the commit message
--

commit 7b1f6ec4590fb8fea27ae6accf9a20a8de12ccd1
Author: Jad Keskes <inasj268@gmail.com>

dt-bindings: misc: convert lis302.txt to YAML

Replace the old lis302.txt with a YAML binding covering four compatibles.
The commit message states it includes a select block to avoid validating
nodes against both the misc and IIO schemas.

> Use a select block that matches only nodes with misc-driver
> compatibles (including standalone st,lis3lv02d for omap3-n950-n9
> and similar), paired with the IIO schema which handles the IIO
> side. This avoids both schemas validating the same node.

[Severity: Medium]
Does this select block actually prevent the IIO schema from validating
the node?

In the dt-schema architecture, schemas evaluate independently. A select
block in this misc schema only determines if this specific schema applies;
it has no effect on whether the IIO schema also matches the compatible
string.

The testing note mentioning "Pre-existing IIO schema errors on paired
compatible nodes unchanged" seems to confirm both schemas are still
validating the node.

> diff --git a/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
> new file mode 100644
> index 0000000000000..c73371b754a1e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/st,lis3lv02d.yaml
[ ... ]
> +select:
> +  anyOf:
> +    - properties:
> +        compatible:
> +          contains:
> +            const: st,lis302dl-spi
> +    - properties:
> +        compatible:
> +          contains:
> +            const: st,lis331dlh
> +    - properties:
> +        compatible:
> +          contains:
> +            const: st,lis33de
> +    - properties:
> +        compatible:
> +          contains:
> +            const: st,lis3lv02d
> +  required:
> +    - compatible

[Severity: Medium]
Is this explicit select block necessary?

Since this block exactly mirrors the default select block automatically
generated by dt-schema from the compatible property definition below it,
could this be removed entirely to simplify the binding?

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

^ permalink raw reply

* Re: [PATCH v8 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Konrad Dybcio @ 2026-06-19 12:37 UTC (permalink / raw)
  To: Dmitry Baryshkov, Vijay Kumar Tumati
  Cc: Bryan O'Donoghue, Vladimir Zapolskiy, Bryan O'Donoghue,
	Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Neil Armstrong, linux-arm-msm,
	linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <qt2d2anvwlubaicwhw3rur7u47v4swqbctapcw5qek54f2yzdu@ljd46avkfgy4>

On 6/10/26 12:30 AM, Dmitry Baryshkov wrote:
> On Tue, Jun 09, 2026 at 12:20:56PM -0700, Vijay Kumar Tumati wrote:
>>
>>
>> On 6/9/2026 6:56 AM, Konrad Dybcio wrote:
>>> On 6/4/26 11:06 AM, Bryan O'Donoghue wrote:
>>>> On 04/06/2026 09:46, Vladimir Zapolskiy wrote:
>>>>> On 6/4/26 03:30, Bryan O'Donoghue wrote:
>>>>>> On 04/06/2026 01:07, Vladimir Zapolskiy wrote:
>>>>>>> On 6/4/26 00:18, Bryan O'Donoghue wrote:
>>>>>>>> On 03/06/2026 21:51, Vladimir Zapolskiy wrote:
>>>>>>>>>> Actually, one more thing, Why isn't TITAN TOP GDSC here?>>>> +
>>>>>>>>> If CSIPHYs are true subdevices under the umbrella CAMSS device and well
>>>>>>>>> described as subnodes, then likely none of power domains are needed
>>> [...]
>>>
>>>>> CCI is not described as a child of CAMSS, here the situation is different.
>>>> CCI probably_should_ be a child of CAMSS given the design we are going for here.
>>> Yes
>> As of now CCI is an independently usable device to configure any I2C slave
>> that is connected to it. If it is to become a child of camss, it should be
>> self contained, as it is now, and camss may have to become a simple-mfd to
>> make the CCI independently probe-able? In which case, we may want to follow
>> the same protocol for all other sub devices like PHY. However, if we do not
>> have any requirement to use CCI independently (who can confirm this?),
> 
> Uno-Q uses CCI as a semi-independent i2c controller. There can be other
> similar designs.

CCI still physically lies within the camera subsystem and needs both the
TOP_GDSC and the AHB/CPAS clocks to be on.

devm_of_platform_populate() will ensure that subdevices will be probed.
simple-mfd is essentially a hack/shortcut to call that function for nodes
which aren't bound to drivers (e.g. because they represent something
without a top-level software interface, which is rarely true and why it
seems to be discouraged)

Konrad

^ permalink raw reply

* Re: [PATCH 1/2] arm64: dts: qcom: sc8280xp: Add camera MCLK pinctrl
From: Konrad Dybcio @ 2026-06-19 12:35 UTC (permalink / raw)
  To: Pengyu Luo
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vladimir Zapolskiy, linux-arm-msm, devicetree,
	linux-kernel
In-Reply-To: <CAH2e8h7aGiF1g_LgG4WxEj1eGbUp-T_U-yZVpoHgU8FsMOrWTg@mail.gmail.com>

On 6/11/26 7:29 AM, Pengyu Luo wrote:
> On Tue, Jun 9, 2026 at 8:17 PM Konrad Dybcio
> <konrad.dybcio@oss.qualcomm.com> wrote:
>>
>> On 6/7/26 6:04 PM, Pengyu Luo wrote:
>>> Define pinctrl definitions to enable camera master clocks on sc8280xp.
>>>
>>> Suggested-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
>>> Signed-off-by: Pengyu Luo <mitltlatltl@gmail.com>
>>> ---
>>>  arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 56 ++++++++++++++++++++++++++
>>>  1 file changed, 56 insertions(+)
>>>
>>> diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
>>> index a2bd6b10e475..0dbcd3069a3b 100644
>>> --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
>>> +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
>>> @@ -5484,6 +5484,62 @@ tlmm: pinctrl@f100000 {
>>>                       gpio-ranges = <&tlmm 0 0 230>;
>>>                       wakeup-parent = <&pdc>;
>>>
>>> +                     cam_mclk0_default: cam-mclk0-default-state {
>>> +                             pins = "gpio119";
>>> +                             function = "cam_mclk";
>>> +                             drive-strength = <6>;
>>
>> Other platforms set this to 2 by default.
>>
>> What's the value set on Windows when the camera is in use?
>>
> 
> It is 6mA.
> 
> Let us get ctl_reg first on Windows
> 
> lkd> !dd f111000 L8
> # f111000 00000284 00000002 000000e2 00000000
> # f111010 00000001 00000801 00000000 00000000
> 
> ctl_reg => 0x284
> 
> in msm_gpio_dbg_show_one()
> ...
> drive = (ctl_reg >> g->drv_bit) & 7; // (0x284 >> 6) & 7 == 2
> ...
> seq_printf(s, " %dmA", msm_regval_to_drive(drive)); // (drive + 1) * 2 == 6;
> ...
> 
> x13s should be the same as gaokun3 in this part.

I confirmed as much and I'm willing to believe this is a default for
all 8280 devices

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

for the second patch, please mention in the commit message that the value
will now match windows and please add a fixes tag

Konrad

^ permalink raw reply

* Re: [PATCH RFC v7 0/9] firmware: arm_scmi: vendors: Qualcomm Generic Vendor Extensions
From: Pragnesh Papaniya @ 2026-06-19 12:31 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: Cristian Marussi, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sibi Sankar, MyungJoo Ham, Kyungmin Park, Chanwoo Choi,
	Dmitry Osipenko, Thierry Reding, Jonathan Hunter, Bjorn Andersson,
	Konrad Dybcio, Rajendra Nayak, Pankaj Patil, linux-arm-msm,
	linux-kernel, arm-scmi, linux-arm-kernel, devicetree, linux-pm,
	linux-tegra, Amir Vajid, Ramakrishna Gottimukkula
In-Reply-To: <20260616-responsible-junglefowl-of-chaos-7eda7d@sudeepholla>



On 16-Jun-26 1:57 PM, Sudeep Holla wrote:
> On Wed, Jun 10, 2026 at 02:21:27PM +0530, Pragnesh Papaniya wrote:
>> The QCOM SCMI vendor protocol provides a generic way of exposing a number of
>> Qualcomm SoC specific features (like memory bus scaling) through a mixture of
>> pre-determined algorithm strings and param_id pairs hosted on the SCMI
>> controller. On Qualcomm Glymur and Hamoa SoCs, the memlat governor and the
>> mechanism to control the various caches and RAM is hosted on the CPU Control
>> Processor (CPUCP) and the method to tweak and start the governor is exposed
>> through the QCOM SCMI Generic Extension Protocol.
>>
>> This series introduces the devfreq SCMI client driver that uses the MEMLAT
>> algorithm string hosted on the QCOM SCMI Generic Extension Protocol to detect
>> memory latency workloads and control frequency/level of the various memory
>> buses (DDR/LLCC/DDR_QOS). DDR/LLCC/DDR_QOS are modelled as devfreq devices
>> using the remote devfreq governor. This provides basic insight into device
>> operation via trans_stat and lets userspace further tweak the parameters of
>> the remote governor.
>>
>> trans_stat data for DDR/LLCC/DDR_QOS is now available with this series:
>>
>>      From  :   To
>>    315000000 479000000 545000000 725000000 840000000  959000000 1090000000 1211000000   time(ms)
>>    315000000:         0         3         6         6         6         7         0        30    143956
>>    479000000:         2         0         7         1         1         1         0         3       356
>>    545000000:         7         6         0         5         5         0         0        10      1200
>>    725000000:         3         0         5         0         6         1         0         6      2172
>>    840000000:         8         2         3         2         0         4         0        12      1188
>>    959000000:         3         0         1         2         2         0         0        13       272
>>   1090000000:         0         0         0         0         0         0         0         0         0
>>   1211000000:        35         4        11         5        11         8         0         0     21684
>> Total transition : 253
>>
>> QCOM SCMI Generic Vendor protocol background:
>> A lot of the vendor protocol numbers used internally were for
>> debug/internal development purposes that were either highly SoC-specific
>> or had to be disabled because some features were fused out during
>> production. This led to a large number of vendor protocol numbers being
>> quickly consumed and never released. Using a single generic vendor
>> protocol with functionality abstracted behind algorithm strings gives us
>> the flexibility of letting such functionality exist during initial
>> development/debugging while still being able to expose mature features
>> (like MEMLAT) once they have stabilised. The param_ids are expected to
>> act as ABI for algorithm strings like MEMLAT.
>>
> 
> Not sure if it was discussed in the previous versions or not, it would be
> good if you can capture why some of bus scaling doesn't work with the existing
> SCMI performance protocol and the monitors don't fit the MPAM mode.
> 
> Please capture them in 1/9 as a motivation for this vendor protocol. It will
> then help to understand it better as I am still struggling to. Sorry for that.

Thanks for the input!

SCMI perf protocol exports perf domains to kernel where kernel can set
the frequency but here the scaling governor runs on the SCP while kernel
just observes frequency changes made by remote governor. While MPAM is
not enabled/supported on all hardware (Hamoa). Here's the pseudo-code
for remote governor on CPUCP to help you understand more:

Barebone Memlat Pseudocode:
Every sample window, get snapshot of latest AMU counters from each CPU and scale all the memory according to the map_table:

For each CPU
    // Calculate IPM ( Instruction retired / cache miss count (L2 cache refills for LLCC voting and CPU RD miss counter for DDR))
    If (IPM < IPM_CEIL)
        Use CPU cycle counter to determine CPU frequency in the past N milliseconds

LLCC_freq = lookup_llcc_freq(cpu_freq_max)
DDR_freq = lookup_ddr_freq(cpu_freq_max)	
DDR_QOS_freq = lookup_ddr_qos_freq(cpu_freq_max)

// Scale all memories
Scale_freq(Memory); // LLCC/DDR/DDR_QOS

> 

^ permalink raw reply

* [PATCH v10 2/2] media: i2c: add Himax HM1246 image sensor driver
From: Matthias Fend @ 2026-06-19 12:28 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Hans Verkuil, Sakari Ailus, Hans de Goede,
	Ricardo Ribalda, André Apitzsch, Tarang Raval,
	Andy Shevchenko, Benjamin Mugnier, Sylvain Petinot, Dongcheng Yan,
	Bryan O'Donoghue, Alan Stern, Jingjing Xiong,
	Heimir Thor Sverrisson, Mehdi Djait, Vladimir Zapolskiy,
	Laurent Pinchart, Hardevsinh Palaniya, Svyatoslav Ryhel,
	Philipp Zabel, Hans Verkuil, Hans de Goede, Xiaolei Wang,
	Walter Werner Schneider, Kate Hsuan, Bartosz Golaszewski,
	Miguel Vadillo
  Cc: linux-media, devicetree, linux-kernel, Hao Yao, Himanshu Bhavani,
	Matthias Fend
In-Reply-To: <20260619-hm1246-v10-0-d88e431a6c11@emfend.at>

Add a V4L2 sub-device driver for Himax HM1246 image sensor.

The Himax HM1246-AWD is a 1/3.7-Inch CMOS image sensor SoC with an active
array size of 1296 x 976. It is programmable through an I2C interface and
connected via parallel bus.

The sensor has an internal ISP with a complete image processing pipeline
including control loops. However, this driver uses the sensor in raw mode
and the entire ISP is bypassed.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Matthias Fend <matthias.fend@emfend.at>
---
 MAINTAINERS                |    1 +
 drivers/media/i2c/Kconfig  |   10 +
 drivers/media/i2c/Makefile |    1 +
 drivers/media/i2c/hm1246.c | 1291 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1303 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c320e7e9a2bd88319945bfe1202bc891d35f0f7c..ca13a5b21306e921e077e2548f6242041c6ee24c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11558,6 +11558,7 @@ M:	Matthias Fend <matthias.fend@emfend.at>
 L:	linux-media@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/media/i2c/himax,hm1246.yaml
+F:	drivers/media/i2c/hm1246.c
 
 HIMAX HX83112B TOUCHSCREEN SUPPORT
 M:	Job Noorman <job@noorman.info>
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5d173e0ecf424f2f204f8d426be818e44357f8e4..52398bad32a0989c40097524ee9dde04e76813b8 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -137,6 +137,16 @@ config VIDEO_HI847
           To compile this driver as a module, choose M here: the
           module will be called hi847.
 
+config VIDEO_HM1246
+	tristate "Himax HM1246 sensor support"
+	select V4L2_CCI_I2C
+	help
+	  This is a Video4Linux2 sensor driver for the Himax
+	  HM1246 camera.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hm1246.
+
 config VIDEO_IMX111
 	tristate "Sony IMX111 sensor support"
 	select V4L2_CCI_I2C
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index e45359efe0e41e13e3c0869e5ead7d6cf4aca3a7..df420ff4e1d6304ef62f9cd84c8ddb9e2db30a11 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_VIDEO_GC2145) += gc2145.o
 obj-$(CONFIG_VIDEO_HI556) += hi556.o
 obj-$(CONFIG_VIDEO_HI846) += hi846.o
 obj-$(CONFIG_VIDEO_HI847) += hi847.o
+obj-$(CONFIG_VIDEO_HM1246) += hm1246.o
 obj-$(CONFIG_VIDEO_I2C) += video-i2c.o
 obj-$(CONFIG_VIDEO_IMX111) += imx111.o
 obj-$(CONFIG_VIDEO_IMX208) += imx208.o
diff --git a/drivers/media/i2c/hm1246.c b/drivers/media/i2c/hm1246.c
new file mode 100644
index 0000000000000000000000000000000000000000..ba120967814f3b2b4a5d2d6b1b6e4f5e5139944f
--- /dev/null
+++ b/drivers/media/i2c/hm1246.c
@@ -0,0 +1,1291 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Himax HM1246 image sensor
+ *
+ * Copyright 2026 Matthias Fend <matthias.fend@emfend.at>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/limits.h>
+#include <linux/math.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+#include <linux/units.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-cci.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+/* Status registers */
+#define HM1246_MODEL_ID_REG		 CCI_REG16(0x0000)
+
+/* General setup registers */
+#define HM1246_MODE_SELECT_REG		 CCI_REG8(0x0100)
+#define HM1246_MODE_SELECT_STANDBY	 0x00
+#define HM1246_MODE_SELECT_STREAM	 0x01
+#define HM1246_MODE_SELECT_STOP		 0x02
+#define HM1246_IMAGE_ORIENTATION_REG	 CCI_REG8(0x0101)
+#define HM1246_IMAGE_ORIENTATION_VFLIP	 BIT(1)
+#define HM1246_IMAGE_ORIENTATION_HFLIP	 BIT(0)
+#define HM1246_CMU_UPDATE_REG		 CCI_REG8(0x0104)
+
+/* Output setup registers */
+#define HM1246_COARSE_INTG_REG		 CCI_REG16(0x0202)
+#define HM1246_ANALOG_GLOBAL_GAIN_REG	 CCI_REG8(0x0205)
+
+/* Clock setup registers */
+#define HM1246_PLL1CFG_REG		 CCI_REG8(0x0303)
+#define HM1246_PLL1CFG_MULTIPLIER(x)	 (((x) & 0xff) << 0)
+#define HM1246_PLL2CFG_REG		 CCI_REG8(0x0305)
+#define HM1246_PLL2CFG_PRE_DIV(x)	 (((x) & 0x1f) << 1)
+#define HM1246_PLL2CFG_MULTIPLIER(x)	 (((x) & 0x01) << 0)
+#define HM1246_PLL3CFG_REG		 CCI_REG8(0x0307)
+#define HM1246_PLL3CFG_POST_DIV(x)	 (((x) & 0x3) << 6)
+#define HM1246_PLL3CFG_SYSCLK_DIV(x)	 (((x) & 0x3) << 4)
+#define HM1246_PLL3CFG_PCLK_DIV(x)	 (((x) & 0x7) << 0)
+
+/* Frame timing registers */
+#define HM1246_FRAME_LENGTH_LINES_REG	 CCI_REG16(0x0340)
+#define HM1246_LINE_LENGTH_PCK_REG	 CCI_REG16(0x0342)
+
+/* Image size registers */
+#define HM1246_X_ADDR_START_REG		 CCI_REG16(0x0344)
+#define HM1246_Y_ADDR_START_REG		 CCI_REG16(0x0346)
+#define HM1246_X_ADDR_END_REG		 CCI_REG16(0x0348)
+#define HM1246_Y_ADDR_END_REG		 CCI_REG16(0x034a)
+#define HM1246_X_LA_START_REG		 CCI_REG16(0x0351)
+#define HM1246_X_LA_END_REG		 CCI_REG16(0x0353)
+#define HM1246_Y_LA_START_REG		 CCI_REG16(0x0355)
+#define HM1246_Y_LA_END_REG		 CCI_REG16(0x0357)
+
+/* Test pattern registers */
+#define HM1246_TEST_PATTERN_MODE_REG	 CCI_REG8(0x0601)
+#define HM1246_TEST_PATTERN_MODE_MODE(x) (((x) & 0xf) << 4)
+#define HM1246_TEST_PATTERN_MODE_ENABLE	 BIT(0)
+#define HM1246_TEST_DATA_BLUE_REG	 CCI_REG16(0x0602)
+#define HM1246_TEST_DATA_GB_REG		 CCI_REG16(0x0604)
+#define HM1246_TEST_DATA_RED_REG	 CCI_REG16(0x0606)
+#define HM1246_TEST_DATA_GR_REG		 CCI_REG16(0x0608)
+
+/* SBC registers */
+#define HM1246_SBC_BOOT_REF2_REG	 CCI_REG8(0x2001)
+#define HM1246_SBC_BOOT_REF2_PLL_LOCK	 BIT(4)
+#define HM1246_SBC_CTRL_REG		 CCI_REG8(0x2003)
+#define HM1246_SBC_CTRL_PLL_EN		 BIT(0)
+
+/* System registers */
+#define HM1246_OUTPUT_PRT_CTRL_REG	 CCI_REG8(0x2f02)
+#define HM1246_POLARITY_CTRL_REG	 CCI_REG8(0x2f20)
+#define HM1246_POLARITY_CTRL_HSYNC	 BIT(7)
+#define HM1246_POLARITY_CTRL_VSYNC	 BIT(6)
+#define HM1246_PCLK_CTRL_REG		 CCI_REG8(0x2f24)
+#define HM1246_PCLK_CTRL_POL		 BIT(3)
+
+/* Digital window control & parameter registers */
+#define HM1246_DWIN_XOFFSET_REG		 CCI_REG16(0xd5e4)
+#define HM1246_DWIN_XSIZE_REG		 CCI_REG16(0xd5e6)
+#define HM1246_DWIN_YOFFSET_REG		 CCI_REG16(0xd5e8)
+#define HM1246_DWIN_YSIZE_REG		 CCI_REG16(0xd5ea)
+
+#define HM1246_MODEL_ID			 0x1245
+
+#define HM1246_NATIVE_WIDTH		 1296
+#define HM1246_NATIVE_HEIGHT		 976
+
+#define HM1246_VTS_MAX			 65535
+
+#define HM1246_COARSE_INTG_MARGIN	 2
+#define HM1246_COARSE_INTG_MIN		 4
+#define HM1246_COARSE_INTG_STEP		 1
+
+#define HM1246_ANALOG_GLOBAL_GAIN_MIN	 0x00
+#define HM1246_ANALOG_GLOBAL_GAIN_MAX	 0xe8
+#define HM1246_ANALOG_GLOBAL_GAIN_STEP	 0x01
+
+#define HM1246_XCLK_MIN			 (6 * HZ_PER_MHZ)
+#define HM1246_XCLK_MAX			 (27 * HZ_PER_MHZ)
+
+#define HM1246_PCLK_MIN			 (8 * HZ_PER_MHZ)
+#define HM1246_PCLK_MAX			 (96 * HZ_PER_MHZ)
+
+#define HM1246_PLL_VCO_MIN		 (360 * HZ_PER_MHZ)
+#define HM1246_PLL_VCO_MAX		 (680 * HZ_PER_MHZ)
+
+#define HM1246_PLL_INCLK_MIN		 (1000 * HZ_PER_KHZ)
+#define HM1246_PLL_INCLK_MAX		 (2500 * HZ_PER_KHZ)
+
+#define HM1246_PLL_MULTI_L_MIN		 1
+#define HM1246_PLL_MULTI_L_MAX		 256
+
+#define HM1246_PLL_MULTI_H_MIN		 2
+#define HM1246_PLL_MULTI_H_MAX		 3
+
+#define HM1246_PLL_MULTI_MIN \
+	(HM1246_PLL_MULTI_H_MIN * HM1246_PLL_MULTI_L_MIN)
+#define HM1246_PLL_MULTI_MAX \
+	(HM1246_PLL_MULTI_H_MAX * HM1246_PLL_MULTI_L_MAX)
+
+static const char *const hm1246_test_pattern_menu[] = {
+	"Disabled",
+	"Checkboard",
+	"Ramp",
+	"Moving ones",
+	"Blending color bars",
+	"Color bars",
+	"Solid white",
+	"Solid black",
+	"Solid red",
+	"Solid green",
+	"Solid blue",
+};
+
+static const char *const hm1246_supply_names[] = {
+	"avdd",
+	"iovdd",
+	"dvdd",
+};
+
+struct hm1246 {
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	struct device *dev;
+
+	struct regulator_bulk_data supplies[ARRAY_SIZE(hm1246_supply_names)];
+	struct clk *xclk;
+	unsigned long xclk_freq;
+	struct reset_control *reset;
+	unsigned int mbus_flags;
+	s64 link_frequency;
+
+	struct v4l2_ctrl_handler ctrls;
+	struct v4l2_ctrl *exposure_ctrl;
+	struct v4l2_ctrl *hflip_ctrl;
+	struct v4l2_ctrl *vflip_ctrl;
+
+	struct regmap *regmap;
+
+	bool identified;
+};
+
+static const struct cci_reg_sequence mode_1296x976_raw[] = {
+	{ HM1246_X_LA_START_REG, 60 },
+	{ HM1246_X_LA_END_REG, 1355 },
+	{ HM1246_Y_LA_START_REG, 0 },
+	{ HM1246_Y_LA_END_REG, 975 },
+	{ HM1246_OUTPUT_PRT_CTRL_REG, 0x20 },
+	{ CCI_REG8(0x300a), 0x01 },
+	{ CCI_REG8(0x300b), 0x00 },
+	{ CCI_REG8(0x50f5), 0x01 },
+	{ CCI_REG8(0x50dd), 0x00 },
+	{ CCI_REG8(0x50a1), 0x02 },
+	{ CCI_REG8(0x50aa), 0x1c },
+	{ CCI_REG8(0x50ac), 0xdd },
+	{ CCI_REG8(0x50ad), 0x08 },
+	{ CCI_REG8(0x50ab), 0x04 },
+	{ CCI_REG8(0x50a0), 0x40 },
+	{ CCI_REG8(0x50a2), 0x12 },
+	{ CCI_REG8(0x50ae), 0x30 },
+	{ CCI_REG8(0x50b3), 0x04 },
+	{ CCI_REG8(0x5204), 0x40 },
+	{ CCI_REG8(0x5208), 0x55 },
+	{ CCI_REG8(0x520b), 0x05 },
+	{ CCI_REG8(0x520d), 0x40 },
+	{ CCI_REG8(0x5214), 0x18 },
+	{ CCI_REG8(0x5215), 0x0f },
+	{ CCI_REG8(0x5217), 0x01 },
+	{ CCI_REG8(0x5218), 0x07 },
+	{ CCI_REG8(0x5219), 0x01 },
+	{ CCI_REG8(0x521a), 0x50 },
+	{ CCI_REG8(0x521b), 0x24 },
+	{ CCI_REG8(0x5232), 0x01 },
+	{ CCI_REG8(0x5220), 0x11 },
+	{ CCI_REG8(0x5227), 0x01 },
+	{ CCI_REG8(0x5106), 0xc1 },
+	{ CCI_REG8(0x5115), 0xc0 },
+	{ CCI_REG8(0x5116), 0xc1 },
+	{ CCI_REG8(0x5138), 0x40 },
+	{ CCI_REG8(0x5139), 0x60 },
+	{ CCI_REG8(0x513a), 0x80 },
+	{ CCI_REG8(0x513b), 0xa0 },
+	{ CCI_REG8(0x513c), 0xa1 },
+	{ CCI_REG8(0x513d), 0xa2 },
+	{ CCI_REG8(0x513e), 0xa3 },
+	{ CCI_REG8(0x5140), 0x40 },
+	{ CCI_REG8(0x5141), 0x60 },
+	{ CCI_REG8(0x5142), 0x80 },
+	{ CCI_REG8(0x5143), 0x81 },
+	{ CCI_REG8(0x5144), 0x82 },
+	{ CCI_REG8(0x5145), 0x83 },
+	{ CCI_REG8(0x5146), 0x93 },
+	{ CCI_REG8(0x51c1), 0xc3 },
+	{ CCI_REG8(0x51c5), 0xc3 },
+	{ CCI_REG8(0x51c9), 0xc3 },
+	{ CCI_REG8(0x51cd), 0xc2 },
+	{ CCI_REG8(0x51d1), 0xc1 },
+	{ CCI_REG8(0x51d5), 0xc1 },
+	{ CCI_REG8(0x51d9), 0x81 },
+	{ CCI_REG8(0x51dd), 0x81 },
+	{ CCI_REG8(0x51c2), 0x49 },
+	{ CCI_REG8(0x51c6), 0x49 },
+	{ CCI_REG8(0x51ca), 0x49 },
+	{ CCI_REG8(0x51ce), 0x49 },
+	{ CCI_REG8(0x51d2), 0x49 },
+	{ CCI_REG8(0x51d6), 0x59 },
+	{ CCI_REG8(0x51da), 0x59 },
+	{ CCI_REG8(0x51de), 0x59 },
+	{ CCI_REG8(0x51c3), 0x20 },
+	{ CCI_REG8(0x51c7), 0x38 },
+	{ CCI_REG8(0x51cb), 0x21 },
+	{ CCI_REG8(0x51cf), 0x11 },
+	{ CCI_REG8(0x51d3), 0x11 },
+	{ CCI_REG8(0x51d7), 0x13 },
+	{ CCI_REG8(0x51db), 0x13 },
+	{ CCI_REG8(0x51df), 0x13 },
+	{ CCI_REG8(0x51e0), 0x03 },
+	{ CCI_REG8(0x51e2), 0x03 },
+	{ CCI_REG8(0x51f0), 0x42 },
+	{ CCI_REG8(0x51f1), 0x40 },
+	{ CCI_REG8(0x51f2), 0x4a },
+	{ CCI_REG8(0x51f3), 0x48 },
+	{ CCI_REG8(0x5015), 0x73 },
+	{ CCI_REG8(0x504a), 0x04 },
+	{ CCI_REG8(0x5044), 0x07 },
+	{ CCI_REG8(0x5040), 0x03 },
+	{ CCI_REG8(0x5135), 0xc4 },
+	{ CCI_REG8(0x5136), 0xc5 },
+	{ CCI_REG8(0x5166), 0xc4 },
+	{ CCI_REG8(0x5196), 0xc4 },
+	{ CCI_REG8(0x51c0), 0x10 },
+	{ CCI_REG8(0x51c4), 0x10 },
+	{ CCI_REG8(0x51c8), 0xa0 },
+	{ CCI_REG8(0x51cc), 0xa0 },
+	{ CCI_REG8(0x51d0), 0xa1 },
+	{ CCI_REG8(0x51d4), 0xa5 },
+	{ CCI_REG8(0x51d8), 0xa5 },
+	{ CCI_REG8(0x51dc), 0xa5 },
+	{ CCI_REG8(0x5200), 0xe4 },
+	{ CCI_REG8(0x5209), 0x04 },
+	{ CCI_REG8(0x301b), 0x01 },
+	{ CCI_REG8(0x3130), 0x01 },
+	{ CCI_REG8(0x5013), 0x07 },
+	{ CCI_REG8(0x5016), 0x01 },
+	{ CCI_REG8(0x501d), 0x50 },
+	{ CCI_REG8(0x0350), 0xfe },
+	{ CCI_REG8(0x2f03), 0x15 },
+	{ CCI_REG8(0xd380), 0x00 },
+	{ CCI_REG8(0x3047), 0x7f },
+	{ CCI_REG8(0x304d), 0x34 },
+	{ CCI_REG8(0x3041), 0x4b },
+	{ CCI_REG8(0x3042), 0x2d },
+	{ CCI_REG8(0x3056), 0x64 },
+	{ CCI_REG8(0x3059), 0x1e },
+	{ CCI_REG8(0x305e), 0x10 },
+	{ CCI_REG8(0x305f), 0x10 },
+	{ CCI_REG8(0x306d), 0x10 },
+	{ CCI_REG8(0x306e), 0x0c },
+	{ CCI_REG8(0x3064), 0x50 },
+	{ CCI_REG8(0x3067), 0x78 },
+	{ CCI_REG8(0x3068), 0x4b },
+	{ CCI_REG8(0x306a), 0x78 },
+	{ CCI_REG8(0x306b), 0x4b },
+	{ CCI_REG8(0xd442), 0x3d },
+	{ CCI_REG8(0xd443), 0x06 },
+	{ CCI_REG8(0xd440), 0x63 },
+	{ CCI_REG8(0xd446), 0xb0 },
+	{ CCI_REG8(0xd447), 0x60 },
+	{ CCI_REG8(0xd448), 0x48 },
+	{ CCI_REG8(0xd449), 0x30 },
+	{ CCI_REG8(0xd44a), 0x18 },
+	{ CCI_REG8(0xd360), 0x03 },
+	{ CCI_REG8(0x30ac), 0x10 },
+	{ CCI_REG8(0x30ad), 0x10 },
+	{ CCI_REG8(0x30ae), 0x10 },
+	{ CCI_REG8(0x3040), 0x0b },
+	{ CCI_REG8(0x2002), 0x00 },
+	{ CCI_REG8(0x2000), 0x08 },
+};
+
+struct hm1246_reg_list {
+	u32 num_of_regs;
+	const struct cci_reg_sequence *regs;
+};
+
+struct hm1246_mode {
+	u32 codes[4];
+	u32 clocks_per_pixel;
+	struct v4l2_rect rect;
+	u32 hts;
+	u32 vts_min;
+	const struct hm1246_reg_list reg_list;
+};
+
+#define FLIP_FORMAT_INDEX(v, h) ((v ? 2 : 0) | (h ? 1 : 0))
+
+/* Get the format code of the mode considering current flip setting. */
+static u32 hm1246_get_format_code(struct hm1246 *hm1246,
+				  const struct hm1246_mode *hm1246_mode)
+{
+	return hm1246_mode->codes[FLIP_FORMAT_INDEX(hm1246->vflip_ctrl->val,
+						    hm1246->hflip_ctrl->val)];
+}
+
+static const struct hm1246_mode hm1246_modes[] = {
+	{
+		.codes = {
+			[FLIP_FORMAT_INDEX(0, 0)] = MEDIA_BUS_FMT_SBGGR10_1X10,
+			[FLIP_FORMAT_INDEX(0, 1)] = MEDIA_BUS_FMT_SGBRG10_1X10,
+			[FLIP_FORMAT_INDEX(1, 0)] = MEDIA_BUS_FMT_SGRBG10_1X10,
+			[FLIP_FORMAT_INDEX(1, 1)] = MEDIA_BUS_FMT_SRGGB10_1X10,
+		},
+		.clocks_per_pixel = 1,
+		.rect.top = 0,
+		.rect.left = 0,
+		.rect.width = 1296,
+		.rect.height = 976,
+		.hts = 1420,
+		.vts_min = 990,
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mode_1296x976_raw),
+			.regs = mode_1296x976_raw,
+		},
+	},
+};
+
+static inline struct hm1246 *to_hm1246(struct v4l2_subdev *sd)
+{
+	return container_of_const(sd, struct hm1246, sd);
+}
+
+static const struct hm1246_mode *
+hm1246_find_mode_by_mbus_code(struct hm1246 *hm1246, u32 code)
+{
+	for (unsigned int i = 0; i < ARRAY_SIZE(hm1246_modes); i++) {
+		if (code == hm1246_get_format_code(hm1246, &hm1246_modes[i]))
+			return &hm1246_modes[i];
+	}
+
+	return NULL;
+}
+
+static int hm1246_power_on(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct hm1246 *hm1246 = to_hm1246(sd);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(hm1246_supply_names),
+				    hm1246->supplies);
+	if (ret) {
+		dev_err(hm1246->dev, "failed to enable regulators\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hm1246->xclk);
+	if (ret) {
+		regulator_bulk_disable(ARRAY_SIZE(hm1246_supply_names),
+				       hm1246->supplies);
+		dev_err(hm1246->dev, "failed to enable clock\n");
+		return ret;
+	}
+
+	reset_control_deassert(hm1246->reset);
+
+	/*
+	 * XSHUTDOWN to crystal clock oscillation (tcrystal):  650us (typical)
+	 * Sample bootstrap pin (tsample):                    2000us (maximum)
+	 * Built in self test (tbist):                        3000us (maximum)
+	 */
+	fsleep(6 * USEC_PER_MSEC);
+
+	return 0;
+}
+
+static int hm1246_power_off(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct hm1246 *hm1246 = to_hm1246(sd);
+
+	reset_control_assert(hm1246->reset);
+
+	clk_disable_unprepare(hm1246->xclk);
+
+	regulator_bulk_disable(ARRAY_SIZE(hm1246_supply_names),
+			       hm1246->supplies);
+
+	return 0;
+}
+
+static int hm1246_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *sd_state,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct hm1246 *hm1246 = to_hm1246(sd);
+
+	if (code->index >= ARRAY_SIZE(hm1246_modes))
+		return -EINVAL;
+
+	code->code = hm1246_get_format_code(hm1246, &hm1246_modes[code->index]);
+
+	return 0;
+}
+
+static int hm1246_enum_frame_size(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct hm1246 *hm1246 = to_hm1246(subdev);
+	const struct hm1246_mode *mode;
+
+	if (fse->index > 0)
+		return -EINVAL;
+
+	mode = hm1246_find_mode_by_mbus_code(hm1246, fse->code);
+	if (!mode)
+		return -EINVAL;
+
+	fse->min_width = mode->rect.width;
+	fse->max_width = mode->rect.width;
+	fse->min_height = mode->rect.height;
+	fse->max_height = mode->rect.height;
+
+	return 0;
+}
+
+static void hm1246_update_pad_format(struct hm1246 *hm1246,
+				     const struct hm1246_mode *hm1246_mode,
+				     struct v4l2_mbus_framefmt *fmt)
+{
+	fmt->width = hm1246_mode->rect.width;
+	fmt->height = hm1246_mode->rect.height;
+	fmt->code = hm1246_get_format_code(hm1246, hm1246_mode);
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->colorspace = V4L2_COLORSPACE_RAW;
+	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
+}
+
+static int hm1246_set_format(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_state *state,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct hm1246 *hm1246 = to_hm1246(sd);
+	struct v4l2_mbus_framefmt *mbus_fmt;
+	struct v4l2_rect *crop;
+	const struct hm1246_mode *mode;
+
+	mode = hm1246_find_mode_by_mbus_code(hm1246, fmt->format.code);
+	if (!mode)
+		mode = &hm1246_modes[0];
+
+	crop = v4l2_subdev_state_get_crop(state, 0);
+	*crop = mode->rect;
+
+	hm1246_update_pad_format(hm1246, mode, &fmt->format);
+	mbus_fmt = v4l2_subdev_state_get_format(state, 0);
+	*mbus_fmt = fmt->format;
+
+	return 0;
+}
+
+static int hm1246_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_state *state,
+				struct v4l2_subdev_selection *sel)
+{
+	const struct v4l2_mbus_framefmt *format;
+	const struct hm1246_mode *mode;
+
+	format = v4l2_subdev_state_get_format(state, 0);
+	mode = v4l2_find_nearest_size(hm1246_modes, ARRAY_SIZE(hm1246_modes),
+				      rect.width, rect.height, format->width,
+				      format->height);
+
+	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 = HM1246_NATIVE_WIDTH;
+		sel->r.height = HM1246_NATIVE_HEIGHT;
+		return 0;
+
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r = mode->rect;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hm1246_init_state(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_state *state)
+{
+	struct hm1246 *hm1246 = to_hm1246(sd);
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_TRY,
+		.pad = 0,
+		.format = {
+			.code = hm1246_get_format_code(hm1246,
+						       &hm1246_modes[0]),
+			.width = hm1246_modes[0].rect.width,
+			.height = hm1246_modes[0].rect.height,
+		},
+	};
+
+	hm1246_set_format(sd, state, &fmt);
+
+	return 0;
+}
+
+static int hm1246_calc_pll(u32 xclk, u32 link_freq, u32 clocks_per_pixel,
+			   u8 *pll1, u8 *pll2, u8 *pll3)
+{
+	static const u8 pclk_div_table[] = { 4, 5, 6, 7, 8, 12, 14, 16 };
+	static const u8 sysclk_div_table[] = { 1, 2, 3, 4 };
+	static const u8 post_div_table[] = { 1, 2, 4, 8 };
+	static const int sysclk_pclk_ratio = 3; /* Recommended value */
+	u32 pclk, vco_out;
+	int pclk_div_index, sysclk_div_index, post_div_index;
+	bool sysclk_pclk_ratio_found = false;
+
+	if (link_freq < HM1246_PCLK_MIN || link_freq > HM1246_PCLK_MAX)
+		return -EINVAL;
+
+	/*
+	 * In raw mode (1 pixel per clock) the pixel clock is internally
+	 * divided by two.
+	 */
+	pclk = 2 * link_freq / clocks_per_pixel;
+
+	/* Find suitable PCLK and SYSCLK dividers. */
+	for (pclk_div_index = 0; pclk_div_index < ARRAY_SIZE(pclk_div_table);
+	     pclk_div_index++) {
+		for (sysclk_div_index = 0;
+		     sysclk_div_index < ARRAY_SIZE(sysclk_div_table);
+		     sysclk_div_index++) {
+			if (sysclk_div_table[sysclk_div_index] *
+				    sysclk_pclk_ratio ==
+			    pclk_div_table[pclk_div_index]) {
+				sysclk_pclk_ratio_found = true;
+				break;
+			}
+		}
+		if (sysclk_pclk_ratio_found)
+			break;
+	}
+
+	if (!sysclk_pclk_ratio_found)
+		return -EINVAL;
+
+	/* Determine an appropriate post divider. */
+	for (post_div_index = 0; post_div_index < ARRAY_SIZE(post_div_table);
+	     post_div_index++) {
+		vco_out = pclk * pclk_div_table[pclk_div_index] *
+			  post_div_table[post_div_index];
+
+		if (vco_out >= HM1246_PLL_VCO_MIN &&
+		    vco_out <= HM1246_PLL_VCO_MAX)
+			break;
+	}
+	if (post_div_index >= ARRAY_SIZE(post_div_table))
+		return -EINVAL;
+
+	/* Find pre-divider and multiplier values. */
+	for (u32 div = DIV_ROUND_UP(xclk, HM1246_PLL_INCLK_MAX);
+	     div <= xclk / HM1246_PLL_INCLK_MIN; div++) {
+		u32 multi, multi_h, multi_l, vco;
+
+		multi = DIV_ROUND_CLOSEST_ULL((u64)vco_out * div, xclk);
+		if (multi < HM1246_PLL_MULTI_MIN ||
+		    multi > HM1246_PLL_MULTI_MAX)
+			continue;
+
+		multi_h = multi / (HM1246_PLL_MULTI_H_MIN *
+				   HM1246_PLL_MULTI_L_MAX) +
+			  2;
+		multi_l = multi / multi_h;
+		vco = div_u64((u64)xclk * multi_h * multi_l, div);
+
+		if (vco != vco_out)
+			continue;
+
+		if (pll1 && pll2 && pll3) {
+			*pll1 = HM1246_PLL1CFG_MULTIPLIER(multi_l - 1);
+			*pll2 = HM1246_PLL2CFG_PRE_DIV(div - 1) |
+				HM1246_PLL2CFG_MULTIPLIER(multi_h - 2);
+			*pll3 = HM1246_PLL3CFG_POST_DIV(post_div_index) |
+				HM1246_PLL3CFG_SYSCLK_DIV(sysclk_div_index) |
+				HM1246_PLL3CFG_PCLK_DIV(pclk_div_index);
+		}
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int hm1246_cci_write_pll(struct hm1246 *hm1246, u8 pll1, u8 pll2,
+				u8 pll3)
+{
+	const struct cci_reg_sequence pll_regs[] = {
+		{ HM1246_PLL1CFG_REG, pll1 },
+		{ HM1246_PLL2CFG_REG, pll2 },
+		{ HM1246_PLL3CFG_REG, pll3 },
+		{ HM1246_SBC_CTRL_REG, HM1246_SBC_CTRL_PLL_EN },
+	};
+
+	return cci_multi_reg_write(hm1246->regmap, pll_regs,
+				   ARRAY_SIZE(pll_regs), NULL);
+}
+
+static int hm1246_pll_check_locked(struct hm1246 *hm1246)
+{
+	u64 boot_ref2;
+	int ret;
+
+	ret = cci_read(hm1246->regmap, HM1246_SBC_BOOT_REF2_REG, &boot_ref2,
+		       NULL);
+	if (ret)
+		return ret;
+
+	return (boot_ref2 & HM1246_SBC_BOOT_REF2_PLL_LOCK) ? 0 : -EIO;
+}
+
+static int hm1246_setup_pll(struct hm1246 *hm1246,
+			    const struct hm1246_mode *mode)
+{
+	u8 pll1, pll2, pll3;
+	int ret;
+
+	ret = hm1246_calc_pll(hm1246->xclk_freq, hm1246->link_frequency,
+			      mode->clocks_per_pixel, &pll1, &pll2, &pll3);
+	if (ret)
+		return ret;
+
+	ret = hm1246_cci_write_pll(hm1246, pll1, pll2, pll3);
+	if (ret)
+		return ret;
+
+	/* PLL lock time (tpll): 100us (typical) */
+	fsleep(200);
+
+	return hm1246_pll_check_locked(hm1246);
+}
+
+static int hm1246_cci_write_test_pattern(struct hm1246 *hm1246, u8 mode,
+					 u16 r, u16 g, u16 b)
+{
+	const struct cci_reg_sequence tpg_enable_regs[] = {
+		{ HM1246_TEST_DATA_RED_REG, r },
+		{ HM1246_TEST_DATA_GR_REG, g },
+		{ HM1246_TEST_DATA_GB_REG, g },
+		{ HM1246_TEST_DATA_BLUE_REG, b },
+		{ HM1246_TEST_PATTERN_MODE_REG, mode },
+	};
+
+	return cci_multi_reg_write(hm1246->regmap, tpg_enable_regs,
+				   ARRAY_SIZE(tpg_enable_regs), NULL);
+}
+
+static int hm1246_test_pattern(struct hm1246 *hm1246, u32 index)
+{
+	static const u16 RGBMIN = 0, RGBMAX = 0x3ff;
+	static const struct tp {
+		int pattern;
+		u16 r, g, b;
+	} tps[] = {
+		/* Disabled */
+		[0] = { .pattern = 0, .r = RGBMIN, .g = RGBMIN, .b = RGBMIN },
+		/* Checkboard pattern */
+		[1] = { .pattern = 0, .r = RGBMIN, .g = RGBMIN, .b = RGBMIN },
+		/* Ramp */
+		[2] = { .pattern = 1, .r = RGBMIN, .g = RGBMIN, .b = RGBMIN },
+		/* Moving ones */
+		[3] = { .pattern = 2, .r = RGBMIN, .g = RGBMIN, .b = RGBMIN },
+		/* Blending color bars */
+		[4] = { .pattern = 3, .r = RGBMIN, .g = RGBMIN, .b = RGBMIN },
+		/* Color bars */
+		[5] = { .pattern = 4, .r = RGBMIN, .g = RGBMIN, .b = RGBMIN },
+		/* Solid white */
+		[6] = { .pattern = 15, .r = RGBMAX, .g = RGBMAX, .b = RGBMAX },
+		/* Solid black */
+		[7] = { .pattern = 15, .r = RGBMIN, .g = RGBMIN, .b = RGBMIN },
+		/* Solid red */
+		[8] = { .pattern = 15, .r = RGBMAX, .g = RGBMIN, .b = RGBMIN },
+		/* Solid green */
+		[9] = { .pattern = 15, .r = RGBMIN, .g = RGBMAX, .b = RGBMIN },
+		/* Solid blue */
+		[10] = { .pattern = 15, .r = RGBMIN, .g = RGBMIN, .b = RGBMAX },
+	};
+	u8 mode;
+
+	if (index >= ARRAY_SIZE(tps))
+		return -EINVAL;
+
+	mode = HM1246_TEST_PATTERN_MODE_MODE(tps[index].pattern);
+	if (index)
+		mode |= HM1246_TEST_PATTERN_MODE_ENABLE;
+
+	return hm1246_cci_write_test_pattern(hm1246, mode, tps[index].r,
+					     tps[index].g, tps[index].b);
+}
+
+static int hm1246_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct hm1246 *hm1246 =
+		container_of_const(ctrl->handler, struct hm1246, ctrls);
+	struct v4l2_subdev_state *state;
+	const struct v4l2_mbus_framefmt *format;
+	u32 val;
+	bool needs_cmu_update = true;
+	int ret;
+
+	state = v4l2_subdev_get_locked_active_state(&hm1246->sd);
+	format = v4l2_subdev_state_get_format(state, 0);
+
+	if (ctrl->id == V4L2_CID_VBLANK) {
+		s64 exposure_max;
+
+		exposure_max =
+			format->height + ctrl->val - HM1246_COARSE_INTG_MARGIN;
+		ret = __v4l2_ctrl_modify_range(hm1246->exposure_ctrl,
+					       hm1246->exposure_ctrl->minimum,
+					       exposure_max,
+					       hm1246->exposure_ctrl->step,
+					       exposure_max);
+
+		if (ret) {
+			dev_err(hm1246->dev, "exposure ctrl range update failed\n");
+			return ret;
+		}
+	}
+
+	if (!pm_runtime_get_if_active(hm1246->dev))
+		return 0;
+
+	ret = 0;
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		cci_write(hm1246->regmap, HM1246_COARSE_INTG_REG, ctrl->val,
+			  &ret);
+		break;
+
+	case V4L2_CID_ANALOGUE_GAIN:
+		cci_write(hm1246->regmap, HM1246_ANALOG_GLOBAL_GAIN_REG,
+			  ctrl->val, &ret);
+		break;
+
+	case V4L2_CID_VBLANK:
+		val = format->height + ctrl->val;
+		cci_write(hm1246->regmap, HM1246_FRAME_LENGTH_LINES_REG, val,
+			  &ret);
+		break;
+
+	case V4L2_CID_HFLIP:
+	case V4L2_CID_VFLIP:
+		val = 0;
+		if (hm1246->hflip_ctrl->val)
+			val |= HM1246_IMAGE_ORIENTATION_HFLIP;
+		if (hm1246->vflip_ctrl->val)
+			val |= HM1246_IMAGE_ORIENTATION_VFLIP;
+
+		cci_write(hm1246->regmap, HM1246_IMAGE_ORIENTATION_REG, val,
+			  &ret);
+		break;
+
+	case V4L2_CID_TEST_PATTERN:
+		ret = hm1246_test_pattern(hm1246, ctrl->val);
+		needs_cmu_update = false;
+		break;
+
+	default:
+		ret = -EINVAL;
+		needs_cmu_update = false;
+		break;
+	}
+
+	if (needs_cmu_update)
+		cci_write(hm1246->regmap, HM1246_CMU_UPDATE_REG, 0, &ret);
+
+	pm_runtime_put(hm1246->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops hm1246_ctrl_ops = {
+	.s_ctrl = hm1246_set_ctrl,
+};
+
+static int hm1246_identify_module(struct hm1246 *hm1246)
+{
+	u64 model_id;
+	int ret;
+
+	if (hm1246->identified)
+		return 0;
+
+	ret = cci_read(hm1246->regmap, HM1246_MODEL_ID_REG, &model_id, NULL);
+	if (ret)
+		return ret;
+
+	if (model_id != HM1246_MODEL_ID) {
+		dev_err(hm1246->dev, "model id mismatch: 0x%llx!=0x%x\n",
+			model_id, HM1246_MODEL_ID);
+		return -ENXIO;
+	}
+
+	hm1246->identified = true;
+
+	return 0;
+}
+
+static int hm1246_setup_moderegs(struct hm1246 *hm1246,
+				 const struct hm1246_mode *mode)
+{
+	const struct hm1246_reg_list *reg_list = &mode->reg_list;
+	const struct cci_reg_sequence modeaw[] = {
+		{ HM1246_X_ADDR_START_REG, mode->rect.left },
+		{ HM1246_Y_ADDR_START_REG, mode->rect.top },
+		{ HM1246_X_ADDR_END_REG, mode->rect.width - 1 },
+		{ HM1246_Y_ADDR_END_REG, mode->rect.height - 1 },
+		{ HM1246_DWIN_XOFFSET_REG, mode->rect.left },
+		{ HM1246_DWIN_YOFFSET_REG, mode->rect.top },
+		{ HM1246_DWIN_XSIZE_REG, mode->rect.width },
+		{ HM1246_DWIN_YSIZE_REG, mode->rect.height },
+		{ HM1246_LINE_LENGTH_PCK_REG, mode->hts },
+	};
+	int ret = 0;
+
+	cci_multi_reg_write(hm1246->regmap, modeaw, ARRAY_SIZE(modeaw), &ret);
+	cci_multi_reg_write(hm1246->regmap, reg_list->regs,
+			    reg_list->num_of_regs, &ret);
+
+	return ret;
+}
+
+static int hm1246_setup_bus(struct hm1246 *hm1246)
+{
+	u64 polarity_ctrl = 0, pclk_ctrl = 0;
+	int ret = 0;
+
+	if (hm1246->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+		polarity_ctrl |= HM1246_POLARITY_CTRL_HSYNC;
+
+	if (hm1246->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+		polarity_ctrl |= HM1246_POLARITY_CTRL_VSYNC;
+
+	cci_write(hm1246->regmap, HM1246_POLARITY_CTRL_REG, polarity_ctrl,
+		  &ret);
+
+	/*
+	 * If the clock output polarity flag PCLK_CTRL[3] is set (high), the
+	 * data lines change state on the falling edge of PCLK and should
+	 * therefore be sampled on the rising edge.
+	 * This is different than described in the data sheet.
+	 */
+	if (hm1246->mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+		pclk_ctrl |= HM1246_PCLK_CTRL_POL;
+
+	cci_write(hm1246->regmap, HM1246_PCLK_CTRL_REG, pclk_ctrl, &ret);
+
+	return ret;
+}
+
+static int hm1246_enable_streams(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *state, u32 pad,
+				 u64 streams_mask)
+{
+	struct hm1246 *hm1246 = to_hm1246(sd);
+	const struct v4l2_mbus_framefmt *format;
+	const struct hm1246_mode *mode;
+	int ret;
+
+	format = v4l2_subdev_state_get_format(state, 0);
+	mode = v4l2_find_nearest_size(hm1246_modes, ARRAY_SIZE(hm1246_modes),
+				      rect.width, rect.height, format->width,
+				      format->height);
+
+	ret = pm_runtime_resume_and_get(hm1246->dev);
+	if (ret)
+		return ret;
+
+	ret = hm1246_identify_module(hm1246);
+	if (ret)
+		goto err_rpm_put;
+
+	ret = hm1246_setup_pll(hm1246, mode);
+	if (ret) {
+		dev_err(hm1246->dev, "failed to setup PLL\n");
+		goto err_rpm_put;
+	}
+
+	ret = hm1246_setup_moderegs(hm1246, mode);
+	if (ret)
+		goto err_rpm_put;
+
+	ret = hm1246_setup_bus(hm1246);
+	if (ret)
+		goto err_rpm_put;
+
+	ret = __v4l2_ctrl_handler_setup(&hm1246->ctrls);
+	if (ret) {
+		dev_err(hm1246->dev, "failed to setup v4l2 controls\n");
+		goto err_rpm_put;
+	}
+
+	ret = cci_write(hm1246->regmap, HM1246_MODE_SELECT_REG,
+			HM1246_MODE_SELECT_STREAM, NULL);
+	if (ret)
+		goto err_rpm_put;
+
+	/*
+	 * Since mirroring may change the actual pixel format, it must not be
+	 * changed during streaming.
+	 */
+	__v4l2_ctrl_grab(hm1246->vflip_ctrl, true);
+	__v4l2_ctrl_grab(hm1246->hflip_ctrl, true);
+
+	return 0;
+
+err_rpm_put:
+	pm_runtime_put_autosuspend(hm1246->dev);
+
+	return ret;
+}
+
+static int hm1246_disable_streams(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state, u32 pad,
+				  u64 streams_mask)
+{
+	struct hm1246 *hm1246 = to_hm1246(sd);
+	int ret;
+
+	ret = cci_write(hm1246->regmap, HM1246_MODE_SELECT_REG,
+			HM1246_MODE_SELECT_STANDBY, NULL);
+
+	__v4l2_ctrl_grab(hm1246->vflip_ctrl, false);
+	__v4l2_ctrl_grab(hm1246->hflip_ctrl, false);
+
+	pm_runtime_put_autosuspend(hm1246->dev);
+
+	return ret;
+}
+
+static const struct v4l2_subdev_video_ops hm1246_video_ops = {
+	.s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops hm1246_subdev_pad_ops = {
+	.enum_mbus_code = hm1246_enum_mbus_code,
+	.enum_frame_size = hm1246_enum_frame_size,
+	.get_fmt = v4l2_subdev_get_fmt,
+	.set_fmt = hm1246_set_format,
+	.get_selection = hm1246_get_selection,
+	.enable_streams = hm1246_enable_streams,
+	.disable_streams = hm1246_disable_streams,
+};
+
+static const struct v4l2_subdev_ops hm1246_subdev_ops = {
+	.video = &hm1246_video_ops,
+	.pad = &hm1246_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops hm1246_internal_ops = {
+	.init_state = hm1246_init_state,
+};
+
+static int hm1246_get_regulators(struct device *dev, struct hm1246 *hm1246)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(hm1246_supply_names); i++)
+		hm1246->supplies[i].supply = hm1246_supply_names[i];
+
+	return devm_regulator_bulk_get(dev, ARRAY_SIZE(hm1246_supply_names),
+				       hm1246->supplies);
+}
+
+static int hm1246_parse_fwnode(struct hm1246 *hm1246)
+{
+	struct fwnode_handle *endpoint;
+	struct v4l2_fwnode_endpoint bus_cfg = {
+		.bus_type = V4L2_MBUS_PARALLEL,
+	};
+	int ret;
+
+	endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(hm1246->dev),
+						   0, 0,
+						   FWNODE_GRAPH_ENDPOINT_NEXT);
+	if (!endpoint)
+		return dev_err_probe(hm1246->dev, -EINVAL,
+				     "missing endpoint node\n");
+
+	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
+	fwnode_handle_put(endpoint);
+	if (ret)
+		return dev_err_probe(hm1246->dev, ret,
+				     "parsing endpoint node failed\n");
+
+	hm1246->mbus_flags = bus_cfg.bus.parallel.flags;
+
+	if (bus_cfg.nr_of_link_frequencies == 1)
+		hm1246->link_frequency = bus_cfg.link_frequencies[0];
+
+	v4l2_fwnode_endpoint_free(&bus_cfg);
+
+	if (!hm1246->link_frequency)
+		return dev_err_probe(hm1246->dev, -EINVAL,
+				     "one link frequency expected\n");
+
+	return 0;
+}
+
+static int hm1246_init_controls(struct hm1246 *hm1246)
+{
+	const struct hm1246_mode *mode = &hm1246_modes[0];
+	struct v4l2_fwnode_device_properties props;
+	struct v4l2_ctrl_handler *ctrl_hdlr = &hm1246->ctrls;
+	struct v4l2_ctrl *ctrl;
+	s64 pixel_rate, exposure_max, vblank_min, hblank;
+	int ret;
+
+	ret = v4l2_fwnode_device_parse(hm1246->dev, &props);
+	if (ret)
+		return ret;
+
+	v4l2_ctrl_handler_init(ctrl_hdlr, 11);
+
+	hm1246->hflip_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &hm1246_ctrl_ops,
+					       V4L2_CID_HFLIP, 0, 1, 1, 0);
+	if (hm1246->hflip_ctrl)
+		hm1246->hflip_ctrl->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+	hm1246->vflip_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &hm1246_ctrl_ops,
+					       V4L2_CID_VFLIP, 0, 1, 1, 0);
+	if (hm1246->vflip_ctrl)
+		hm1246->vflip_ctrl->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+	v4l2_ctrl_cluster(2, &hm1246->hflip_ctrl);
+
+	ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &hm1246_ctrl_ops,
+				      V4L2_CID_LINK_FREQ,
+				      0, 0,
+				      &hm1246->link_frequency);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	pixel_rate = div_u64(hm1246->link_frequency, mode->clocks_per_pixel);
+	ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &hm1246_ctrl_ops,
+				 V4L2_CID_PIXEL_RATE,
+				 pixel_rate, pixel_rate, 1,
+				 pixel_rate);
+
+	vblank_min = mode->vts_min - mode->rect.height;
+	ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &hm1246_ctrl_ops,
+				 V4L2_CID_VBLANK, vblank_min,
+				 HM1246_VTS_MAX - mode->rect.height,
+				 1, vblank_min);
+
+	hblank = mode->hts - mode->rect.width;
+	ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &hm1246_ctrl_ops,
+				 V4L2_CID_HBLANK, hblank, hblank,
+				 1, hblank);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &hm1246_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+			  HM1246_ANALOG_GLOBAL_GAIN_MIN,
+			  HM1246_ANALOG_GLOBAL_GAIN_MAX,
+			  HM1246_ANALOG_GLOBAL_GAIN_STEP,
+			  HM1246_ANALOG_GLOBAL_GAIN_MIN);
+
+	exposure_max = mode->vts_min - HM1246_COARSE_INTG_MARGIN;
+	hm1246->exposure_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &hm1246_ctrl_ops,
+						  V4L2_CID_EXPOSURE,
+						  HM1246_COARSE_INTG_MIN,
+						  exposure_max,
+						  HM1246_COARSE_INTG_STEP,
+						  exposure_max);
+
+	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &hm1246_ctrl_ops,
+				     V4L2_CID_TEST_PATTERN,
+				     ARRAY_SIZE(hm1246_test_pattern_menu) - 1,
+				     0, 0, hm1246_test_pattern_menu);
+
+	v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &hm1246_ctrl_ops, &props);
+
+	if (ctrl_hdlr->error) {
+		v4l2_ctrl_handler_free(ctrl_hdlr);
+		return ctrl_hdlr->error;
+	}
+
+	hm1246->sd.ctrl_handler = ctrl_hdlr;
+
+	return 0;
+}
+
+static int hm1246_probe(struct i2c_client *client)
+{
+	struct hm1246 *hm1246;
+	int ret;
+
+	hm1246 = devm_kzalloc(&client->dev, sizeof(*hm1246), GFP_KERNEL);
+	if (!hm1246)
+		return -ENOMEM;
+
+	hm1246->dev = &client->dev;
+
+	ret = hm1246_parse_fwnode(hm1246);
+	if (ret)
+		return ret;
+
+	hm1246->regmap = devm_cci_regmap_init_i2c(client, 16);
+	if (IS_ERR(hm1246->regmap))
+		return dev_err_probe(hm1246->dev, PTR_ERR(hm1246->regmap),
+				     "failed to init CCI\n");
+
+	hm1246->xclk = devm_v4l2_sensor_clk_get(hm1246->dev, NULL);
+	if (IS_ERR(hm1246->xclk))
+		return dev_err_probe(hm1246->dev, PTR_ERR(hm1246->xclk),
+				     "failed to get xclk\n");
+
+	hm1246->xclk_freq = clk_get_rate(hm1246->xclk);
+	if (hm1246->xclk_freq < HM1246_XCLK_MIN ||
+	    hm1246->xclk_freq > HM1246_XCLK_MAX)
+		return dev_err_probe(hm1246->dev, -EINVAL,
+				     "xclk frequency out of range: %luHz\n",
+				     hm1246->xclk_freq);
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(hm1246_modes); i++) {
+		ret = hm1246_calc_pll(hm1246->xclk_freq, hm1246->link_frequency,
+				      hm1246_modes[i].clocks_per_pixel,
+				      NULL, NULL, NULL);
+		if (ret)
+			return dev_err_probe(hm1246->dev, ret,
+					     "no PLL setup for %lld Hz\n",
+					     hm1246->link_frequency);
+	}
+
+	ret = hm1246_get_regulators(hm1246->dev, hm1246);
+	if (ret)
+		return dev_err_probe(hm1246->dev, ret,
+				     "failed to get regulators\n");
+
+	hm1246->reset = devm_reset_control_get_optional(hm1246->dev, NULL);
+	if (IS_ERR(hm1246->reset))
+		return dev_err_probe(hm1246->dev, PTR_ERR(hm1246->reset),
+				     "failed to get reset\n");
+	reset_control_assert(hm1246->reset);
+
+	v4l2_i2c_subdev_init(&hm1246->sd, client, &hm1246_subdev_ops);
+	hm1246->sd.internal_ops = &hm1246_internal_ops;
+
+	ret = hm1246_init_controls(hm1246);
+	if (ret)
+		return dev_err_probe(hm1246->dev, ret,
+				     "failed to init controls\n");
+
+	hm1246->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	hm1246->pad.flags = MEDIA_PAD_FL_SOURCE;
+	hm1246->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+	ret = media_entity_pads_init(&hm1246->sd.entity, 1, &hm1246->pad);
+	if (ret) {
+		dev_err_probe(hm1246->dev, ret, "failed to init media pads\n");
+		goto err_v4l2_ctrl_handler_free;
+	}
+
+	hm1246->sd.state_lock = hm1246->ctrls.lock;
+	ret = v4l2_subdev_init_finalize(&hm1246->sd);
+	if (ret) {
+		dev_err_probe(hm1246->dev, ret, "failed to init v4l2 subdev\n");
+		goto err_media_entity_cleanup;
+	}
+
+	pm_runtime_enable(hm1246->dev);
+	pm_runtime_set_autosuspend_delay(hm1246->dev, 1000);
+	pm_runtime_use_autosuspend(hm1246->dev);
+	pm_runtime_idle(hm1246->dev);
+
+	ret = v4l2_async_register_subdev_sensor(&hm1246->sd);
+	if (ret) {
+		dev_err_probe(hm1246->dev, ret,
+			      "failed to register v4l2 subdev\n");
+		goto err_subdev_cleanup;
+	}
+
+	return 0;
+
+err_subdev_cleanup:
+	v4l2_subdev_cleanup(&hm1246->sd);
+	pm_runtime_disable(hm1246->dev);
+	pm_runtime_set_suspended(hm1246->dev);
+
+err_media_entity_cleanup:
+	media_entity_cleanup(&hm1246->sd.entity);
+
+err_v4l2_ctrl_handler_free:
+	v4l2_ctrl_handler_free(&hm1246->ctrls);
+
+	return ret;
+}
+
+static void hm1246_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct hm1246 *hm1246 = to_hm1246(sd);
+
+	v4l2_async_unregister_subdev(&hm1246->sd);
+	v4l2_subdev_cleanup(sd);
+	media_entity_cleanup(&hm1246->sd.entity);
+	v4l2_ctrl_handler_free(&hm1246->ctrls);
+
+	pm_runtime_disable(&client->dev);
+	if (!pm_runtime_status_suspended(&client->dev)) {
+		hm1246_power_off(hm1246->dev);
+		pm_runtime_set_suspended(&client->dev);
+	}
+}
+
+static const struct of_device_id hm1246_of_match[] = {
+	{ .compatible = "himax,hm1246" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, hm1246_of_match);
+
+static DEFINE_RUNTIME_DEV_PM_OPS(hm1246_pm_ops,
+				 hm1246_power_off, hm1246_power_on, NULL);
+
+static struct i2c_driver hm1246_i2c_driver = {
+	.driver = {
+		.of_match_table = hm1246_of_match,
+		.pm = pm_ptr(&hm1246_pm_ops),
+		.name = "hm1246",
+	},
+	.probe = hm1246_probe,
+	.remove = hm1246_remove,
+};
+module_i2c_driver(hm1246_i2c_driver);
+
+MODULE_DESCRIPTION("Himax HM1246 camera driver");
+MODULE_AUTHOR("Matthias Fend <matthias.fend@emfend.at>");
+MODULE_LICENSE("GPL");

-- 
2.34.1


^ 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