mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver
@ 2026-10-05  7:10 Robert Bozik
  2026-10-05  7:10 ` [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4 Robert Bozik
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Robert Bozik @ 2026-10-05  7:10 UTC (permalink / raw)
  To: linux-media
  Cc: Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel,
	Robert Bozik

Hi,

v4 of the OV32C4 sensor driver. v3 is at
https://lore.kernel.org/linux-media/20260829115832.8749-1-robertbozik@gmail.com/

The one open question from v1 and v2 was the second I2C address - the
write to 0x3e that the sensor needs before its main address answers -
and whether it belongs in a sensor driver. v3 could only say what it was
not. This version answers it with a measurement, and the design follows
from the answer.

The question that decides it is whether the block behind 0x3e lives and
dies with the sensor. Measured on the machine, polling 0x3e and 0x36
every 0.5 ms through a runtime power cycle and lining the polls up with
the kernel's regulator, gpio and i2c tracepoints:

  - sensor off (AVDD disabled, reset asserted): 0x3e NACKs, as does 0x36
  - AVDD on at t=1.0 ms, settled 3.5 ms; reset released 8.9 ms
  - 0x3e first ACK at 10.1 ms, reading 0x1001 = 0x00; between AVDD and
    the reset release it did not answer
  - the driver's 0x1001 = 0x04 at 30.1 ms; 0x36 first ACK at 30.6 ms
  - reset asserted and AVDD off at 4000.8 ms: 0x3e gone by 4001.9 ms,
    0x36 by 4003.0 ms

So it is unreachable without power, appears only once the sensor's own
reset is released, forgets the value written to it over a power cycle,
and disappears with the sensor. It has no ACPI device of its own, 0x300a
there reads zero (it is not an alias of the main map), and 0x36 has
nothing at 0x1000. The same register pair exists in OV08X40 at that
sensor's main address, named AO_STANDBY (0x1000) and MS_SELECT (0x1001,
0x04 for streaming) in ov08x40.c. The vendor Windows driver writes it
from the sensor driver as well, once, after reset and before the chip id
read, and never reads it back. I take all of that to mean the block is
part of the sensor and the sensor driver is its owner.

What changed accordingly:

 - The driver claims the second address with devm_i2c_new_dummy_device()
   and writes it through a CCI regmap of its own; the bare i2c_transfer()
   is gone.
 - ipu-bridge no longer instantiates a VCM for this sensor. The SSDB
   says vcmtype 2 and the bridge would put a dw9714 on 0x3e; dw9714 has
   no id register and binds to anything, and that client would hold the
   address the sensor driver needs. Patch 3 carries the exception, so
   patches 2 and 3 go together.

Two smaller things turned up while re-reading the driver for this:

 - The 10 ms after the software reset was a busy wait. The reset sat in
   the mode table with a delay_us, and regmap_multi_reg_write() turns
   that into udelay() on a regmap without can_sleep, which the CCI one
   is. The driver now issues the stream-off and the reset itself and
   sleeps; the table is the vendor's sequence minus those two entries.
 - power_on() returned 0 when the enable write failed. It now fails and
   undoes the clock, the supply and the reset.

The power-up timing, your "0 and 5 ms" on v1: I did not follow it then,
and I think I do now - nothing after the supply, because the regulator
core waits for it, and 5 ms after reset. The measurement above agrees:
the block answers about 1 ms after reset release and the main address
within 1 ms of the enable write. v4 uses 0, 5 ms and 1 ms, verified over
a cold boot, 20 runtime power cycles and 15 stream starts without a
failure.

Where the numbers come from, stated plainly this time, because v3 said
both "copied 1:1" and "measured by me" about the same table:

  From the vendor Windows driver (ov32c4.sys, FileVersion
  70.26100.2.18255):
  - the mode register table (1787 writes, at file offset 0x31300), of
    which the driver drops the first two entries, stream-off and reset,
    and issues them itself;
  - the 400 MHz link frequency, carried there as bits per second;
  - the chip id 0x563243;
  - the write of 0x04 to 0x1001 at the second address;
  - the registers the controls use (exposure 0x3500, analogue gain
    0x3508, digital gain 0x350a, VTS 0x380e) and the rule
    exposure_max = VTS - 32.

  Measured on the sensor:
  - the chip id, the register meanings above and the exposure rule,
    confirmed against what the chip reports;
  - the gain ranges: analogue exactly proportional between 0x100 and
    0x7c0 (1x to 7.75x, 0x100 being the power-up value), digital
    proportional with 1024 as unity, clipping to black one step above
    16383 - the obvious donor, ov13b10 on the same registers, puts
    analogue unity at 0x80, which is wrong here;
  - the timings: 320000000 / (4080 * 2614) = 30.005 fps against a
    measured 30.00; the power-up sequence as above;
  - flips preserve the Bayer order, so the media bus code never changes
    and the crop compensation ov13b10 does would introduce the shift it
    undoes there;
  - the 6560x4928 array and 6528x4896 active area, from the window
    registers of the table, agreeing with the vendor's product brief;
  - the second address, as above.

The rest of the series is as before. It adds a driver for the OmniVision
OV32C4, a 32 megapixel RGBC CMOS image sensor. It ships as the
under-display camera in the Lenovo Yoga Slim 9 14ILL10, where it is
enumerated through ACPI (_HID "OVTI32C4") and feeds an Intel IPU7. The
driver supports 3264x1840 at 30 fps, 10-bit Bayer, 4 CSI-2 lanes at a
400 MHz link frequency, with exposure, analogue gain, digital gain,
vblank, hblank and flip controls, runtime PM and .get_selection. Tested
on that machine: the sensor probes, streams at a measured 30.00 fps,
frames arrive complete, and the full path to a processed image runs
through libcamera's software ISP. The driver has what libcamera's sensor
driver requirements ask for: the five mandatory controls, the crop
selection targets, flips that keep the Bayer order, and the orientation
and rotation properties.

v4l2-compliance on the subdev, kernel 7.0.0-38:

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

Static checks: checkpatch.pl --strict, sparse (C=1), W=1 and
dt_binding_check.

The series applies to media_stage.git; base-commit is below.

Thanks,
Robert

Robert Bozik (3):
  dt-bindings: media: i2c: Add OmniVision OV32C4
  media: i2c: Add driver for OmniVision OV32C4
  media: ipu-bridge: Add OmniVision OV32C4

 .../bindings/media/i2c/ovti,ov32c4.yaml       |  105 +
 MAINTAINERS                                   |    8 +
 drivers/media/i2c/Kconfig                     |   10 +
 drivers/media/i2c/Makefile                    |    1 +
 drivers/media/i2c/ov32c4.c                    | 2716 +++++++++++++++++
 drivers/media/pci/intel/ipu-bridge.c          |   26 +-
 6 files changed, 2865 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
 create mode 100644 drivers/media/i2c/ov32c4.c


base-commit: 4900cad020c0580dfb1be27776ff10a4ef110cfa
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4
  2026-10-05  7:10 [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver Robert Bozik
@ 2026-10-05  7:10 ` Robert Bozik
  2026-10-05  8:11   ` Sakari Ailus
  2026-10-05  7:10 ` [PATCH v4 2/3] media: i2c: Add driver for " Robert Bozik
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Robert Bozik @ 2026-10-05  7:10 UTC (permalink / raw)
  To: linux-media
  Cc: Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel,
	Robert Bozik, Conor Dooley

Add a binding for the OmniVision OV32C4, a 32 megapixel RGBC CMOS image
sensor with on-chip 4-cell fusion, a 4-lane MIPI CSI-2 D-PHY transmitter
and the standard SCCB command interface.

The sensor ships in laptops as an under-display camera, where it is
described by ACPI; the binding follows ovti,ov08x40.yaml, which covers
the closest relative already in tree.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Robert Bozik <robertbozik@gmail.com>
---
Changes in v4:
- No changes to the binding.

 .../bindings/media/i2c/ovti,ov32c4.yaml       | 105 ++++++++++++++++++
 1 file changed, 105 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml

diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
new file mode 100644
index 000000000..804307cd0
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
@@ -0,0 +1,105 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,ov32c4.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OmniVision OV32C4 Image Sensor
+
+maintainers:
+  - Robert Bozik <robertbozik@gmail.com>
+
+description:
+  The OmniVision OV32C4 is a 32 megapixel RGBC (red, green, blue and clear)
+  CMOS image sensor in a 4-cell arrangement, with on-chip 4-cell fusion and
+  binning. It has a 6528x4896 active pixel array, a 4-lane MIPI CSI-2 D-PHY
+  transmitter and the standard SCCB command interface.
+
+allOf:
+  - $ref: /schemas/media/video-interface-devices.yaml#
+
+properties:
+  compatible:
+    const: ovti,ov32c4
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+    description: Input clock (XVCLK).
+
+  avdd-supply: true
+
+  dovdd-supply: true
+
+  dvdd-supply: true
+
+  reset-gpios:
+    maxItems: 1
+    description: Active low GPIO connected to the XSHUTDOWN pad of the sensor.
+
+  port:
+    $ref: /schemas/graph.yaml#/$defs/port-base
+    additionalProperties: false
+
+    properties:
+      endpoint:
+        $ref: /schemas/media/video-interfaces.yaml#
+        additionalProperties: false
+
+        properties:
+          data-lanes:
+            items:
+              - const: 1
+              - const: 2
+              - const: 3
+              - const: 4
+          link-frequencies: true
+          remote-endpoint: true
+
+        required:
+          - data-lanes
+          - link-frequencies
+          - remote-endpoint
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - port
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        camera@36 {
+            compatible = "ovti,ov32c4";
+            reg = <0x36>;
+
+            clocks = <&ov32c4_clk>;
+            assigned-clocks = <&ov32c4_clk>;
+            assigned-clock-rates = <19200000>;
+
+            avdd-supply = <&vreg_2p8>;
+            dovdd-supply = <&vreg_1p8>;
+            dvdd-supply = <&vreg_1p1>;
+
+            reset-gpios = <&tlmm 111 GPIO_ACTIVE_LOW>;
+
+            port {
+                ov32c4_ep: endpoint {
+                    remote-endpoint = <&csiphy0_ep>;
+                    data-lanes = <1 2 3 4>;
+                    link-frequencies = /bits/ 64 <400000000>;
+                };
+            };
+        };
+    };
+...
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v4 2/3] media: i2c: Add driver for OmniVision OV32C4
  2026-10-05  7:10 [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver Robert Bozik
  2026-10-05  7:10 ` [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4 Robert Bozik
@ 2026-10-05  7:10 ` Robert Bozik
  2026-10-05  9:23   ` Sakari Ailus
  2026-10-05  7:10 ` [PATCH v4 3/3] media: ipu-bridge: Add " Robert Bozik
  2026-10-05  8:04 ` [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver Sakari Ailus
  3 siblings, 1 reply; 13+ messages in thread
From: Robert Bozik @ 2026-10-05  7:10 UTC (permalink / raw)
  To: linux-media
  Cc: Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel,
	Robert Bozik

The OV32C4 is a 32 megapixel RGBC CMOS image sensor with on-chip 4-cell
fusion and binning, connected over 4 MIPI CSI-2 D-PHY lanes. It is used
as an under-display camera in laptops, where it is enumerated through
ACPI (_HID "OVTI32C4") and paired with an Intel IPU.

The driver supports 3264x1840 at 30 fps in 10-bit Bayer at a link
frequency of 400 MHz, with exposure, analogue gain, digital gain,
vblank, hblank and horizontal and vertical flip controls, runtime PM
and .get_selection reporting the 6560x4928 pixel array.

The sensor has a second I2C address, the second I2cSerialBus resource of
its _CRS, behind which sits a small register block of its own; the main
address does not answer until 0x1001 there is written. The block is part
of the sensor - it is unreachable while the sensor is unpowered or in
reset, starts answering about a millisecond after reset is released,
loses the written value over a power cycle and has no ACPI device of
its own - so the driver claims the address as a second I2C client and
writes it on every power-up.

There is no public datasheet for this sensor. The mode register table is
the vendor driver's initialisation sequence, and the registers the
controls use were established by correlating that binary with the values
read back from the chip; the cover letter has the measurements that back
the ranges and the timings.

Signed-off-by: Robert Bozik <robertbozik@gmail.com>
---
Changes in v4:
- The second I2C address is claimed with devm_i2c_new_dummy_device() and
  driven through its own CCI regmap instead of a bare i2c_transfer(),
  now that it is measured to be part of the sensor (cover letter).
- power_on() fails when the enable write to that block fails, and undoes
  the clock, the supply and the reset, instead of returning 0.
- The stream-off and the software reset are issued by the driver before
  the mode table rather than from inside it: the delay_us of a
  reg_sequence is a udelay() on a regmap without can_sleep, which made
  the 10 ms settle a busy wait. The table is now the vendor's list minus
  those two entries.
- Power-up timing from the measurement, in line with the "0 and 5 ms"
  remark on v1: no wait after the supply (the regulator core waits for
  it), 5 ms after reset release, 1 ms after the enable write. Verified
  over a cold boot, 20 runtime power cycles and 15 stream starts.
- Copyright line.

 MAINTAINERS                |    8 +
 drivers/media/i2c/Kconfig  |   10 +
 drivers/media/i2c/Makefile |    1 +
 drivers/media/i2c/ov32c4.c | 2716 ++++++++++++++++++++++++++++++++++++
 4 files changed, 2735 insertions(+)
 create mode 100644 drivers/media/i2c/ov32c4.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3785b8c1d..7b28717fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20008,6 +20008,14 @@ S:	Maintained
 T:	git git://linuxtv.org/media.git
 F:	drivers/media/i2c/ov2740.c
 
+OMNIVISION OV32C4 SENSOR DRIVER
+M:	Robert Bozik <robertbozik@gmail.com>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+T:	git git://linuxtv.org/media.git
+F:	Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
+F:	drivers/media/i2c/ov32c4.c
+
 OMNIVISION OV4689 SENSOR DRIVER
 M:	Mikhail Rudenko <mike.rudenko@gmail.com>
 L:	linux-media@vger.kernel.org
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5c52007f9..1c363d581 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -547,6 +547,16 @@ config VIDEO_OV2740
 	  To compile this driver as a module, choose M here: the
 	  module will be called ov2740.
 
+config VIDEO_OV32C4
+	tristate "OmniVision OV32C4 sensor support"
+	select V4L2_CCI_I2C
+	help
+	  This is a Video4Linux2 sensor driver for the OmniVision
+	  OV32C4 camera.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ov32c4.
+
 config VIDEO_OV4689
 	tristate "OmniVision OV4689 sensor support"
 	depends on GPIOLIB
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index d04bd5724..79bf2e393 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_VIDEO_OV2685) += ov2685.o
 obj-$(CONFIG_VIDEO_OV2732) += ov2732.o
 obj-$(CONFIG_VIDEO_OV2735) += ov2735.o
 obj-$(CONFIG_VIDEO_OV2740) += ov2740.o
+obj-$(CONFIG_VIDEO_OV32C4) += ov32c4.o
 obj-$(CONFIG_VIDEO_OV4689) += ov4689.o
 obj-$(CONFIG_VIDEO_OV5640) += ov5640.o
 obj-$(CONFIG_VIDEO_OV5645) += ov5645.o
diff --git a/drivers/media/i2c/ov32c4.c b/drivers/media/i2c/ov32c4.c
new file mode 100644
index 000000000..151d6b32e
--- /dev/null
+++ b/drivers/media/i2c/ov32c4.c
@@ -0,0 +1,2716 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OmniVision OV32C4 image sensor driver.
+ *
+ * Copyright (C) 2026 Robert Bozik
+ *
+ * The sensor ships in laptops with an Intel IPU7, where it is enumerated
+ * through ACPI _HID "OVTI32C4". There is no public datasheet; the 400 MHz
+ * link frequency comes from the vendor driver, which carries it as bits per
+ * second, and is confirmed on hardware: the receiver locks and the sensor
+ * streams 3264x1840 at a measured 30.00 fps, which is pixel_rate divided by
+ * ppl times vts.
+ */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/minmax.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define OV32C4_LINK_FREQ_400MHZ		400000000ULL	/* 800 Mbps/lane */
+#define OV32C4_MCLK			19200000
+#define OV32C4_RGB_DEPTH		10
+#define OV32C4_DATA_LANES		4
+
+/* Horizontal timing */
+#define OV32C4_REG_HTS			CCI_REG16(0x380c)
+
+/*
+ * Pixel array geometry, derived from the mode registers: 0x3800..0x3807 read
+ * a 6560x3712 window out of a 6560x4928 array, 2x2 binned to 3280x1856, of
+ * which 0x3810..0x3813 take 3264x1840 at offset (8, 9). The 32 columns and
+ * rows by which the array exceeds the 6528x4896 active area are blind.
+ */
+#define OV32C4_NATIVE_WIDTH		6560U
+#define OV32C4_NATIVE_HEIGHT		4928U
+#define OV32C4_ACTIVE_LEFT		16U
+#define OV32C4_ACTIVE_TOP		16U
+#define OV32C4_ACTIVE_WIDTH		6528U
+#define OV32C4_ACTIVE_HEIGHT		4896U
+#define OV32C4_CROP_LEFT		16U
+#define OV32C4_CROP_TOP			626U
+#define OV32C4_CROP_WIDTH		6528U
+#define OV32C4_CROP_HEIGHT		3680U
+
+#define OV32C4_REG_CHIP_ID		CCI_REG24(0x300a)
+#define OV32C4_CHIP_ID			0x563243
+
+#define OV32C4_REG_STREAM_CONTROL	CCI_REG8(0x0100)
+#define OV32C4_REG_SW_RESET		CCI_REG8(0x0103)
+/* The vendor driver issues the reset itself and waits this long after it. */
+#define OV32C4_SW_RESET_SETTLE_US	10000
+
+/*
+ * The sensor has a second I2C address, listed as the second I2cSerialBus
+ * resource of its ACPI _CRS, behind which sits a small register block of
+ * its own. Until 0x1001 there is written, the main address does not answer
+ * at all. The block is part of the sensor: it is unreachable while the
+ * sensor is unpowered or held in reset, starts answering about a millisecond
+ * after reset is released, loses the value written to 0x1001 over a power
+ * cycle, and has no ACPI device of its own. The same register pair exists in
+ * OV08X40 (AO_STANDBY at 0x1000, MS_SELECT at 0x1001, 0x04 for streaming)
+ * at that sensor's main address.
+ */
+#define OV32C4_COMPANION_ENABLE_REG	CCI_REG8(0x1001)
+#define OV32C4_COMPANION_ENABLE_VAL	0x04
+
+/* Vertical timing */
+#define OV32C4_REG_VTS			CCI_REG16(0x380e)
+#define OV32C4_VTS_MAX			0xffff
+
+/* Exposure; the sensor has two exposure contexts and ov32c4.sys writes both */
+#define OV32C4_REG_EXPOSURE		CCI_REG24(0x3500)
+#define OV32C4_REG_EXPOSURE_CTX2	CCI_REG24(0x3540)
+#define OV32C4_EXPOSURE_MIN		4
+#define OV32C4_EXPOSURE_STEP		1
+/* VTS = max(vts, exposure + 32) in ov32c4.sys -> keep 32 lines of margin */
+#define OV32C4_EXPOSURE_MAX_MARGIN	32
+
+/*
+ * Mirror and flip: bit 2 in each register, but with opposite polarity. The
+ * mode table leaves 0x3821 set and 0x3820 clear, and that is the un-flipped
+ * state. Neither changes the Bayer order.
+ */
+#define OV32C4_REG_FLIP			CCI_REG8(0x3820)
+#define OV32C4_REG_MIRROR		CCI_REG8(0x3821)
+#define OV32C4_FLIP_BIT			BIT(2)
+
+/* Analogue gain: 0x100 is unity and 0x7c0, 7.75x, is the maximum. */
+#define OV32C4_REG_ANALOG_GAIN		CCI_REG16(0x3508)
+#define OV32C4_REG_ANALOG_GAIN_CTX2	CCI_REG16(0x3548)
+#define OV32C4_ANA_GAIN_MIN		0x100
+#define OV32C4_ANA_GAIN_MAX		0x07c0
+#define OV32C4_ANA_GAIN_STEP		1
+#define OV32C4_ANA_GAIN_DEFAULT		0x100
+
+/*
+ * Digital gain. The register holds the gain shifted left by 6; the control
+ * carries the value itself, of which 1024 is unity.
+ */
+#define OV32C4_REG_DIGITAL_GAIN		CCI_REG24(0x350a)
+#define OV32C4_REG_DIGITAL_GAIN_CTX2	CCI_REG24(0x354a)
+#define OV32C4_DGAIN_SHIFT		6
+#define OV32C4_DGAIN_MIN		1024
+#define OV32C4_DGAIN_MAX		16383
+#define OV32C4_DGAIN_STEP		1
+#define OV32C4_DGAIN_DEFAULT		1024
+
+struct ov32c4_mode {
+	u32 width;
+	u32 height;
+	/*
+	 * Line length in pixels, in the units of the PIXEL_RATE control.
+	 * OV32C4_REG_HTS holds the same line in the sensor's own clock
+	 * units, which for this mode is 1224 against these 4080 pixels.
+	 */
+	u32 ppl;
+	/* Frame length in lines, as written to OV32C4_REG_VTS */
+	u32 vts_min;
+
+	const struct reg_sequence *reg_sequence;
+	int sequence_length;
+};
+
+static const char * const ov32c4_supply_names[] = {
+	"avdd",		/* Analog power */
+};
+
+/*
+ * Power-up timing; there is no public datasheet for this sensor. The
+ * regulator core already waits for the supply to settle. Measured on the
+ * hardware, the block behind the second address answers about 1 ms after
+ * reset is released, and the main address answers within 1 ms of the
+ * enable write; 5 ms and 1 ms leave a margin over that.
+ */
+#define OV32C4_RESET_SETTLE_US		5000
+#define OV32C4_ENABLE_SETTLE_US		1000
+
+/*
+ * Mode 3264x1840 @ 30 fps, 4 lanes, SGRBG10. The 15 fps variant of the same
+ * table differs only in VTS, which V4L2_CID_VBLANK covers.
+ *
+ * This is the vendor driver's list for the mode, minus its first two
+ * entries: the stream-off and the software reset, which the driver issues
+ * itself in ov32c4_enable_streams() so that the settle time after the reset
+ * can be a sleep rather than a delay inside a register sequence.
+ */
+static const struct reg_sequence ov32c4_mode_3264x1840_regs[] = {
+	{ 0x0301, 0xc8 },
+	{ 0x0303, 0x04 },
+	{ 0x0304, 0x02 },
+	{ 0x0305, 0x71 },
+	{ 0x0306, 0x04 },
+	{ 0x0307, 0x01 },
+	{ 0x0308, 0x03 },
+	{ 0x0316, 0x3c },
+	{ 0x0325, 0xd0 },
+	{ 0x0343, 0x04 },
+	{ 0x0344, 0x02 },
+	{ 0x0345, 0x32 },
+	{ 0x034b, 0x03 },
+	{ 0x034f, 0xe4 },
+	{ 0x3012, 0x41 },
+	{ 0x3025, 0x89 },
+	{ 0x3107, 0x86 },
+	{ 0x3400, 0x00 },
+	{ 0x3402, 0x8c },
+	{ 0x3404, 0x1a },
+	{ 0x3405, 0xb6 },
+	{ 0x3406, 0x88 },
+	{ 0x3407, 0x01 },
+	{ 0x3408, 0xb6 },
+	{ 0x3409, 0x88 },
+	{ 0x340a, 0x01 },
+	{ 0x340c, 0x50 },
+	{ 0x340d, 0x52 },
+	{ 0x3419, 0x15 },
+	{ 0x341a, 0xfc },
+	{ 0x341b, 0x30 },
+	{ 0x3420, 0x00 },
+	{ 0x3421, 0x00 },
+	{ 0x3422, 0x00 },
+	{ 0x3423, 0x00 },
+	{ 0x3424, 0x00 },
+	{ 0x3425, 0x00 },
+	{ 0x3426, 0x00 },
+	{ 0x3427, 0x00 },
+	{ 0x3428, 0xff },
+	{ 0x342a, 0x00 },
+	{ 0x342b, 0x00 },
+	{ 0x342c, 0x00 },
+	{ 0x342d, 0x0f },
+	{ 0x342e, 0x00 },
+	{ 0x342f, 0x00 },
+	{ 0x3430, 0x00 },
+	{ 0x3431, 0x00 },
+	{ 0x3432, 0x00 },
+	{ 0x3436, 0x10 },
+	{ 0x3437, 0x00 },
+	{ 0x3438, 0x00 },
+	{ 0x3439, 0x00 },
+	{ 0x3452, 0x14 },
+	{ 0x3453, 0x88 },
+	{ 0x3458, 0x02 },
+	{ 0x3459, 0x02 },
+	{ 0x3504, 0x4c },
+	{ 0x3506, 0x30 },
+	{ 0x3507, 0x00 },
+	{ 0x3544, 0x4c },
+	{ 0x3546, 0x30 },
+	{ 0x3547, 0x00 },
+	{ 0x3602, 0x24 },
+	{ 0x3605, 0xd0 },
+	{ 0x3608, 0x21 },
+	{ 0x3609, 0x90 },
+	{ 0x360c, 0x08 },
+	{ 0x3616, 0x31 },
+	{ 0x361a, 0x0a },
+	{ 0x3682, 0x80 },
+	{ 0x368e, 0x71 },
+	{ 0x3696, 0xd1 },
+	{ 0x36af, 0x00 },
+	{ 0x3714, 0x22 },
+	{ 0x3718, 0x02 },
+	{ 0x37b0, 0x00 },
+	{ 0x37b1, 0x8a },
+	{ 0x37b2, 0x01 },
+	{ 0x37b3, 0x5f },
+	{ 0x37b4, 0x00 },
+	{ 0x37b5, 0xd3 },
+	{ 0x37b6, 0x01 },
+	{ 0x37b7, 0xbe },
+	{ 0x3800, 0x00 },
+	{ 0x3801, 0x00 },
+	{ 0x3802, 0x02 },
+	{ 0x3803, 0x60 },
+	{ 0x3804, 0x19 },
+	{ 0x3805, 0x9f },
+	{ 0x3806, 0x10 },
+	{ 0x3807, 0xdf },
+	{ 0x3808, 0x0c },
+	{ 0x3809, 0xc0 },
+	{ 0x380a, 0x07 },
+	{ 0x380b, 0x30 },
+	{ 0x380c, 0x04 },
+	{ 0x380d, 0xc8 },
+	{ 0x380e, 0x0a },
+	{ 0x380f, 0x36 },
+	{ 0x3810, 0x00 },
+	{ 0x3811, 0x08 },
+	{ 0x3812, 0x00 },
+	{ 0x3813, 0x09 },
+	{ 0x3814, 0x11 },
+	{ 0x3815, 0x11 },
+	{ 0x3820, 0x02 },
+	{ 0x3821, 0x06 },
+	{ 0x3828, 0x0d },
+	{ 0x382a, 0x80 },
+	{ 0x3837, 0x08 },
+	{ 0x383a, 0x81 },
+	{ 0x383b, 0x81 },
+	{ 0x383c, 0x11 },
+	{ 0x383d, 0x11 },
+	{ 0x3840, 0x00 },
+	{ 0x3902, 0x12 },
+	{ 0x3903, 0x12 },
+	{ 0x3904, 0x12 },
+	{ 0x3905, 0x12 },
+	{ 0x3906, 0x12 },
+	{ 0x3907, 0x12 },
+	{ 0x3908, 0x12 },
+	{ 0x3909, 0x12 },
+	{ 0x390a, 0x03 },
+	{ 0x390b, 0x0d },
+	{ 0x390c, 0x12 },
+	{ 0x390d, 0x14 },
+	{ 0x390e, 0x03 },
+	{ 0x390f, 0x0d },
+	{ 0x3910, 0x12 },
+	{ 0x3911, 0x14 },
+	{ 0x3913, 0x00 },
+	{ 0x3914, 0x00 },
+	{ 0x3915, 0x00 },
+	{ 0x3916, 0x00 },
+	{ 0x391a, 0x78 },
+	{ 0x391c, 0x78 },
+	{ 0x391e, 0x78 },
+	{ 0x3920, 0x78 },
+	{ 0x3922, 0x78 },
+	{ 0x3924, 0x78 },
+	{ 0x3926, 0x78 },
+	{ 0x3928, 0x78 },
+	{ 0x392a, 0x04 },
+	{ 0x3930, 0x55 },
+	{ 0x3937, 0x09 },
+	{ 0x3938, 0x13 },
+	{ 0x3939, 0x25 },
+	{ 0x393a, 0x4b },
+	{ 0x393b, 0x05 },
+	{ 0x393f, 0xa6 },
+	{ 0x3940, 0x03 },
+	{ 0x3941, 0x01 },
+	{ 0x3942, 0x03 },
+	{ 0x3943, 0x01 },
+	{ 0x3944, 0x03 },
+	{ 0x3945, 0x02 },
+	{ 0x3946, 0x07 },
+	{ 0x3947, 0x06 },
+	{ 0x394e, 0xaa },
+	{ 0x394f, 0xaa },
+	{ 0x3950, 0x03 },
+	{ 0x395a, 0x60 },
+	{ 0x3a05, 0x03 },
+	{ 0x3a10, 0x84 },
+	{ 0x3a11, 0x20 },
+	{ 0x3a14, 0x13 },
+	{ 0x3a1a, 0x78 },
+	{ 0x3a1d, 0x48 },
+	{ 0x3ae1, 0x7b },
+	{ 0x3b21, 0x71 },
+	{ 0x3b25, 0x71 },
+	{ 0x3b29, 0x71 },
+	{ 0x3b2d, 0x71 },
+	{ 0x3b31, 0x71 },
+	{ 0x3b35, 0x71 },
+	{ 0x3b39, 0x71 },
+	{ 0x3b3d, 0x71 },
+	{ 0x3b64, 0x20 },
+	{ 0x3b68, 0x7f },
+	{ 0x3b69, 0xe3 },
+	{ 0x3b6c, 0x7f },
+	{ 0x3b6d, 0xe3 },
+	{ 0x3b71, 0x83 },
+	{ 0x3b73, 0xbf },
+	{ 0x3ba9, 0x9d },
+	{ 0x3bab, 0xe2 },
+	{ 0x3baf, 0x9d },
+	{ 0x3bb1, 0xe2 },
+	{ 0x3bb5, 0x9d },
+	{ 0x3bb7, 0xe2 },
+	{ 0x3bbb, 0x9d },
+	{ 0x3bbd, 0xe2 },
+	{ 0x3f00, 0x11 },
+	{ 0x4010, 0xe8 },
+	{ 0x4011, 0x01 },
+	{ 0x4012, 0x0c },
+	{ 0x4015, 0x00 },
+	{ 0x4016, 0x0f },
+	{ 0x4017, 0x00 },
+	{ 0x4018, 0x07 },
+	{ 0x401a, 0x40 },
+	{ 0x402e, 0x00 },
+	{ 0x4040, 0x00 },
+	{ 0x4041, 0x00 },
+	{ 0x4042, 0x00 },
+	{ 0x4043, 0x00 },
+	{ 0x4044, 0x00 },
+	{ 0x4045, 0x00 },
+	{ 0x4046, 0x00 },
+	{ 0x4047, 0x00 },
+	{ 0x4048, 0x00 },
+	{ 0x4049, 0x00 },
+	{ 0x404a, 0x00 },
+	{ 0x404b, 0x00 },
+	{ 0x404c, 0x00 },
+	{ 0x404d, 0x00 },
+	{ 0x404e, 0x00 },
+	{ 0x404f, 0x00 },
+	{ 0x40dc, 0x02 },
+	{ 0x4501, 0x11 },
+	{ 0x4504, 0x80 },
+	{ 0x4603, 0x15 },
+	{ 0x4609, 0x20 },
+	{ 0x460e, 0x00 },
+	{ 0x4680, 0x01 },
+	{ 0x4686, 0x00 },
+	{ 0x4687, 0x00 },
+	{ 0x4691, 0x00 },
+	{ 0x4800, 0x64 },
+	{ 0x4802, 0x00 },
+	{ 0x4806, 0x40 },
+	{ 0x481b, 0x3c },
+	{ 0x481f, 0x30 },
+	{ 0x4829, 0x70 },
+	{ 0x4837, 0x10 },
+	{ 0x4850, 0x42 },
+	{ 0x4853, 0x04 },
+	{ 0x4860, 0x00 },
+	{ 0x4861, 0xec },
+	{ 0x4862, 0x04 },
+	{ 0x4883, 0x00 },
+	{ 0x4888, 0x10 },
+	{ 0x4889, 0x03 },
+	{ 0x488a, 0x04 },
+	{ 0x48f8, 0x05 },
+	{ 0x48f9, 0xdc },
+	{ 0x4910, 0xe8 },
+	{ 0x4911, 0x01 },
+	{ 0x4912, 0x0c },
+	{ 0x4915, 0x00 },
+	{ 0x4916, 0x0f },
+	{ 0x4917, 0x00 },
+	{ 0x4918, 0x07 },
+	{ 0x491a, 0x40 },
+	{ 0x4940, 0x00 },
+	{ 0x4941, 0x00 },
+	{ 0x4942, 0x00 },
+	{ 0x4943, 0x00 },
+	{ 0x4944, 0x00 },
+	{ 0x4945, 0x00 },
+	{ 0x4946, 0x00 },
+	{ 0x4947, 0x00 },
+	{ 0x4948, 0x00 },
+	{ 0x4949, 0x00 },
+	{ 0x494a, 0x00 },
+	{ 0x494b, 0x00 },
+	{ 0x494c, 0x00 },
+	{ 0x494d, 0x00 },
+	{ 0x494e, 0x00 },
+	{ 0x494f, 0x00 },
+	{ 0x49dc, 0x02 },
+	{ 0x4d00, 0x04 },
+	{ 0x4d01, 0xea },
+	{ 0x4d02, 0xb9 },
+	{ 0x4d03, 0x40 },
+	{ 0x4d04, 0x72 },
+	{ 0x4d05, 0xf7 },
+	{ 0x5000, 0x1f },
+	{ 0x5001, 0x10 },
+	{ 0x5004, 0x17 },
+	{ 0x5007, 0x06 },
+	{ 0x5008, 0x04 },
+	{ 0x50c1, 0x00 },
+	{ 0x5110, 0x00 },
+	{ 0x5111, 0x14 },
+	{ 0x5112, 0x03 },
+	{ 0x5113, 0x93 },
+	{ 0x5152, 0xa3 },
+	{ 0x5180, 0xc1 },
+	{ 0x518a, 0x04 },
+	{ 0x51b0, 0x30 },
+	{ 0x52c1, 0x00 },
+	{ 0x52c2, 0x00 },
+	{ 0x5310, 0x00 },
+	{ 0x5311, 0x14 },
+	{ 0x5312, 0x03 },
+	{ 0x5313, 0x93 },
+	{ 0x5352, 0x63 },
+	{ 0x5380, 0xc1 },
+	{ 0x538a, 0x04 },
+	{ 0x53b0, 0x00 },
+	{ 0x5400, 0x3f },
+	{ 0x5401, 0x10 },
+	{ 0x5408, 0x0c },
+	{ 0x5409, 0xc0 },
+	{ 0x540a, 0x09 },
+	{ 0x540b, 0x90 },
+	{ 0x6ad0, 0x00 },
+	{ 0x6ad1, 0x75 },
+	{ 0x6ad2, 0x00 },
+	{ 0x6ad3, 0x75 },
+	{ 0x6ad4, 0x00 },
+	{ 0x6ad5, 0x75 },
+	{ 0x6ad6, 0x00 },
+	{ 0x6ad7, 0x75 },
+	{ 0x6ad8, 0x00 },
+	{ 0x6ad9, 0x75 },
+	{ 0x6ada, 0x00 },
+	{ 0x6adb, 0x75 },
+	{ 0x6adc, 0x00 },
+	{ 0x6add, 0x75 },
+	{ 0x6ade, 0x00 },
+	{ 0x6adf, 0x75 },
+	{ 0x6ae0, 0x00 },
+	{ 0x6ae1, 0x75 },
+	{ 0x6ae2, 0x00 },
+	{ 0x6ae3, 0x75 },
+	{ 0x6ae4, 0x00 },
+	{ 0x6ae5, 0x75 },
+	{ 0x6ae6, 0x00 },
+	{ 0x6ae7, 0x75 },
+	{ 0x6ae8, 0x00 },
+	{ 0x6ae9, 0x75 },
+	{ 0x6aea, 0x00 },
+	{ 0x6aeb, 0x75 },
+	{ 0x6aec, 0x00 },
+	{ 0x6aed, 0x75 },
+	{ 0x6aee, 0x00 },
+	{ 0x6aef, 0x75 },
+	{ 0x6af0, 0x00 },
+	{ 0x6af1, 0x75 },
+	{ 0x6af2, 0x00 },
+	{ 0x6af3, 0x75 },
+	{ 0x6af4, 0x00 },
+	{ 0x6af5, 0x75 },
+	{ 0x6af6, 0x00 },
+	{ 0x6af7, 0x75 },
+	{ 0x6af8, 0x00 },
+	{ 0x6af9, 0x75 },
+	{ 0x6afa, 0x00 },
+	{ 0x6afb, 0x75 },
+	{ 0x6afc, 0x00 },
+	{ 0x6afd, 0x75 },
+	{ 0x6afe, 0x00 },
+	{ 0x6aff, 0x75 },
+	{ 0x6b00, 0x00 },
+	{ 0x6b01, 0x75 },
+	{ 0x6b02, 0x00 },
+	{ 0x6b03, 0x75 },
+	{ 0x6b04, 0x00 },
+	{ 0x6b05, 0x75 },
+	{ 0x6b06, 0x00 },
+	{ 0x6b07, 0x75 },
+	{ 0x6b08, 0x00 },
+	{ 0x6b09, 0x75 },
+	{ 0x6b0a, 0x00 },
+	{ 0x6b0b, 0x75 },
+	{ 0x6b0c, 0x00 },
+	{ 0x6b0d, 0x75 },
+	{ 0x6b0e, 0x00 },
+	{ 0x6b0f, 0x75 },
+	{ 0x6b10, 0x00 },
+	{ 0x6b11, 0x75 },
+	{ 0x6b12, 0x00 },
+	{ 0x6b13, 0x75 },
+	{ 0x6b14, 0x00 },
+	{ 0x6b15, 0x75 },
+	{ 0x6b16, 0x00 },
+	{ 0x6b17, 0x75 },
+	{ 0x6b18, 0x00 },
+	{ 0x6b19, 0x75 },
+	{ 0x6b1a, 0x00 },
+	{ 0x6b1b, 0x75 },
+	{ 0x6b1c, 0x00 },
+	{ 0x6b1d, 0x75 },
+	{ 0x6b1e, 0x00 },
+	{ 0x6b1f, 0x75 },
+	{ 0x6b20, 0x00 },
+	{ 0x6b21, 0x75 },
+	{ 0x6b22, 0x00 },
+	{ 0x6b23, 0x75 },
+	{ 0x6b24, 0x00 },
+	{ 0x6b25, 0x75 },
+	{ 0x6b26, 0x00 },
+	{ 0x6b27, 0x75 },
+	{ 0x6b28, 0x00 },
+	{ 0x6b29, 0x75 },
+	{ 0x6b2a, 0x00 },
+	{ 0x6b2b, 0x75 },
+	{ 0x6b2c, 0x00 },
+	{ 0x6b2d, 0x75 },
+	{ 0x6b2e, 0x00 },
+	{ 0x6b2f, 0x75 },
+	{ 0x6b30, 0x00 },
+	{ 0x6b31, 0x75 },
+	{ 0x6b32, 0x00 },
+	{ 0x6b33, 0x75 },
+	{ 0x6b34, 0x00 },
+	{ 0x6b35, 0x75 },
+	{ 0x6b36, 0x00 },
+	{ 0x6b37, 0x75 },
+	{ 0x6b38, 0x00 },
+	{ 0x6b39, 0x75 },
+	{ 0x6b3a, 0x00 },
+	{ 0x6b3b, 0x75 },
+	{ 0x6b3c, 0x00 },
+	{ 0x6b3d, 0x75 },
+	{ 0x6b3e, 0x00 },
+	{ 0x6b3f, 0x75 },
+	{ 0x6b40, 0x00 },
+	{ 0x6b41, 0x75 },
+	{ 0x6b42, 0x00 },
+	{ 0x6b43, 0x75 },
+	{ 0x6b44, 0x00 },
+	{ 0x6b45, 0x75 },
+	{ 0x6b46, 0x00 },
+	{ 0x6b47, 0x75 },
+	{ 0x6b48, 0x00 },
+	{ 0x6b49, 0x75 },
+	{ 0x6b4a, 0x00 },
+	{ 0x6b4b, 0x75 },
+	{ 0x6b4c, 0x00 },
+	{ 0x6b4d, 0x75 },
+	{ 0x6b4e, 0x00 },
+	{ 0x6b4f, 0x75 },
+	{ 0x6b50, 0x00 },
+	{ 0x6b51, 0x75 },
+	{ 0x6b52, 0x00 },
+	{ 0x6b53, 0x75 },
+	{ 0x6b54, 0x00 },
+	{ 0x6b55, 0x75 },
+	{ 0x6b56, 0x00 },
+	{ 0x6b57, 0x75 },
+	{ 0x6b58, 0x00 },
+	{ 0x6b59, 0x75 },
+	{ 0x6b5a, 0x00 },
+	{ 0x6b5b, 0x75 },
+	{ 0x6b5c, 0x00 },
+	{ 0x6b5d, 0x75 },
+	{ 0x6b5e, 0x00 },
+	{ 0x6b5f, 0x75 },
+	{ 0x6b60, 0x00 },
+	{ 0x6b61, 0x75 },
+	{ 0x6b62, 0x00 },
+	{ 0x6b63, 0x75 },
+	{ 0x6b64, 0x00 },
+	{ 0x6b65, 0x75 },
+	{ 0x6b66, 0x00 },
+	{ 0x6b67, 0x75 },
+	{ 0x6b68, 0x00 },
+	{ 0x6b69, 0x75 },
+	{ 0x6b6a, 0x00 },
+	{ 0x6b6b, 0x75 },
+	{ 0x6b6c, 0x00 },
+	{ 0x6b6d, 0x75 },
+	{ 0x6b6e, 0x00 },
+	{ 0x6b6f, 0x75 },
+	{ 0x6b70, 0x00 },
+	{ 0x6b71, 0x75 },
+	{ 0x6b72, 0x00 },
+	{ 0x6b73, 0x75 },
+	{ 0x6b74, 0x00 },
+	{ 0x6b75, 0x75 },
+	{ 0x6b76, 0x00 },
+	{ 0x6b77, 0x75 },
+	{ 0x6b78, 0x00 },
+	{ 0x6b79, 0x75 },
+	{ 0x6b7a, 0x00 },
+	{ 0x6b7b, 0x75 },
+	{ 0x6b7c, 0x00 },
+	{ 0x6b7d, 0x75 },
+	{ 0x6b7e, 0x00 },
+	{ 0x6b7f, 0x75 },
+	{ 0x6b80, 0x00 },
+	{ 0x6b81, 0x75 },
+	{ 0x6b82, 0x00 },
+	{ 0x6b83, 0x75 },
+	{ 0x6b84, 0x00 },
+	{ 0x6b85, 0x75 },
+	{ 0x6b86, 0x00 },
+	{ 0x6b87, 0x75 },
+	{ 0x6b88, 0x00 },
+	{ 0x6b89, 0x75 },
+	{ 0x6b8a, 0x00 },
+	{ 0x6b8b, 0x75 },
+	{ 0x6b8c, 0x00 },
+	{ 0x6b8d, 0x75 },
+	{ 0x6b8e, 0x00 },
+	{ 0x6b8f, 0x75 },
+	{ 0x6b90, 0x00 },
+	{ 0x6b91, 0x75 },
+	{ 0x6b92, 0x00 },
+	{ 0x6b93, 0x75 },
+	{ 0x6b94, 0x00 },
+	{ 0x6b95, 0x75 },
+	{ 0x6b96, 0x00 },
+	{ 0x6b97, 0x75 },
+	{ 0x6b98, 0x00 },
+	{ 0x6b99, 0x75 },
+	{ 0x6b9a, 0x00 },
+	{ 0x6b9b, 0x75 },
+	{ 0x6b9c, 0x00 },
+	{ 0x6b9d, 0x75 },
+	{ 0x6b9e, 0x00 },
+	{ 0x6b9f, 0x75 },
+	{ 0x6ba0, 0x00 },
+	{ 0x6ba1, 0x75 },
+	{ 0x6ba2, 0x00 },
+	{ 0x6ba3, 0x75 },
+	{ 0x6ba4, 0x00 },
+	{ 0x6ba5, 0x75 },
+	{ 0x6ba6, 0x00 },
+	{ 0x6ba7, 0x75 },
+	{ 0x6ba8, 0x00 },
+	{ 0x6ba9, 0x75 },
+	{ 0x6baa, 0x00 },
+	{ 0x6bab, 0x75 },
+	{ 0x6bac, 0x00 },
+	{ 0x6bad, 0x75 },
+	{ 0x6bae, 0x00 },
+	{ 0x6baf, 0x75 },
+	{ 0x6bb0, 0x00 },
+	{ 0x6bb1, 0x75 },
+	{ 0x6bb2, 0x00 },
+	{ 0x6bb3, 0x75 },
+	{ 0x6bb4, 0x00 },
+	{ 0x6bb5, 0x75 },
+	{ 0x6bb6, 0x00 },
+	{ 0x6bb7, 0x75 },
+	{ 0x6bb8, 0x00 },
+	{ 0x6bb9, 0x75 },
+	{ 0x6bba, 0x00 },
+	{ 0x6bbb, 0x75 },
+	{ 0x6bbc, 0x00 },
+	{ 0x6bbd, 0x75 },
+	{ 0x6bbe, 0x00 },
+	{ 0x6bbf, 0x75 },
+	{ 0x6bc0, 0x00 },
+	{ 0x6bc1, 0x75 },
+	{ 0x6bc2, 0x00 },
+	{ 0x6bc3, 0x75 },
+	{ 0x6bc4, 0x00 },
+	{ 0x6bc5, 0x75 },
+	{ 0x6bc6, 0x00 },
+	{ 0x6bc7, 0x75 },
+	{ 0x6bc8, 0x00 },
+	{ 0x6bc9, 0x75 },
+	{ 0x6bca, 0x00 },
+	{ 0x6bcb, 0x75 },
+	{ 0x6bcc, 0x00 },
+	{ 0x6bcd, 0x75 },
+	{ 0x6bce, 0x00 },
+	{ 0x6bcf, 0x75 },
+	{ 0x6bd0, 0x00 },
+	{ 0x6bd1, 0x75 },
+	{ 0x6bd2, 0x00 },
+	{ 0x6bd3, 0x75 },
+	{ 0x6bd4, 0x00 },
+	{ 0x6bd5, 0x75 },
+	{ 0x6bd6, 0x00 },
+	{ 0x6bd7, 0x75 },
+	{ 0x6bd8, 0x00 },
+	{ 0x6bd9, 0x75 },
+	{ 0x6bda, 0x00 },
+	{ 0x6bdb, 0x75 },
+	{ 0x6bdc, 0x00 },
+	{ 0x6bdd, 0x75 },
+	{ 0x6bde, 0x00 },
+	{ 0x6bdf, 0x75 },
+	{ 0x6be0, 0x00 },
+	{ 0x6be1, 0x75 },
+	{ 0x6be2, 0x00 },
+	{ 0x6be3, 0x75 },
+	{ 0x6be4, 0x00 },
+	{ 0x6be5, 0x75 },
+	{ 0x6be6, 0x00 },
+	{ 0x6be7, 0x75 },
+	{ 0x6be8, 0x00 },
+	{ 0x6be9, 0x75 },
+	{ 0x6bea, 0x00 },
+	{ 0x6beb, 0x75 },
+	{ 0x6bec, 0x00 },
+	{ 0x6bed, 0x75 },
+	{ 0x6bee, 0x00 },
+	{ 0x6bef, 0x75 },
+	{ 0x6c00, 0x00 },
+	{ 0x6c01, 0x75 },
+	{ 0x6c02, 0x00 },
+	{ 0x6c03, 0x75 },
+	{ 0x6c04, 0x00 },
+	{ 0x6c05, 0x75 },
+	{ 0x6c06, 0x00 },
+	{ 0x6c07, 0x75 },
+	{ 0x6c08, 0x00 },
+	{ 0x6c09, 0x75 },
+	{ 0x6c0a, 0x00 },
+	{ 0x6c0b, 0x75 },
+	{ 0x6c0c, 0x00 },
+	{ 0x6c0d, 0x75 },
+	{ 0x6c0e, 0x00 },
+	{ 0x6c0f, 0x75 },
+	{ 0x6c10, 0x00 },
+	{ 0x6c11, 0x75 },
+	{ 0x6c12, 0x00 },
+	{ 0x6c13, 0x75 },
+	{ 0x6c14, 0x00 },
+	{ 0x6c15, 0x75 },
+	{ 0x6c16, 0x00 },
+	{ 0x6c17, 0x75 },
+	{ 0x6c18, 0x00 },
+	{ 0x6c19, 0x75 },
+	{ 0x6c1a, 0x00 },
+	{ 0x6c1b, 0x75 },
+	{ 0x6c1c, 0x00 },
+	{ 0x6c1d, 0x75 },
+	{ 0x6c1e, 0x00 },
+	{ 0x6c1f, 0x75 },
+	{ 0x6c20, 0x00 },
+	{ 0x6c21, 0x75 },
+	{ 0x6c22, 0x00 },
+	{ 0x6c23, 0x75 },
+	{ 0x6c24, 0x00 },
+	{ 0x6c25, 0x75 },
+	{ 0x6c26, 0x00 },
+	{ 0x6c27, 0x75 },
+	{ 0x6c28, 0x00 },
+	{ 0x6c29, 0x75 },
+	{ 0x6c2a, 0x00 },
+	{ 0x6c2b, 0x75 },
+	{ 0x6c2c, 0x00 },
+	{ 0x6c2d, 0x75 },
+	{ 0x6c2e, 0x00 },
+	{ 0x6c2f, 0x75 },
+	{ 0x6c30, 0x00 },
+	{ 0x6c31, 0x75 },
+	{ 0x6c32, 0x00 },
+	{ 0x6c33, 0x75 },
+	{ 0x6c34, 0x00 },
+	{ 0x6c35, 0x75 },
+	{ 0x6c36, 0x00 },
+	{ 0x6c37, 0x75 },
+	{ 0x6c38, 0x00 },
+	{ 0x6c39, 0x75 },
+	{ 0x6c3a, 0x00 },
+	{ 0x6c3b, 0x75 },
+	{ 0x6c3c, 0x00 },
+	{ 0x6c3d, 0x75 },
+	{ 0x6c3e, 0x00 },
+	{ 0x6c3f, 0x75 },
+	{ 0x6c40, 0x00 },
+	{ 0x6c41, 0x75 },
+	{ 0x6c42, 0x00 },
+	{ 0x6c43, 0x75 },
+	{ 0x6c44, 0x00 },
+	{ 0x6c45, 0x75 },
+	{ 0x6c46, 0x00 },
+	{ 0x6c47, 0x75 },
+	{ 0x6c48, 0x00 },
+	{ 0x6c49, 0x75 },
+	{ 0x6c4a, 0x00 },
+	{ 0x6c4b, 0x75 },
+	{ 0x6c4c, 0x00 },
+	{ 0x6c4d, 0x75 },
+	{ 0x6c4e, 0x00 },
+	{ 0x6c4f, 0x75 },
+	{ 0x6c50, 0x00 },
+	{ 0x6c51, 0x75 },
+	{ 0x6c52, 0x00 },
+	{ 0x6c53, 0x75 },
+	{ 0x6c54, 0x00 },
+	{ 0x6c55, 0x75 },
+	{ 0x6c56, 0x00 },
+	{ 0x6c57, 0x75 },
+	{ 0x6c58, 0x00 },
+	{ 0x6c59, 0x75 },
+	{ 0x6c5a, 0x00 },
+	{ 0x6c5b, 0x75 },
+	{ 0x6c5c, 0x00 },
+	{ 0x6c5d, 0x75 },
+	{ 0x6c5e, 0x00 },
+	{ 0x6c5f, 0x75 },
+	{ 0x6c60, 0x00 },
+	{ 0x6c61, 0x75 },
+	{ 0x6c62, 0x00 },
+	{ 0x6c63, 0x75 },
+	{ 0x6c64, 0x00 },
+	{ 0x6c65, 0x75 },
+	{ 0x6c66, 0x00 },
+	{ 0x6c67, 0x75 },
+	{ 0x6c68, 0x00 },
+	{ 0x6c69, 0x75 },
+	{ 0x6c6a, 0x00 },
+	{ 0x6c6b, 0x75 },
+	{ 0x6c6c, 0x00 },
+	{ 0x6c6d, 0x75 },
+	{ 0x6c6e, 0x00 },
+	{ 0x6c6f, 0x75 },
+	{ 0x6c70, 0x00 },
+	{ 0x6c71, 0x75 },
+	{ 0x6c72, 0x00 },
+	{ 0x6c73, 0x75 },
+	{ 0x6c74, 0x00 },
+	{ 0x6c75, 0x75 },
+	{ 0x6c76, 0x00 },
+	{ 0x6c77, 0x75 },
+	{ 0x6c78, 0x00 },
+	{ 0x6c79, 0x75 },
+	{ 0x6c7a, 0x00 },
+	{ 0x6c7b, 0x75 },
+	{ 0x6c7c, 0x00 },
+	{ 0x6c7d, 0x75 },
+	{ 0x6c7e, 0x00 },
+	{ 0x6c7f, 0x75 },
+	{ 0x6c80, 0x00 },
+	{ 0x6c81, 0x75 },
+	{ 0x6c82, 0x00 },
+	{ 0x6c83, 0x75 },
+	{ 0x6c84, 0x00 },
+	{ 0x6c85, 0x75 },
+	{ 0x6c86, 0x00 },
+	{ 0x6c87, 0x75 },
+	{ 0x6c88, 0x00 },
+	{ 0x6c89, 0x75 },
+	{ 0x6c8a, 0x00 },
+	{ 0x6c8b, 0x75 },
+	{ 0x6c8c, 0x00 },
+	{ 0x6c8d, 0x75 },
+	{ 0x6c8e, 0x00 },
+	{ 0x6c8f, 0x75 },
+	{ 0x6c90, 0x00 },
+	{ 0x6c91, 0x75 },
+	{ 0x6c92, 0x00 },
+	{ 0x6c93, 0x75 },
+	{ 0x6c94, 0x00 },
+	{ 0x6c95, 0x75 },
+	{ 0x6c96, 0x00 },
+	{ 0x6c97, 0x75 },
+	{ 0x6c98, 0x00 },
+	{ 0x6c99, 0x75 },
+	{ 0x6c9a, 0x00 },
+	{ 0x6c9b, 0x75 },
+	{ 0x6c9c, 0x00 },
+	{ 0x6c9d, 0x75 },
+	{ 0x6c9e, 0x00 },
+	{ 0x6c9f, 0x75 },
+	{ 0x6ca0, 0x00 },
+	{ 0x6ca1, 0x75 },
+	{ 0x6ca2, 0x00 },
+	{ 0x6ca3, 0x75 },
+	{ 0x6ca4, 0x00 },
+	{ 0x6ca5, 0x75 },
+	{ 0x6ca6, 0x00 },
+	{ 0x6ca7, 0x75 },
+	{ 0x6ca8, 0x00 },
+	{ 0x6ca9, 0x75 },
+	{ 0x6caa, 0x00 },
+	{ 0x6cab, 0x75 },
+	{ 0x6cac, 0x00 },
+	{ 0x6cad, 0x75 },
+	{ 0x6cae, 0x00 },
+	{ 0x6caf, 0x75 },
+	{ 0x6cb0, 0x00 },
+	{ 0x6cb1, 0x75 },
+	{ 0x6cb2, 0x00 },
+	{ 0x6cb3, 0x75 },
+	{ 0x6cb4, 0x00 },
+	{ 0x6cb5, 0x75 },
+	{ 0x6cb6, 0x00 },
+	{ 0x6cb7, 0x75 },
+	{ 0x6cb8, 0x00 },
+	{ 0x6cb9, 0x75 },
+	{ 0x6cba, 0x00 },
+	{ 0x6cbb, 0x75 },
+	{ 0x6cbc, 0x00 },
+	{ 0x6cbd, 0x75 },
+	{ 0x6cbe, 0x00 },
+	{ 0x6cbf, 0x75 },
+	{ 0x6cc0, 0x00 },
+	{ 0x6cc1, 0x75 },
+	{ 0x6cc2, 0x00 },
+	{ 0x6cc3, 0x75 },
+	{ 0x6cc4, 0x00 },
+	{ 0x6cc5, 0x75 },
+	{ 0x6cc6, 0x00 },
+	{ 0x6cc7, 0x75 },
+	{ 0x6cc8, 0x00 },
+	{ 0x6cc9, 0x75 },
+	{ 0x6cca, 0x00 },
+	{ 0x6ccb, 0x75 },
+	{ 0x6ccc, 0x00 },
+	{ 0x6ccd, 0x75 },
+	{ 0x6cce, 0x00 },
+	{ 0x6ccf, 0x75 },
+	{ 0x6cd0, 0x00 },
+	{ 0x6cd1, 0x75 },
+	{ 0x6cd2, 0x00 },
+	{ 0x6cd3, 0x75 },
+	{ 0x6cd4, 0x00 },
+	{ 0x6cd5, 0x75 },
+	{ 0x6cd6, 0x00 },
+	{ 0x6cd7, 0x75 },
+	{ 0x6cd8, 0x00 },
+	{ 0x6cd9, 0x75 },
+	{ 0x6cda, 0x00 },
+	{ 0x6cdb, 0x75 },
+	{ 0x6cdc, 0x00 },
+	{ 0x6cdd, 0x75 },
+	{ 0x6cde, 0x00 },
+	{ 0x6cdf, 0x75 },
+	{ 0x6ce0, 0x00 },
+	{ 0x6ce1, 0x75 },
+	{ 0x6ce2, 0x00 },
+	{ 0x6ce3, 0x75 },
+	{ 0x6ce4, 0x00 },
+	{ 0x6ce5, 0x75 },
+	{ 0x6ce6, 0x00 },
+	{ 0x6ce7, 0x75 },
+	{ 0x6ce8, 0x00 },
+	{ 0x6ce9, 0x75 },
+	{ 0x6cea, 0x00 },
+	{ 0x6ceb, 0x75 },
+	{ 0x6cec, 0x00 },
+	{ 0x6ced, 0x75 },
+	{ 0x6cee, 0x00 },
+	{ 0x6cef, 0x75 },
+	{ 0x6cf0, 0x00 },
+	{ 0x6cf1, 0x75 },
+	{ 0x6cf2, 0x00 },
+	{ 0x6cf3, 0x75 },
+	{ 0x6cf4, 0x00 },
+	{ 0x6cf5, 0x75 },
+	{ 0x6cf6, 0x00 },
+	{ 0x6cf7, 0x75 },
+	{ 0x6cf8, 0x00 },
+	{ 0x6cf9, 0x75 },
+	{ 0x6cfa, 0x00 },
+	{ 0x6cfb, 0x75 },
+	{ 0x6cfc, 0x00 },
+	{ 0x6cfd, 0x75 },
+	{ 0x6cfe, 0x00 },
+	{ 0x6cff, 0x75 },
+	{ 0x6d00, 0x00 },
+	{ 0x6d01, 0x75 },
+	{ 0x6d02, 0x00 },
+	{ 0x6d03, 0x75 },
+	{ 0x6d04, 0x00 },
+	{ 0x6d05, 0x75 },
+	{ 0x6d06, 0x00 },
+	{ 0x6d07, 0x75 },
+	{ 0x6d08, 0x00 },
+	{ 0x6d09, 0x75 },
+	{ 0x6d0a, 0x00 },
+	{ 0x6d0b, 0x75 },
+	{ 0x6d0c, 0x00 },
+	{ 0x6d0d, 0x75 },
+	{ 0x6d0e, 0x00 },
+	{ 0x6d0f, 0x75 },
+	{ 0x6d10, 0x00 },
+	{ 0x6d11, 0x75 },
+	{ 0x6d12, 0x00 },
+	{ 0x6d13, 0x75 },
+	{ 0x6d14, 0x00 },
+	{ 0x6d15, 0x75 },
+	{ 0x6d16, 0x00 },
+	{ 0x6d17, 0x75 },
+	{ 0x6d18, 0x00 },
+	{ 0x6d19, 0x75 },
+	{ 0x6d1a, 0x00 },
+	{ 0x6d1b, 0x75 },
+	{ 0x6d1c, 0x00 },
+	{ 0x6d1d, 0x75 },
+	{ 0x6d1e, 0x00 },
+	{ 0x6d1f, 0x75 },
+	{ 0x6d20, 0x00 },
+	{ 0x6d21, 0x75 },
+	{ 0x6d22, 0x00 },
+	{ 0x6d23, 0x75 },
+	{ 0x6d24, 0x00 },
+	{ 0x6d25, 0x75 },
+	{ 0x6d26, 0x00 },
+	{ 0x6d27, 0x75 },
+	{ 0x6d28, 0x00 },
+	{ 0x6d29, 0x75 },
+	{ 0x6d2a, 0x00 },
+	{ 0x6d2b, 0x75 },
+	{ 0x6d2c, 0x00 },
+	{ 0x6d2d, 0x75 },
+	{ 0x6d2e, 0x00 },
+	{ 0x6d2f, 0x75 },
+	{ 0x6d30, 0x00 },
+	{ 0x6d31, 0x75 },
+	{ 0x6d32, 0x00 },
+	{ 0x6d33, 0x75 },
+	{ 0x6d34, 0x00 },
+	{ 0x6d35, 0x75 },
+	{ 0x6d36, 0x00 },
+	{ 0x6d37, 0x75 },
+	{ 0x6d38, 0x00 },
+	{ 0x6d39, 0x75 },
+	{ 0x6d3a, 0x00 },
+	{ 0x6d3b, 0x75 },
+	{ 0x6d3c, 0x00 },
+	{ 0x6d3d, 0x75 },
+	{ 0x6d3e, 0x00 },
+	{ 0x6d3f, 0x75 },
+	{ 0x6d40, 0x00 },
+	{ 0x6d41, 0x75 },
+	{ 0x6d42, 0x00 },
+	{ 0x6d43, 0x75 },
+	{ 0x6d44, 0x00 },
+	{ 0x6d45, 0x75 },
+	{ 0x6d46, 0x00 },
+	{ 0x6d47, 0x75 },
+	{ 0x6d48, 0x00 },
+	{ 0x6d49, 0x75 },
+	{ 0x6d4a, 0x00 },
+	{ 0x6d4b, 0x75 },
+	{ 0x6d4c, 0x00 },
+	{ 0x6d4d, 0x75 },
+	{ 0x6d4e, 0x00 },
+	{ 0x6d4f, 0x75 },
+	{ 0x6d50, 0x00 },
+	{ 0x6d51, 0x75 },
+	{ 0x6d52, 0x00 },
+	{ 0x6d53, 0x75 },
+	{ 0x6d54, 0x00 },
+	{ 0x6d55, 0x75 },
+	{ 0x6d56, 0x00 },
+	{ 0x6d57, 0x75 },
+	{ 0x6d58, 0x00 },
+	{ 0x6d59, 0x75 },
+	{ 0x6d5a, 0x00 },
+	{ 0x6d5b, 0x75 },
+	{ 0x6d5c, 0x00 },
+	{ 0x6d5d, 0x75 },
+	{ 0x6d5e, 0x00 },
+	{ 0x6d5f, 0x75 },
+	{ 0x6d60, 0x00 },
+	{ 0x6d61, 0x75 },
+	{ 0x6d62, 0x00 },
+	{ 0x6d63, 0x75 },
+	{ 0x6d64, 0x00 },
+	{ 0x6d65, 0x75 },
+	{ 0x6d66, 0x00 },
+	{ 0x6d67, 0x75 },
+	{ 0x6d68, 0x00 },
+	{ 0x6d69, 0x75 },
+	{ 0x6d6a, 0x00 },
+	{ 0x6d6b, 0x75 },
+	{ 0x6d6c, 0x00 },
+	{ 0x6d6d, 0x75 },
+	{ 0x6d6e, 0x00 },
+	{ 0x6d6f, 0x75 },
+	{ 0x6d70, 0x00 },
+	{ 0x6d71, 0x75 },
+	{ 0x6d72, 0x00 },
+	{ 0x6d73, 0x75 },
+	{ 0x6d74, 0x00 },
+	{ 0x6d75, 0x75 },
+	{ 0x6d76, 0x00 },
+	{ 0x6d77, 0x75 },
+	{ 0x6d78, 0x00 },
+	{ 0x6d79, 0x75 },
+	{ 0x6d7a, 0x00 },
+	{ 0x6d7b, 0x75 },
+	{ 0x6d7c, 0x00 },
+	{ 0x6d7d, 0x75 },
+	{ 0x6d7e, 0x00 },
+	{ 0x6d7f, 0x75 },
+	{ 0x6d80, 0x00 },
+	{ 0x6d81, 0x75 },
+	{ 0x6d82, 0x00 },
+	{ 0x6d83, 0x75 },
+	{ 0x6d84, 0x00 },
+	{ 0x6d85, 0x75 },
+	{ 0x6d86, 0x00 },
+	{ 0x6d87, 0x75 },
+	{ 0x6d88, 0x00 },
+	{ 0x6d89, 0x75 },
+	{ 0x6d8a, 0x00 },
+	{ 0x6d8b, 0x75 },
+	{ 0x6d8c, 0x00 },
+	{ 0x6d8d, 0x75 },
+	{ 0x6d8e, 0x00 },
+	{ 0x6d8f, 0x75 },
+	{ 0x6d90, 0x00 },
+	{ 0x6d91, 0x75 },
+	{ 0x6d92, 0x00 },
+	{ 0x6d93, 0x75 },
+	{ 0x6d94, 0x00 },
+	{ 0x6d95, 0x75 },
+	{ 0x6d96, 0x00 },
+	{ 0x6d97, 0x75 },
+	{ 0x6d98, 0x00 },
+	{ 0x6d99, 0x75 },
+	{ 0x6d9a, 0x00 },
+	{ 0x6d9b, 0x75 },
+	{ 0x6d9c, 0x00 },
+	{ 0x6d9d, 0x75 },
+	{ 0x6d9e, 0x00 },
+	{ 0x6d9f, 0x75 },
+	{ 0x6da0, 0x00 },
+	{ 0x6da1, 0x75 },
+	{ 0x6da2, 0x00 },
+	{ 0x6da3, 0x75 },
+	{ 0x6da4, 0x00 },
+	{ 0x6da5, 0x75 },
+	{ 0x6da6, 0x00 },
+	{ 0x6da7, 0x75 },
+	{ 0x6da8, 0x00 },
+	{ 0x6da9, 0x75 },
+	{ 0x6daa, 0x00 },
+	{ 0x6dab, 0x75 },
+	{ 0x6dac, 0x00 },
+	{ 0x6dad, 0x75 },
+	{ 0x6dae, 0x00 },
+	{ 0x6daf, 0x75 },
+	{ 0x6db0, 0x00 },
+	{ 0x6db1, 0x75 },
+	{ 0x6db2, 0x00 },
+	{ 0x6db3, 0x75 },
+	{ 0x6db4, 0x00 },
+	{ 0x6db5, 0x75 },
+	{ 0x6db6, 0x00 },
+	{ 0x6db7, 0x75 },
+	{ 0x6db8, 0x00 },
+	{ 0x6db9, 0x75 },
+	{ 0x6dba, 0x00 },
+	{ 0x6dbb, 0x75 },
+	{ 0x6dbc, 0x00 },
+	{ 0x6dbd, 0x75 },
+	{ 0x6dbe, 0x00 },
+	{ 0x6dbf, 0x75 },
+	{ 0x6dc0, 0x00 },
+	{ 0x6dc1, 0x75 },
+	{ 0x6dc2, 0x00 },
+	{ 0x6dc3, 0x75 },
+	{ 0x6dc4, 0x00 },
+	{ 0x6dc5, 0x75 },
+	{ 0x6dc6, 0x00 },
+	{ 0x6dc7, 0x75 },
+	{ 0x6dc8, 0x00 },
+	{ 0x6dc9, 0x75 },
+	{ 0x6dca, 0x00 },
+	{ 0x6dcb, 0x75 },
+	{ 0x6dcc, 0x00 },
+	{ 0x6dcd, 0x75 },
+	{ 0x6dce, 0x00 },
+	{ 0x6dcf, 0x75 },
+	{ 0x6dd0, 0x00 },
+	{ 0x6dd1, 0x75 },
+	{ 0x6dd2, 0x00 },
+	{ 0x6dd3, 0x75 },
+	{ 0x6dd4, 0x00 },
+	{ 0x6dd5, 0x75 },
+	{ 0x6dd6, 0x00 },
+	{ 0x6dd7, 0x75 },
+	{ 0x6dd8, 0x00 },
+	{ 0x6dd9, 0x75 },
+	{ 0x6dda, 0x00 },
+	{ 0x6ddb, 0x75 },
+	{ 0x6ddc, 0x00 },
+	{ 0x6ddd, 0x75 },
+	{ 0x6dde, 0x00 },
+	{ 0x6ddf, 0x75 },
+	{ 0x6de0, 0x00 },
+	{ 0x6de1, 0x75 },
+	{ 0x6de2, 0x00 },
+	{ 0x6de3, 0x75 },
+	{ 0x6de4, 0x00 },
+	{ 0x6de5, 0x75 },
+	{ 0x6de6, 0x00 },
+	{ 0x6de7, 0x75 },
+	{ 0x6de8, 0x00 },
+	{ 0x6de9, 0x75 },
+	{ 0x6dea, 0x00 },
+	{ 0x6deb, 0x75 },
+	{ 0x6dec, 0x00 },
+	{ 0x6ded, 0x75 },
+	{ 0x6dee, 0x00 },
+	{ 0x6def, 0x75 },
+	{ 0x6df0, 0x00 },
+	{ 0x6df1, 0x75 },
+	{ 0x6df2, 0x00 },
+	{ 0x6df3, 0x75 },
+	{ 0x6df4, 0x00 },
+	{ 0x6df5, 0x75 },
+	{ 0x6df6, 0x00 },
+	{ 0x6df7, 0x75 },
+	{ 0x6df8, 0x00 },
+	{ 0x6df9, 0x75 },
+	{ 0x6dfa, 0x00 },
+	{ 0x6dfb, 0x75 },
+	{ 0x6dfc, 0x00 },
+	{ 0x6dfd, 0x75 },
+	{ 0x6dfe, 0x00 },
+	{ 0x6dff, 0x75 },
+	{ 0x6e00, 0x00 },
+	{ 0x6e01, 0x75 },
+	{ 0x6e02, 0x00 },
+	{ 0x6e03, 0x75 },
+	{ 0x6e04, 0x00 },
+	{ 0x6e05, 0x75 },
+	{ 0x6e06, 0x00 },
+	{ 0x6e07, 0x75 },
+	{ 0x6e08, 0x00 },
+	{ 0x6e09, 0x75 },
+	{ 0x6e0a, 0x00 },
+	{ 0x6e0b, 0x75 },
+	{ 0x6e0c, 0x00 },
+	{ 0x6e0d, 0x75 },
+	{ 0x6e0e, 0x00 },
+	{ 0x6e0f, 0x75 },
+	{ 0x6e10, 0x00 },
+	{ 0x6e11, 0x75 },
+	{ 0x6e12, 0x00 },
+	{ 0x6e13, 0x75 },
+	{ 0x6e14, 0x00 },
+	{ 0x6e15, 0x75 },
+	{ 0x6e16, 0x00 },
+	{ 0x6e17, 0x75 },
+	{ 0x6e18, 0x00 },
+	{ 0x6e19, 0x75 },
+	{ 0x6e1a, 0x00 },
+	{ 0x6e1b, 0x75 },
+	{ 0x6e1c, 0x00 },
+	{ 0x6e1d, 0x75 },
+	{ 0x6e1e, 0x00 },
+	{ 0x6e1f, 0x75 },
+	{ 0x6e20, 0x00 },
+	{ 0x6e21, 0x75 },
+	{ 0x6e22, 0x00 },
+	{ 0x6e23, 0x75 },
+	{ 0x6e24, 0x00 },
+	{ 0x6e25, 0x75 },
+	{ 0x6e26, 0x00 },
+	{ 0x6e27, 0x75 },
+	{ 0x6e28, 0x00 },
+	{ 0x6e29, 0x75 },
+	{ 0x6e2a, 0x00 },
+	{ 0x6e2b, 0x75 },
+	{ 0x6e2c, 0x00 },
+	{ 0x6e2d, 0x75 },
+	{ 0x6e2e, 0x00 },
+	{ 0x6e2f, 0x75 },
+	{ 0x6e30, 0x00 },
+	{ 0x6e31, 0x75 },
+	{ 0x6e32, 0x00 },
+	{ 0x6e33, 0x75 },
+	{ 0x6e34, 0x00 },
+	{ 0x6e35, 0x75 },
+	{ 0x6e36, 0x00 },
+	{ 0x6e37, 0x75 },
+	{ 0x6e38, 0x00 },
+	{ 0x6e39, 0x75 },
+	{ 0x6e3a, 0x00 },
+	{ 0x6e3b, 0x75 },
+	{ 0x6e3c, 0x00 },
+	{ 0x6e3d, 0x75 },
+	{ 0x6e3e, 0x00 },
+	{ 0x6e3f, 0x75 },
+	{ 0x6e40, 0x00 },
+	{ 0x6e41, 0x75 },
+	{ 0x6e42, 0x00 },
+	{ 0x6e43, 0x75 },
+	{ 0x6e44, 0x00 },
+	{ 0x6e45, 0x75 },
+	{ 0x6e46, 0x00 },
+	{ 0x6e47, 0x75 },
+	{ 0x6e48, 0x00 },
+	{ 0x6e49, 0x75 },
+	{ 0x6e4a, 0x00 },
+	{ 0x6e4b, 0x75 },
+	{ 0x6e4c, 0x00 },
+	{ 0x6e4d, 0x75 },
+	{ 0x6e4e, 0x00 },
+	{ 0x6e4f, 0x75 },
+	{ 0x6e50, 0x00 },
+	{ 0x6e51, 0x75 },
+	{ 0x6e52, 0x00 },
+	{ 0x6e53, 0x75 },
+	{ 0x6e54, 0x00 },
+	{ 0x6e55, 0x75 },
+	{ 0x6e56, 0x00 },
+	{ 0x6e57, 0x75 },
+	{ 0x6e58, 0x00 },
+	{ 0x6e59, 0x75 },
+	{ 0x6e5a, 0x00 },
+	{ 0x6e5b, 0x75 },
+	{ 0x6e5c, 0x00 },
+	{ 0x6e5d, 0x75 },
+	{ 0x6e5e, 0x00 },
+	{ 0x6e5f, 0x75 },
+	{ 0x6e60, 0x00 },
+	{ 0x6e61, 0x75 },
+	{ 0x6e62, 0x00 },
+	{ 0x6e63, 0x75 },
+	{ 0x6e64, 0x00 },
+	{ 0x6e65, 0x75 },
+	{ 0x6e66, 0x00 },
+	{ 0x6e67, 0x75 },
+	{ 0x6e68, 0x00 },
+	{ 0x6e69, 0x75 },
+	{ 0x6e6a, 0x00 },
+	{ 0x6e6b, 0x75 },
+	{ 0x6e6c, 0x00 },
+	{ 0x6e6d, 0x75 },
+	{ 0x6e6e, 0x00 },
+	{ 0x6e6f, 0x75 },
+	{ 0x6e70, 0x00 },
+	{ 0x6e71, 0x75 },
+	{ 0x6e72, 0x00 },
+	{ 0x6e73, 0x75 },
+	{ 0x6e74, 0x00 },
+	{ 0x6e75, 0x75 },
+	{ 0x6e76, 0x00 },
+	{ 0x6e77, 0x75 },
+	{ 0x6e78, 0x00 },
+	{ 0x6e79, 0x75 },
+	{ 0x6e7a, 0x00 },
+	{ 0x6e7b, 0x75 },
+	{ 0x6e7c, 0x00 },
+	{ 0x6e7d, 0x75 },
+	{ 0x6e7e, 0x00 },
+	{ 0x6e7f, 0x75 },
+	{ 0x6e80, 0x00 },
+	{ 0x6e81, 0x75 },
+	{ 0x6e82, 0x00 },
+	{ 0x6e83, 0x75 },
+	{ 0x6e84, 0x00 },
+	{ 0x6e85, 0x75 },
+	{ 0x6e86, 0x00 },
+	{ 0x6e87, 0x75 },
+	{ 0x6e88, 0x00 },
+	{ 0x6e89, 0x75 },
+	{ 0x6e8a, 0x00 },
+	{ 0x6e8b, 0x75 },
+	{ 0x6e8c, 0x00 },
+	{ 0x6e8d, 0x75 },
+	{ 0x6e8e, 0x00 },
+	{ 0x6e8f, 0x75 },
+	{ 0x6e90, 0x00 },
+	{ 0x6e91, 0x75 },
+	{ 0x6e92, 0x00 },
+	{ 0x6e93, 0x75 },
+	{ 0x6e94, 0x00 },
+	{ 0x6e95, 0x75 },
+	{ 0x6e96, 0x00 },
+	{ 0x6e97, 0x75 },
+	{ 0x6e98, 0x00 },
+	{ 0x6e99, 0x75 },
+	{ 0x6e9a, 0x00 },
+	{ 0x6e9b, 0x75 },
+	{ 0x6e9c, 0x00 },
+	{ 0x6e9d, 0x75 },
+	{ 0x6e9e, 0x00 },
+	{ 0x6e9f, 0x75 },
+	{ 0x6ea0, 0x00 },
+	{ 0x6ea1, 0x75 },
+	{ 0x6ea2, 0x00 },
+	{ 0x6ea3, 0x75 },
+	{ 0x6ea4, 0x00 },
+	{ 0x6ea5, 0x75 },
+	{ 0x6ea6, 0x00 },
+	{ 0x6ea7, 0x75 },
+	{ 0x6ea8, 0x00 },
+	{ 0x6ea9, 0x75 },
+	{ 0x6eaa, 0x00 },
+	{ 0x6eab, 0x75 },
+	{ 0x6eac, 0x00 },
+	{ 0x6ead, 0x75 },
+	{ 0x6eae, 0x00 },
+	{ 0x6eaf, 0x75 },
+	{ 0x6eb0, 0x00 },
+	{ 0x6eb1, 0x75 },
+	{ 0x6eb2, 0x00 },
+	{ 0x6eb3, 0x75 },
+	{ 0x6eb4, 0x00 },
+	{ 0x6eb5, 0x75 },
+	{ 0x6eb6, 0x00 },
+	{ 0x6eb7, 0x75 },
+	{ 0x6eb8, 0x00 },
+	{ 0x6eb9, 0x75 },
+	{ 0x6eba, 0x00 },
+	{ 0x6ebb, 0x75 },
+	{ 0x6ebc, 0x00 },
+	{ 0x6ebd, 0x75 },
+	{ 0x6ebe, 0x00 },
+	{ 0x6ebf, 0x75 },
+	{ 0x6ec0, 0x00 },
+	{ 0x6ec1, 0x75 },
+	{ 0x6ec2, 0x00 },
+	{ 0x6ec3, 0x75 },
+	{ 0x6ec4, 0x00 },
+	{ 0x6ec5, 0x75 },
+	{ 0x6ec6, 0x00 },
+	{ 0x6ec7, 0x75 },
+	{ 0x6ec8, 0x00 },
+	{ 0x6ec9, 0x75 },
+	{ 0x6eca, 0x00 },
+	{ 0x6ecb, 0x75 },
+	{ 0x6ecc, 0x00 },
+	{ 0x6ecd, 0x75 },
+	{ 0x6ece, 0x00 },
+	{ 0x6ecf, 0x75 },
+	{ 0x6ed0, 0x00 },
+	{ 0x6ed1, 0x75 },
+	{ 0x6ed2, 0x00 },
+	{ 0x6ed3, 0x75 },
+	{ 0x6ed4, 0x00 },
+	{ 0x6ed5, 0x75 },
+	{ 0x6ed6, 0x00 },
+	{ 0x6ed7, 0x75 },
+	{ 0x6ed8, 0x00 },
+	{ 0x6ed9, 0x75 },
+	{ 0x6eda, 0x00 },
+	{ 0x6edb, 0x75 },
+	{ 0x6edc, 0x00 },
+	{ 0x6edd, 0x75 },
+	{ 0x6ede, 0x00 },
+	{ 0x6edf, 0x75 },
+	{ 0x6ee0, 0x00 },
+	{ 0x6ee1, 0x75 },
+	{ 0x6ee2, 0x00 },
+	{ 0x6ee3, 0x75 },
+	{ 0x6ee4, 0x00 },
+	{ 0x6ee5, 0x75 },
+	{ 0x6ee6, 0x00 },
+	{ 0x6ee7, 0x75 },
+	{ 0x6ee8, 0x00 },
+	{ 0x6ee9, 0x75 },
+	{ 0x6eea, 0x00 },
+	{ 0x6eeb, 0x75 },
+	{ 0x6eec, 0x00 },
+	{ 0x6eed, 0x75 },
+	{ 0x6eee, 0x00 },
+	{ 0x6eef, 0x75 },
+	{ 0x6ef0, 0x00 },
+	{ 0x6ef1, 0x75 },
+	{ 0x6ef2, 0x00 },
+	{ 0x6ef3, 0x75 },
+	{ 0x6ef4, 0x00 },
+	{ 0x6ef5, 0x75 },
+	{ 0x6ef6, 0x00 },
+	{ 0x6ef7, 0x75 },
+	{ 0x6ef8, 0x00 },
+	{ 0x6ef9, 0x75 },
+	{ 0x6efa, 0x00 },
+	{ 0x6efb, 0x75 },
+	{ 0x6efc, 0x00 },
+	{ 0x6efd, 0x75 },
+	{ 0x6efe, 0x00 },
+	{ 0x6eff, 0x75 },
+	{ 0x6f00, 0x00 },
+	{ 0x6f01, 0x75 },
+	{ 0x6f02, 0x00 },
+	{ 0x6f03, 0x75 },
+	{ 0x6f04, 0x00 },
+	{ 0x6f05, 0x75 },
+	{ 0x6f06, 0x00 },
+	{ 0x6f07, 0x75 },
+	{ 0x6f08, 0x00 },
+	{ 0x6f09, 0x75 },
+	{ 0x6f0a, 0x00 },
+	{ 0x6f0b, 0x75 },
+	{ 0x6f0c, 0x00 },
+	{ 0x6f0d, 0x75 },
+	{ 0x6f0e, 0x00 },
+	{ 0x6f0f, 0x75 },
+	{ 0x6f10, 0x00 },
+	{ 0x6f11, 0x75 },
+	{ 0x6f12, 0x00 },
+	{ 0x6f13, 0x75 },
+	{ 0x6f14, 0x00 },
+	{ 0x6f15, 0x75 },
+	{ 0x6f16, 0x00 },
+	{ 0x6f17, 0x75 },
+	{ 0x6f18, 0x00 },
+	{ 0x6f19, 0x75 },
+	{ 0x6f1a, 0x00 },
+	{ 0x6f1b, 0x75 },
+	{ 0x6f1c, 0x00 },
+	{ 0x6f1d, 0x75 },
+	{ 0x6f1e, 0x00 },
+	{ 0x6f1f, 0x75 },
+	{ 0x6f20, 0x00 },
+	{ 0x6f21, 0x75 },
+	{ 0x6f22, 0x00 },
+	{ 0x6f23, 0x75 },
+	{ 0x6f24, 0x00 },
+	{ 0x6f25, 0x75 },
+	{ 0x6f26, 0x00 },
+	{ 0x6f27, 0x75 },
+	{ 0x6f28, 0x00 },
+	{ 0x6f29, 0x75 },
+	{ 0x6f2a, 0x00 },
+	{ 0x6f2b, 0x75 },
+	{ 0x6f2c, 0x00 },
+	{ 0x6f2d, 0x75 },
+	{ 0x6f2e, 0x00 },
+	{ 0x6f2f, 0x75 },
+	{ 0x6f30, 0x00 },
+	{ 0x6f31, 0x75 },
+	{ 0x6f32, 0x00 },
+	{ 0x6f33, 0x75 },
+	{ 0x6f34, 0x00 },
+	{ 0x6f35, 0x75 },
+	{ 0x6f36, 0x00 },
+	{ 0x6f37, 0x75 },
+	{ 0x6f38, 0x00 },
+	{ 0x6f39, 0x75 },
+	{ 0x6f3a, 0x00 },
+	{ 0x6f3b, 0x75 },
+	{ 0x6f3c, 0x00 },
+	{ 0x6f3d, 0x75 },
+	{ 0x6f3e, 0x00 },
+	{ 0x6f3f, 0x75 },
+	{ 0x6f40, 0x00 },
+	{ 0x6f41, 0x75 },
+	{ 0x6f42, 0x00 },
+	{ 0x6f43, 0x75 },
+	{ 0x6f44, 0x00 },
+	{ 0x6f45, 0x75 },
+	{ 0x6f46, 0x00 },
+	{ 0x6f47, 0x75 },
+	{ 0x6f48, 0x00 },
+	{ 0x6f49, 0x75 },
+	{ 0x6f4a, 0x00 },
+	{ 0x6f4b, 0x75 },
+	{ 0x6f4c, 0x00 },
+	{ 0x6f4d, 0x75 },
+	{ 0x6f4e, 0x00 },
+	{ 0x6f4f, 0x75 },
+	{ 0x6f50, 0x00 },
+	{ 0x6f51, 0x75 },
+	{ 0x6f52, 0x00 },
+	{ 0x6f53, 0x75 },
+	{ 0x6f54, 0x00 },
+	{ 0x6f55, 0x75 },
+	{ 0x6f56, 0x00 },
+	{ 0x6f57, 0x75 },
+	{ 0x6f58, 0x00 },
+	{ 0x6f59, 0x75 },
+	{ 0x6f5a, 0x00 },
+	{ 0x6f5b, 0x75 },
+	{ 0x6f5c, 0x00 },
+	{ 0x6f5d, 0x75 },
+	{ 0x6f5e, 0x00 },
+	{ 0x6f5f, 0x75 },
+	{ 0x6f60, 0x00 },
+	{ 0x6f61, 0x75 },
+	{ 0x6f62, 0x00 },
+	{ 0x6f63, 0x75 },
+	{ 0x6f64, 0x00 },
+	{ 0x6f65, 0x75 },
+	{ 0x6f66, 0x00 },
+	{ 0x6f67, 0x75 },
+	{ 0x6f68, 0x00 },
+	{ 0x6f69, 0x75 },
+	{ 0x6f6a, 0x00 },
+	{ 0x6f6b, 0x75 },
+	{ 0x6f6c, 0x00 },
+	{ 0x6f6d, 0x75 },
+	{ 0x6f6e, 0x00 },
+	{ 0x6f6f, 0x75 },
+	{ 0x6f70, 0x00 },
+	{ 0x6f71, 0x75 },
+	{ 0x6f72, 0x00 },
+	{ 0x6f73, 0x75 },
+	{ 0x6f74, 0x00 },
+	{ 0x6f75, 0x75 },
+	{ 0x6f76, 0x00 },
+	{ 0x6f77, 0x75 },
+	{ 0x6f78, 0x00 },
+	{ 0x6f79, 0x75 },
+	{ 0x6f7a, 0x00 },
+	{ 0x6f7b, 0x75 },
+	{ 0x6f7c, 0x00 },
+	{ 0x6f7d, 0x75 },
+	{ 0x6f7e, 0x00 },
+	{ 0x6f7f, 0x75 },
+	{ 0x6f80, 0x00 },
+	{ 0x6f81, 0x75 },
+	{ 0x6f82, 0x00 },
+	{ 0x6f83, 0x75 },
+	{ 0x6f84, 0x00 },
+	{ 0x6f85, 0x75 },
+	{ 0x6f86, 0x00 },
+	{ 0x6f87, 0x75 },
+	{ 0x6f88, 0x00 },
+	{ 0x6f89, 0x75 },
+	{ 0x6f8a, 0x00 },
+	{ 0x6f8b, 0x75 },
+	{ 0x6f8c, 0x00 },
+	{ 0x6f8d, 0x75 },
+	{ 0x6f8e, 0x00 },
+	{ 0x6f8f, 0x75 },
+	{ 0x6f90, 0x00 },
+	{ 0x6f91, 0x75 },
+	{ 0x6f92, 0x00 },
+	{ 0x6f93, 0x75 },
+	{ 0x6f94, 0x00 },
+	{ 0x6f95, 0x75 },
+	{ 0x6f96, 0x00 },
+	{ 0x6f97, 0x75 },
+	{ 0x6f98, 0x00 },
+	{ 0x6f99, 0x75 },
+	{ 0x6f9a, 0x00 },
+	{ 0x6f9b, 0x75 },
+	{ 0x6f9c, 0x00 },
+	{ 0x6f9d, 0x75 },
+	{ 0x6f9e, 0x00 },
+	{ 0x6f9f, 0x75 },
+	{ 0x6fa0, 0x00 },
+	{ 0x6fa1, 0x75 },
+	{ 0x6fa2, 0x00 },
+	{ 0x6fa3, 0x75 },
+	{ 0x6fa4, 0x00 },
+	{ 0x6fa5, 0x75 },
+	{ 0x6fa6, 0x00 },
+	{ 0x6fa7, 0x75 },
+	{ 0x6fa8, 0x00 },
+	{ 0x6fa9, 0x75 },
+	{ 0x6faa, 0x00 },
+	{ 0x6fab, 0x75 },
+	{ 0x6fac, 0x00 },
+	{ 0x6fad, 0x75 },
+	{ 0x6fae, 0x00 },
+	{ 0x6faf, 0x75 },
+	{ 0x6fb0, 0x00 },
+	{ 0x6fb1, 0x75 },
+	{ 0x6fb2, 0x00 },
+	{ 0x6fb3, 0x75 },
+	{ 0x6fb4, 0x00 },
+	{ 0x6fb5, 0x75 },
+	{ 0x6fb6, 0x00 },
+	{ 0x6fb7, 0x75 },
+	{ 0x6fb8, 0x00 },
+	{ 0x6fb9, 0x75 },
+	{ 0x6fba, 0x00 },
+	{ 0x6fbb, 0x75 },
+	{ 0x6fbc, 0x00 },
+	{ 0x6fbd, 0x75 },
+	{ 0x6fbe, 0x00 },
+	{ 0x6fbf, 0x75 },
+	{ 0x6fc0, 0x00 },
+	{ 0x6fc1, 0x75 },
+	{ 0x6fc2, 0x00 },
+	{ 0x6fc3, 0x75 },
+	{ 0x6fc4, 0x00 },
+	{ 0x6fc5, 0x75 },
+	{ 0x6fc6, 0x00 },
+	{ 0x6fc7, 0x75 },
+	{ 0x6fc8, 0x00 },
+	{ 0x6fc9, 0x75 },
+	{ 0x6fca, 0x00 },
+	{ 0x6fcb, 0x75 },
+	{ 0x6fcc, 0x00 },
+	{ 0x6fcd, 0x75 },
+	{ 0x6fce, 0x00 },
+	{ 0x6fcf, 0x75 },
+	{ 0x6fd0, 0x00 },
+	{ 0x6fd1, 0x75 },
+	{ 0x6fd2, 0x00 },
+	{ 0x6fd3, 0x75 },
+	{ 0x6fd4, 0x00 },
+	{ 0x6fd5, 0x75 },
+	{ 0x6fd6, 0x00 },
+	{ 0x6fd7, 0x75 },
+	{ 0x6fd8, 0x00 },
+	{ 0x6fd9, 0x75 },
+	{ 0x6fda, 0x00 },
+	{ 0x6fdb, 0x75 },
+	{ 0x6fdc, 0x00 },
+	{ 0x6fdd, 0x75 },
+	{ 0x6fde, 0x00 },
+	{ 0x6fdf, 0x75 },
+	{ 0x6fe0, 0x00 },
+	{ 0x6fe1, 0x75 },
+	{ 0x6fe2, 0x00 },
+	{ 0x6fe3, 0x75 },
+	{ 0x6fe4, 0x00 },
+	{ 0x6fe5, 0x75 },
+	{ 0x6fe6, 0x00 },
+	{ 0x6fe7, 0x75 },
+	{ 0x6fe8, 0x00 },
+	{ 0x6fe9, 0x75 },
+	{ 0x6fea, 0x00 },
+	{ 0x6feb, 0x75 },
+	{ 0x6fec, 0x00 },
+	{ 0x6fed, 0x75 },
+	{ 0x6fee, 0x00 },
+	{ 0x6fef, 0x75 },
+	{ 0x6ff0, 0x00 },
+	{ 0x6ff1, 0x75 },
+	{ 0x6ff2, 0x00 },
+	{ 0x6ff3, 0x75 },
+	{ 0x6ff4, 0x00 },
+	{ 0x6ff5, 0x75 },
+	{ 0x6ff6, 0x00 },
+	{ 0x6ff7, 0x75 },
+	{ 0x6ff8, 0x00 },
+	{ 0x6ff9, 0x75 },
+	{ 0x6ffa, 0x00 },
+	{ 0x6ffb, 0x75 },
+	{ 0x6ffc, 0x00 },
+	{ 0x6ffd, 0x75 },
+	{ 0x6ffe, 0x00 },
+	{ 0x6fff, 0x75 },
+	{ 0x7000, 0x00 },
+	{ 0x7001, 0x75 },
+	{ 0x7002, 0x00 },
+	{ 0x7003, 0x75 },
+	{ 0x7004, 0x00 },
+	{ 0x7005, 0x75 },
+	{ 0x7006, 0x00 },
+	{ 0x7007, 0x75 },
+	{ 0x7008, 0x00 },
+	{ 0x7009, 0x75 },
+	{ 0x700a, 0x00 },
+	{ 0x700b, 0x75 },
+	{ 0x700c, 0x00 },
+	{ 0x700d, 0x75 },
+	{ 0x700e, 0x00 },
+	{ 0x700f, 0x75 },
+	{ 0x7010, 0x00 },
+	{ 0x7011, 0x75 },
+	{ 0x7012, 0x00 },
+	{ 0x7013, 0x75 },
+	{ 0x7014, 0x00 },
+	{ 0x7015, 0x75 },
+	{ 0x7016, 0x00 },
+	{ 0x7017, 0x75 },
+	{ 0x7018, 0x00 },
+	{ 0x7019, 0x75 },
+	{ 0x701a, 0x00 },
+	{ 0x701b, 0x75 },
+	{ 0x701c, 0x00 },
+	{ 0x701d, 0x75 },
+	{ 0x701e, 0x00 },
+	{ 0x701f, 0x75 },
+	{ 0x7020, 0x00 },
+	{ 0x7021, 0x75 },
+	{ 0x7022, 0x00 },
+	{ 0x7023, 0x75 },
+	{ 0x7024, 0x00 },
+	{ 0x7025, 0x75 },
+	{ 0x7026, 0x00 },
+	{ 0x7027, 0x75 },
+	{ 0x7028, 0x00 },
+	{ 0x7029, 0x75 },
+	{ 0x702a, 0x00 },
+	{ 0x702b, 0x75 },
+	{ 0x702c, 0x00 },
+	{ 0x702d, 0x75 },
+	{ 0x702e, 0x00 },
+	{ 0x702f, 0x75 },
+	{ 0x7030, 0x00 },
+	{ 0x7031, 0x75 },
+	{ 0x7032, 0x00 },
+	{ 0x7033, 0x75 },
+	{ 0x7034, 0x00 },
+	{ 0x7035, 0x75 },
+	{ 0x7036, 0x00 },
+	{ 0x7037, 0x75 },
+	{ 0x7038, 0x00 },
+	{ 0x7039, 0x75 },
+	{ 0x703a, 0x00 },
+	{ 0x703b, 0x75 },
+	{ 0x703c, 0x00 },
+	{ 0x703d, 0x75 },
+	{ 0x703e, 0x00 },
+	{ 0x703f, 0x75 },
+	{ 0x7040, 0x00 },
+	{ 0x7041, 0x75 },
+	{ 0x7042, 0x00 },
+	{ 0x7043, 0x75 },
+	{ 0x7044, 0x00 },
+	{ 0x7045, 0x75 },
+	{ 0x7046, 0x00 },
+	{ 0x7047, 0x75 },
+	{ 0x7048, 0x00 },
+	{ 0x7049, 0x75 },
+	{ 0x704a, 0x00 },
+	{ 0x704b, 0x75 },
+	{ 0x704c, 0x00 },
+	{ 0x704d, 0x75 },
+	{ 0x704e, 0x00 },
+	{ 0x704f, 0x75 },
+	{ 0x7050, 0x00 },
+	{ 0x7051, 0x75 },
+	{ 0x7052, 0x00 },
+	{ 0x7053, 0x75 },
+	{ 0x7054, 0x00 },
+	{ 0x7055, 0x75 },
+	{ 0x7056, 0x00 },
+	{ 0x7057, 0x75 },
+	{ 0x7058, 0x00 },
+	{ 0x7059, 0x75 },
+	{ 0x705a, 0x00 },
+	{ 0x705b, 0x75 },
+	{ 0x705c, 0x00 },
+	{ 0x705d, 0x75 },
+	{ 0x705e, 0x00 },
+	{ 0x705f, 0x75 },
+	{ 0x7060, 0x00 },
+	{ 0x7061, 0x75 },
+	{ 0x7062, 0x00 },
+	{ 0x7063, 0x75 },
+	{ 0x7064, 0x00 },
+	{ 0x7065, 0x75 },
+	{ 0x7066, 0x00 },
+	{ 0x7067, 0x75 },
+	{ 0x7068, 0x00 },
+	{ 0x7069, 0x75 },
+	{ 0x706a, 0x00 },
+	{ 0x706b, 0x75 },
+	{ 0x706c, 0x00 },
+	{ 0x706d, 0x75 },
+	{ 0x706e, 0x00 },
+	{ 0x706f, 0x75 },
+	{ 0x7070, 0x00 },
+	{ 0x7071, 0x75 },
+	{ 0x7072, 0x00 },
+	{ 0x7073, 0x75 },
+	{ 0x7074, 0x00 },
+	{ 0x7075, 0x75 },
+	{ 0x7076, 0x00 },
+	{ 0x7077, 0x75 },
+	{ 0x7078, 0x00 },
+	{ 0x7079, 0x75 },
+	{ 0x707a, 0x00 },
+	{ 0x707b, 0x75 },
+	{ 0x707c, 0x00 },
+	{ 0x707d, 0x75 },
+	{ 0x707e, 0x00 },
+	{ 0x707f, 0x75 },
+	{ 0x70e4, 0x02 },
+	{ 0x70e6, 0x06 },
+	{ 0x70e7, 0x08 },
+	{ 0x70e8, 0x0a },
+	{ 0x70e9, 0x0c },
+	{ 0x70ea, 0x10 },
+	{ 0x70eb, 0x16 },
+	{ 0x70ec, 0x1a },
+	{ 0x70ed, 0x20 },
+	{ 0x70ee, 0x04 },
+	{ 0x70ef, 0x06 },
+	{ 0x70f0, 0x08 },
+	{ 0x70f1, 0x0a },
+	{ 0x70f2, 0x10 },
+	{ 0x70f3, 0x16 },
+	{ 0x70f4, 0x1a },
+	{ 0x70f5, 0x20 },
+	{ 0x7119, 0x16 },
+	{ 0x711b, 0x1a },
+	{ 0x713a, 0x19 },
+	{ 0x713b, 0x17 },
+	{ 0x713c, 0x15 },
+	{ 0x713d, 0x13 },
+	{ 0x713e, 0x11 },
+	{ 0x713f, 0x11 },
+	{ 0x7140, 0x11 },
+	{ 0x7141, 0x11 },
+	{ 0x7142, 0x12 },
+	{ 0x7143, 0x0d },
+	{ 0x7144, 0x0b },
+	{ 0x7145, 0x0b },
+	{ 0x7146, 0x09 },
+	{ 0x7147, 0x09 },
+	{ 0x7148, 0x09 },
+	{ 0x7149, 0x08 },
+	{ 0x7150, 0x00 },
+};
+
+static const s64 link_freq_menu_items[] = {
+	OV32C4_LINK_FREQ_400MHZ,
+};
+
+static const struct ov32c4_mode supported_modes[] = {
+	{
+		.width = 3264,
+		.height = 1840,
+		.ppl = 4080,
+		.vts_min = 2614,
+		.reg_sequence = ov32c4_mode_3264x1840_regs,
+		.sequence_length = ARRAY_SIZE(ov32c4_mode_3264x1840_regs),
+	},
+};
+
+struct ov32c4 {
+	struct device *dev;
+
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct regmap *regmap;
+
+	/* The sensor's second I2C address, see OV32C4_COMPANION_ENABLE_REG */
+	struct regmap *companion;
+	u16 companion_addr;
+
+	/* V4L2 controls */
+	struct v4l2_ctrl *link_freq;
+	struct v4l2_ctrl *pixel_rate;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *hblank;
+	struct v4l2_ctrl *exposure;
+
+	struct clk *img_clk;
+	struct gpio_desc *reset;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(ov32c4_supply_names)];
+
+	u32 link_freq_index;
+	u8 mipi_lanes;
+};
+
+#ifdef CONFIG_ACPI
+/*
+ * Walk the sensor's ACPI _CRS and return the address of the n-th
+ * I2cSerialBus resource. Index 0 is the sensor itself (the kernel binds the
+ * i2c client to it), index 1 is the companion, index 2 the module EEPROM.
+ */
+struct ov32c4_i2c_res_ctx {
+	int index;
+	int want;
+	u16 addr;
+};
+
+static int ov32c4_i2c_res_cb(struct acpi_resource *ares, void *data)
+{
+	struct ov32c4_i2c_res_ctx *ctx = data;
+	struct acpi_resource_i2c_serialbus *sb;
+
+	if (i2c_acpi_get_i2c_resource(ares, &sb)) {
+		if (ctx->index == ctx->want)
+			ctx->addr = sb->slave_address;
+		ctx->index++;
+	}
+
+	return 1;
+}
+
+static u16 ov32c4_acpi_i2c_addr(struct device *dev, int index)
+{
+	struct ov32c4_i2c_res_ctx ctx = { .want = index };
+	struct acpi_device *adev = ACPI_COMPANION(dev);
+	LIST_HEAD(resources);
+	int ret;
+
+	if (!adev)
+		return 0;
+
+	ret = acpi_dev_get_resources(adev, &resources, ov32c4_i2c_res_cb, &ctx);
+	acpi_dev_free_resource_list(&resources);
+
+	return ret < 0 ? 0 : ctx.addr;
+}
+#else
+static u16 ov32c4_acpi_i2c_addr(struct device *dev, int index)
+{
+	return 0;
+}
+#endif
+
+static inline struct ov32c4 *to_ov32c4(struct v4l2_subdev *subdev)
+{
+	return container_of(subdev, struct ov32c4, sd);
+}
+
+/* MIPI D-PHY is DDR -> link frequency * 2 */
+static u64 ov32c4_pixel_rate(struct ov32c4 *ov32c4)
+{
+	return div_u64(link_freq_menu_items[ov32c4->link_freq_index] *
+		       2 * ov32c4->mipi_lanes, OV32C4_RGB_DEPTH);
+}
+
+static int ov32c4_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov32c4 *ov32c4 = container_of(ctrl->handler,
+					     struct ov32c4, ctrl_handler);
+	const u32 height = supported_modes[0].height;
+	s64 exposure_max;
+	int ret = 0;
+	int pm;
+
+	if (ctrl->id == V4L2_CID_VBLANK) {
+		exposure_max = height + ctrl->val - OV32C4_EXPOSURE_MAX_MARGIN;
+		ret = __v4l2_ctrl_modify_range(ov32c4->exposure,
+					       ov32c4->exposure->minimum,
+					       exposure_max,
+					       ov32c4->exposure->step,
+					       exposure_max);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * A negative return means runtime PM is disabled for the device, in
+	 * which case it is powered and the registers can be written, but no
+	 * reference was taken and none may be dropped below.
+	 */
+	pm = pm_runtime_get_if_active(ov32c4->dev);
+	if (!pm)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ANALOGUE_GAIN:
+		cci_write(ov32c4->regmap, OV32C4_REG_ANALOG_GAIN,
+			  ctrl->val, &ret);
+		cci_write(ov32c4->regmap, OV32C4_REG_ANALOG_GAIN_CTX2,
+			  ctrl->val, &ret);
+		break;
+
+	case V4L2_CID_EXPOSURE:
+		cci_write(ov32c4->regmap, OV32C4_REG_EXPOSURE,
+			  ctrl->val, &ret);
+		cci_write(ov32c4->regmap, OV32C4_REG_EXPOSURE_CTX2,
+			  ctrl->val, &ret);
+		break;
+
+	case V4L2_CID_VBLANK:
+		cci_write(ov32c4->regmap, OV32C4_REG_VTS, height + ctrl->val,
+			  &ret);
+		break;
+
+	case V4L2_CID_DIGITAL_GAIN:
+		cci_write(ov32c4->regmap, OV32C4_REG_DIGITAL_GAIN,
+			  (u64)ctrl->val << OV32C4_DGAIN_SHIFT, &ret);
+		cci_write(ov32c4->regmap, OV32C4_REG_DIGITAL_GAIN_CTX2,
+			  (u64)ctrl->val << OV32C4_DGAIN_SHIFT, &ret);
+		break;
+
+	case V4L2_CID_HFLIP:
+		cci_update_bits(ov32c4->regmap, OV32C4_REG_MIRROR,
+				OV32C4_FLIP_BIT,
+				ctrl->val ? 0 : OV32C4_FLIP_BIT, &ret);
+		break;
+
+	case V4L2_CID_VFLIP:
+		cci_update_bits(ov32c4->regmap, OV32C4_REG_FLIP,
+				OV32C4_FLIP_BIT,
+				ctrl->val ? OV32C4_FLIP_BIT : 0, &ret);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (pm > 0)
+		pm_runtime_put(ov32c4->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov32c4_ctrl_ops = {
+	.s_ctrl = ov32c4_set_ctrl,
+};
+
+static int ov32c4_init_controls(struct ov32c4 *ov32c4)
+{
+	struct v4l2_ctrl_handler *ctrl_hdlr = &ov32c4->ctrl_handler;
+	const struct ov32c4_mode *mode = &supported_modes[0];
+	u32 vblank_min, vblank_max, vblank_default;
+	struct v4l2_fwnode_device_properties props;
+	s64 exposure_max, h_blank, pixel_rate;
+	int ret;
+
+	ret = v4l2_fwnode_device_parse(ov32c4->dev, &props);
+	if (ret)
+		return ret;
+
+	v4l2_ctrl_handler_init(ctrl_hdlr, 13);
+
+	ov32c4->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov32c4_ctrl_ops,
+						   V4L2_CID_LINK_FREQ,
+						   ARRAY_SIZE(link_freq_menu_items) - 1,
+						   ov32c4->link_freq_index,
+						   link_freq_menu_items);
+
+	pixel_rate = ov32c4_pixel_rate(ov32c4);
+	ov32c4->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops,
+					       V4L2_CID_PIXEL_RATE, 0,
+					       pixel_rate, 1, pixel_rate);
+
+	vblank_min = mode->vts_min - mode->height;
+	vblank_max = OV32C4_VTS_MAX - mode->height;
+	vblank_default = vblank_min;
+	ov32c4->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops,
+					   V4L2_CID_VBLANK, vblank_min,
+					   vblank_max, 1, vblank_default);
+
+	h_blank = mode->ppl - mode->width;
+	ov32c4->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops,
+					   V4L2_CID_HBLANK, h_blank, h_blank,
+					   1, h_blank);
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+			  OV32C4_ANA_GAIN_MIN, OV32C4_ANA_GAIN_MAX,
+			  OV32C4_ANA_GAIN_STEP, OV32C4_ANA_GAIN_DEFAULT);
+
+	exposure_max = mode->vts_min - OV32C4_EXPOSURE_MAX_MARGIN;
+	ov32c4->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops,
+					     V4L2_CID_EXPOSURE,
+					     OV32C4_EXPOSURE_MIN, exposure_max,
+					     OV32C4_EXPOSURE_STEP,
+					     exposure_max);
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+			  OV32C4_DGAIN_MIN, OV32C4_DGAIN_MAX,
+			  OV32C4_DGAIN_STEP, OV32C4_DGAIN_DEFAULT);
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops, V4L2_CID_HFLIP,
+			  0, 1, 1, 0);
+	v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops, V4L2_CID_VFLIP,
+			  0, 1, 1, 0);
+
+	v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov32c4_ctrl_ops, &props);
+
+	if (ctrl_hdlr->error)
+		return ctrl_hdlr->error;
+
+	ov32c4->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	ov32c4->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	ov32c4->sd.ctrl_handler = ctrl_hdlr;
+
+	return 0;
+}
+
+static void ov32c4_update_pad_format(const struct ov32c4_mode *mode,
+				     struct v4l2_mbus_framefmt *fmt)
+{
+	fmt->width = mode->width;
+	fmt->height = mode->height;
+	fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+	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 ov32c4_enable_streams(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *state,
+				 u32 pad, u64 streams_mask)
+{
+	const struct ov32c4_mode *mode = &supported_modes[0];
+	struct ov32c4 *ov32c4 = to_ov32c4(sd);
+	int ret;
+
+	ret = pm_runtime_resume_and_get(ov32c4->dev);
+	if (ret)
+		return ret;
+
+	cci_write(ov32c4->regmap, OV32C4_REG_STREAM_CONTROL, 0, &ret);
+	cci_write(ov32c4->regmap, OV32C4_REG_SW_RESET, 1, &ret);
+	if (ret) {
+		dev_err(ov32c4->dev, "failed to reset the sensor: %d\n", ret);
+		goto out;
+	}
+	fsleep(OV32C4_SW_RESET_SETTLE_US);
+
+	ret = regmap_multi_reg_write(ov32c4->regmap, mode->reg_sequence,
+				     mode->sequence_length);
+	if (ret) {
+		dev_err(ov32c4->dev, "failed to set mode: %d\n", ret);
+		goto out;
+	}
+
+	ret = __v4l2_ctrl_handler_setup(ov32c4->sd.ctrl_handler);
+	if (ret)
+		goto out;
+
+	ret = cci_write(ov32c4->regmap, OV32C4_REG_STREAM_CONTROL, 1, NULL);
+out:
+	if (ret)
+		pm_runtime_put(ov32c4->dev);
+
+	return ret;
+}
+
+static int ov32c4_disable_streams(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state,
+				  u32 pad, u64 streams_mask)
+{
+	struct ov32c4 *ov32c4 = to_ov32c4(sd);
+	int ret;
+
+	ret = cci_write(ov32c4->regmap, OV32C4_REG_STREAM_CONTROL, 0, NULL);
+	pm_runtime_put(ov32c4->dev);
+
+	return ret;
+}
+
+static int ov32c4_get_pm_resources(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct ov32c4 *ov32c4 = to_ov32c4(sd);
+
+	/* The reset pin is active low, so a logical 1 means "held in reset". */
+	ov32c4->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(ov32c4->reset))
+		return dev_err_probe(dev, PTR_ERR(ov32c4->reset),
+				     "failed to get reset gpio\n");
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(ov32c4_supply_names); i++)
+		ov32c4->supplies[i].supply = ov32c4_supply_names[i];
+
+	return devm_regulator_bulk_get(dev, ARRAY_SIZE(ov32c4_supply_names),
+				       ov32c4->supplies);
+}
+
+/* Ungate the main address, see OV32C4_COMPANION_ENABLE_REG. */
+static int ov32c4_companion_enable(struct ov32c4 *ov32c4)
+{
+	return cci_write(ov32c4->companion, OV32C4_COMPANION_ENABLE_REG,
+			 OV32C4_COMPANION_ENABLE_VAL, NULL);
+}
+
+static int ov32c4_power_off(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct ov32c4 *ov32c4 = to_ov32c4(sd);
+
+	gpiod_set_value_cansleep(ov32c4->reset, 1);
+	regulator_bulk_disable(ARRAY_SIZE(ov32c4_supply_names),
+			       ov32c4->supplies);
+	clk_disable_unprepare(ov32c4->img_clk);
+
+	return 0;
+}
+
+static int ov32c4_power_on(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct ov32c4 *ov32c4 = to_ov32c4(sd);
+	int ret;
+
+	ret = clk_prepare_enable(ov32c4->img_clk);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable imaging clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(ov32c4_supply_names),
+				    ov32c4->supplies);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable regulators: %d\n", ret);
+		clk_disable_unprepare(ov32c4->img_clk);
+		return ret;
+	}
+
+	if (ov32c4->reset) {
+		gpiod_set_value_cansleep(ov32c4->reset, 0);
+		fsleep(OV32C4_RESET_SETTLE_US);
+	}
+
+	if (ov32c4->companion) {
+		ret = ov32c4_companion_enable(ov32c4);
+		if (ret) {
+			dev_err(dev, "the block at 0x%02x did not accept the enable write: %d\n",
+				ov32c4->companion_addr, ret);
+			goto err_power_off;
+		}
+		fsleep(OV32C4_ENABLE_SETTLE_US);
+	}
+
+	return 0;
+
+err_power_off:
+	if (ov32c4->reset)
+		gpiod_set_value_cansleep(ov32c4->reset, 1);
+	regulator_bulk_disable(ARRAY_SIZE(ov32c4_supply_names),
+			       ov32c4->supplies);
+	clk_disable_unprepare(ov32c4->img_clk);
+
+	return ret;
+}
+
+static int ov32c4_set_format(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_state *sd_state,
+			     struct v4l2_subdev_format *fmt)
+{
+	const struct ov32c4_mode *mode = &supported_modes[0];
+	struct ov32c4 *ov32c4 = to_ov32c4(sd);
+	s32 vblank_def, h_blank;
+	int ret;
+
+	ov32c4_update_pad_format(mode, &fmt->format);
+	*v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	vblank_def = mode->vts_min - mode->height;
+	ret = __v4l2_ctrl_modify_range(ov32c4->vblank, vblank_def,
+				       OV32C4_VTS_MAX - mode->height, 1,
+				       vblank_def);
+	if (ret)
+		return ret;
+
+	ret = __v4l2_ctrl_s_ctrl(ov32c4->vblank, vblank_def);
+	if (ret)
+		return ret;
+
+	h_blank = mode->ppl - mode->width;
+
+	return __v4l2_ctrl_modify_range(ov32c4->hblank, h_blank, h_blank, 1,
+					h_blank);
+}
+
+static int ov32c4_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *sd_state,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index > 0)
+		return -EINVAL;
+
+	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+
+	return 0;
+}
+
+static int ov32c4_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index >= ARRAY_SIZE(supported_modes))
+		return -EINVAL;
+
+	if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
+		return -EINVAL;
+
+	fse->min_width = supported_modes[fse->index].width;
+	fse->max_width = fse->min_width;
+	fse->min_height = supported_modes[fse->index].height;
+	fse->max_height = fse->min_height;
+
+	return 0;
+}
+
+static int ov32c4_init_state(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_state *sd_state)
+{
+	ov32c4_update_pad_format(&supported_modes[0],
+				 v4l2_subdev_state_get_format(sd_state, 0));
+
+	return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov32c4_video_ops = {
+	.s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static int ov32c4_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_state *state,
+				struct v4l2_subdev_selection *sel)
+{
+	if (sel->pad != 0)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP:
+		sel->r.left = OV32C4_CROP_LEFT;
+		sel->r.top = OV32C4_CROP_TOP;
+		sel->r.width = OV32C4_CROP_WIDTH;
+		sel->r.height = OV32C4_CROP_HEIGHT;
+		return 0;
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = OV32C4_NATIVE_WIDTH;
+		sel->r.height = OV32C4_NATIVE_HEIGHT;
+		return 0;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		sel->r.left = OV32C4_ACTIVE_LEFT;
+		sel->r.top = OV32C4_ACTIVE_TOP;
+		sel->r.width = OV32C4_ACTIVE_WIDTH;
+		sel->r.height = OV32C4_ACTIVE_HEIGHT;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct v4l2_subdev_pad_ops ov32c4_pad_ops = {
+	.set_fmt = ov32c4_set_format,
+	.get_fmt = v4l2_subdev_get_fmt,
+	.get_selection = ov32c4_get_selection,
+	.enum_mbus_code = ov32c4_enum_mbus_code,
+	.enum_frame_size = ov32c4_enum_frame_size,
+	.enable_streams = ov32c4_enable_streams,
+	.disable_streams = ov32c4_disable_streams,
+};
+
+static const struct v4l2_subdev_ops ov32c4_subdev_ops = {
+	.video = &ov32c4_video_ops,
+	.pad = &ov32c4_pad_ops,
+};
+
+static const struct media_entity_operations ov32c4_subdev_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops ov32c4_internal_ops = {
+	.init_state = ov32c4_init_state,
+};
+
+static int ov32c4_identify_module(struct ov32c4 *ov32c4)
+{
+	u64 chip_id;
+	int ret;
+
+	ret = cci_read(ov32c4->regmap, OV32C4_REG_CHIP_ID, &chip_id, NULL);
+	if (ret)
+		return dev_err_probe(ov32c4->dev, ret,
+				     "failed to read the chip id\n");
+
+	if (chip_id != OV32C4_CHIP_ID)
+		return dev_err_probe(ov32c4->dev, -ENXIO,
+				     "chip id mismatch: %x != %llx\n",
+				     OV32C4_CHIP_ID, chip_id);
+
+	return 0;
+}
+
+static int ov32c4_check_hwcfg(struct ov32c4 *ov32c4)
+{
+	struct v4l2_fwnode_endpoint bus_cfg = {
+		.bus_type = V4L2_MBUS_CSI2_DPHY
+	};
+	struct device *dev = ov32c4->dev;
+	struct fwnode_handle *ep, *fwnode = dev_fwnode(dev);
+	unsigned long link_freq_bitmap;
+	int ret;
+
+	ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
+
+	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+	fwnode_handle_put(ep);
+	if (ret)
+		return dev_err_probe(dev, ret, "parsing endpoint failed\n");
+
+	ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,
+				       bus_cfg.nr_of_link_frequencies,
+				       link_freq_menu_items,
+				       ARRAY_SIZE(link_freq_menu_items),
+				       &link_freq_bitmap);
+	if (ret)
+		goto check_hwcfg_error;
+
+	/* v4l2_link_freq_to_bitmap() guarantees at least one bit is set */
+	ov32c4->link_freq_index = ffs(link_freq_bitmap) - 1;
+
+	if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV32C4_DATA_LANES) {
+		ret = dev_err_probe(dev, -EINVAL,
+				    "number of CSI2 data lanes %u is not supported\n",
+				    bus_cfg.bus.mipi_csi2.num_data_lanes);
+		goto check_hwcfg_error;
+	}
+
+	ov32c4->mipi_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+
+check_hwcfg_error:
+	v4l2_fwnode_endpoint_free(&bus_cfg);
+	return ret;
+}
+
+static void ov32c4_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov32c4 *ov32c4 = to_ov32c4(sd);
+
+	v4l2_async_unregister_subdev(sd);
+	v4l2_subdev_cleanup(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	pm_runtime_disable(ov32c4->dev);
+	if (!pm_runtime_status_suspended(ov32c4->dev)) {
+		ov32c4_power_off(ov32c4->dev);
+		pm_runtime_set_suspended(ov32c4->dev);
+	}
+}
+
+static int ov32c4_probe(struct i2c_client *client)
+{
+	struct ov32c4 *ov32c4;
+	unsigned long freq;
+	int ret;
+
+	ov32c4 = devm_kzalloc(&client->dev, sizeof(*ov32c4), GFP_KERNEL);
+	if (!ov32c4)
+		return -ENOMEM;
+
+	ov32c4->dev = &client->dev;
+
+	ov32c4->img_clk = devm_v4l2_sensor_clk_get(ov32c4->dev, NULL);
+	if (IS_ERR(ov32c4->img_clk))
+		return dev_err_probe(ov32c4->dev, PTR_ERR(ov32c4->img_clk),
+				     "failed to get imaging clock\n");
+
+	freq = clk_get_rate(ov32c4->img_clk);
+	if (freq != OV32C4_MCLK)
+		return dev_err_probe(ov32c4->dev, -EINVAL,
+				     "external clock %lu is not supported\n",
+				     freq);
+
+	v4l2_i2c_subdev_init(&ov32c4->sd, client, &ov32c4_subdev_ops);
+
+	ret = ov32c4_check_hwcfg(ov32c4);
+	if (ret)
+		return ret;
+
+	ret = ov32c4_get_pm_resources(ov32c4->dev);
+	if (ret)
+		return ret;
+
+	ov32c4->regmap = devm_cci_regmap_init_i2c(client, 16);
+	if (IS_ERR(ov32c4->regmap))
+		return PTR_ERR(ov32c4->regmap);
+
+	/*
+	 * On the ACPI machines this sensor ships in, the main address only
+	 * answers after a write to the sensor's second address, listed as the
+	 * second I2C resource of _CRS (see OV32C4_COMPANION_ENABLE_REG). The
+	 * address is claimed here so that nothing else binds to it; the
+	 * platform's SSDB wrongly calls it a VCM, and ipu-bridge knows not to
+	 * instantiate one for this sensor.
+	 */
+	ov32c4->companion_addr = ov32c4_acpi_i2c_addr(ov32c4->dev, 1);
+	if (ov32c4->companion_addr) {
+		struct i2c_client *companion;
+
+		companion = devm_i2c_new_dummy_device(ov32c4->dev,
+						      client->adapter,
+						      ov32c4->companion_addr);
+		if (IS_ERR(companion))
+			return dev_err_probe(ov32c4->dev, PTR_ERR(companion),
+					     "failed to claim the second address 0x%02x\n",
+					     ov32c4->companion_addr);
+
+		ov32c4->companion = devm_cci_regmap_init_i2c(companion, 16);
+		if (IS_ERR(ov32c4->companion))
+			return PTR_ERR(ov32c4->companion);
+	} else if (ACPI_COMPANION(ov32c4->dev)) {
+		dev_warn(ov32c4->dev,
+			 "no second I2C address in _CRS, the sensor may not answer\n");
+	}
+
+	ret = ov32c4_power_on(ov32c4->dev);
+	if (ret) {
+		dev_err_probe(ov32c4->dev, ret, "failed to power on\n");
+		return ret;
+	}
+
+	ret = ov32c4_identify_module(ov32c4);
+	if (ret)
+		goto probe_error_power_off;
+
+	ret = ov32c4_init_controls(ov32c4);
+	if (ret) {
+		dev_err_probe(ov32c4->dev, ret, "failed to init controls\n");
+		goto probe_error_v4l2_ctrl_handler_free;
+	}
+
+	ov32c4->sd.internal_ops = &ov32c4_internal_ops;
+	ov32c4->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	ov32c4->sd.entity.ops = &ov32c4_subdev_entity_ops;
+	ov32c4->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	ov32c4->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_pads_init(&ov32c4->sd.entity, 1, &ov32c4->pad);
+	if (ret) {
+		dev_err_probe(ov32c4->dev, ret, "failed to init entity pads\n");
+		goto probe_error_v4l2_ctrl_handler_free;
+	}
+
+	ov32c4->sd.state_lock = ov32c4->ctrl_handler.lock;
+	ret = v4l2_subdev_init_finalize(&ov32c4->sd);
+	if (ret < 0) {
+		dev_err_probe(ov32c4->dev, ret, "failed to init subdev\n");
+		goto probe_error_media_entity_cleanup;
+	}
+
+	pm_runtime_set_active(ov32c4->dev);
+	pm_runtime_enable(ov32c4->dev);
+
+	ret = v4l2_async_register_subdev_sensor(&ov32c4->sd);
+	if (ret < 0) {
+		dev_err_probe(ov32c4->dev, ret, "failed to register subdev\n");
+		goto probe_error_v4l2_subdev_cleanup;
+	}
+
+	pm_runtime_idle(ov32c4->dev);
+
+	return 0;
+
+probe_error_v4l2_subdev_cleanup:
+	pm_runtime_disable(ov32c4->dev);
+	pm_runtime_set_suspended(ov32c4->dev);
+	v4l2_subdev_cleanup(&ov32c4->sd);
+
+probe_error_media_entity_cleanup:
+	media_entity_cleanup(&ov32c4->sd.entity);
+
+probe_error_v4l2_ctrl_handler_free:
+	v4l2_ctrl_handler_free(&ov32c4->ctrl_handler);
+
+probe_error_power_off:
+	ov32c4_power_off(ov32c4->dev);
+
+	return ret;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(ov32c4_pm_ops, ov32c4_power_off,
+				 ov32c4_power_on, NULL);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ov32c4_acpi_ids[] = {
+	{ "OVTI32C4" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, ov32c4_acpi_ids);
+#endif
+
+static const struct of_device_id ov32c4_of_match[] = {
+	{ .compatible = "ovti,ov32c4" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ov32c4_of_match);
+
+static struct i2c_driver ov32c4_i2c_driver = {
+	.driver = {
+		.name = "ov32c4",
+		.pm = pm_ptr(&ov32c4_pm_ops),
+		.acpi_match_table = ACPI_PTR(ov32c4_acpi_ids),
+		.of_match_table = ov32c4_of_match,
+	},
+	.probe = ov32c4_probe,
+	.remove = ov32c4_remove,
+};
+module_i2c_driver(ov32c4_i2c_driver);
+
+MODULE_DESCRIPTION("OmniVision OV32C4 sensor driver");
+MODULE_LICENSE("GPL");
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v4 3/3] media: ipu-bridge: Add OmniVision OV32C4
  2026-10-05  7:10 [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver Robert Bozik
  2026-10-05  7:10 ` [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4 Robert Bozik
  2026-10-05  7:10 ` [PATCH v4 2/3] media: i2c: Add driver for " Robert Bozik
@ 2026-10-05  7:10 ` Robert Bozik
  2026-10-05  8:04 ` [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver Sakari Ailus
  3 siblings, 0 replies; 13+ messages in thread
From: Robert Bozik @ 2026-10-05  7:10 UTC (permalink / raw)
  To: linux-media
  Cc: Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel,
	Robert Bozik

Add the sensor configuration for the OV32C4, matching the _HID the
sensor enumerates with. Without this entry the bridge does not build a
software node graph for the sensor, so its driver defers probing on the
missing fwnode endpoint forever and the camera never binds.

The SSDB of this sensor declares a VCM, and ipu-bridge would instantiate
a dw9714 client on the sensor's second I2C address. There is no lens
driver there: the address belongs to a register block of the sensor
itself, which the sensor driver claims and needs. A dw9714 client on it
takes the address away from the sensor driver, and dw9714 has no id
register, so it binds to anything. Do not instantiate a VCM for this
sensor, whatever the SSDB says.

Signed-off-by: Robert Bozik <robertbozik@gmail.com>
---
Changes in v4:
- Do not instantiate the VCM the SSDB declares for this sensor; the
  address it names is the sensor's own second address, which the sensor
  driver now claims.

 drivers/media/pci/intel/ipu-bridge.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
index 1bb3a3e98..a0ba323d4 100644
--- a/drivers/media/pci/intel/ipu-bridge.c
+++ b/drivers/media/pci/intel/ipu-bridge.c
@@ -93,6 +93,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
 	IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
 	/* Omnivision OV2680 */
 	IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000),
+	/* Omnivision OV32C4 */
+	IPU_SENSOR_CONFIG("OVTI32C4", 1, 400000000),
 	/* Omnivision OV5675 */
 	IPU_SENSOR_CONFIG("OVTI5675", 1, 450000000),
 	/* Omnivision OV8856 */
@@ -217,6 +219,28 @@ static const char * const ipu_vcm_types[] = {
 	"lc898212axb",
 };
 
+/*
+ * Sensors whose second I2C resource is not a lens driver, whatever the SSDB
+ * calls it. The OV32C4 keeps a register block of its own at that address,
+ * part of the sensor and owned by its driver; a VCM client there would take
+ * the address away and leave the notifier waiting for a lens subdev that
+ * never appears.
+ */
+static const char * const ipu_no_vcm_hids[] = {
+	"OVTI32C4",
+};
+
+static bool ipu_bridge_sensor_has_no_vcm(struct acpi_device *adev)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(ipu_no_vcm_hids); i++)
+		if (acpi_dev_hid_match(adev, ipu_no_vcm_hids[i]))
+			return true;
+
+	return false;
+}
+
 /*
  * Used to figure out IVSC acpi device by ipu_bridge_get_ivsc_acpi_dev()
  * instead of device and driver match to probe IVSC device.
@@ -435,7 +459,7 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
 	sensor->rotation = ipu_bridge_parse_rotation(adev, &ssdb);
 	sensor->orientation = ipu_bridge_parse_orientation(adev);
 
-	if (ssdb.vcmtype)
+	if (ssdb.vcmtype && !ipu_bridge_sensor_has_no_vcm(adev))
 		sensor->vcm_type = ipu_vcm_types[ssdb.vcmtype - 1];
 
 	return 0;
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver
  2026-10-05  7:10 [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver Robert Bozik
                   ` (2 preceding siblings ...)
  2026-10-05  7:10 ` [PATCH v4 3/3] media: ipu-bridge: Add " Robert Bozik
@ 2026-10-05  8:04 ` Sakari Ailus
  3 siblings, 0 replies; 13+ messages in thread
From: Sakari Ailus @ 2026-10-05  8:04 UTC (permalink / raw)
  To: Robert Bozik
  Cc: linux-media, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel,
	Antti Laakso

Hi Robert,

On Mon, Oct 05, 2026 at 09:10:07AM +0200, Robert Bozik wrote:
> Hi,
> 
> v4 of the OV32C4 sensor driver. v3 is at
> https://lore.kernel.org/linux-media/20260829115832.8749-1-robertbozik@gmail.com/
> 
> The one open question from v1 and v2 was the second I2C address - the
> write to 0x3e that the sensor needs before its main address answers -
> and whether it belongs in a sensor driver. v3 could only say what it was
> not. This version answers it with a measurement, and the design follows
> from the answer.
> 
> The question that decides it is whether the block behind 0x3e lives and
> dies with the sensor. Measured on the machine, polling 0x3e and 0x36
> every 0.5 ms through a runtime power cycle and lining the polls up with
> the kernel's regulator, gpio and i2c tracepoints:

I've been looking into this and it seems the answer to the question is
"yes", we can assume it's always there. The sensor has some kind of
always-on functionality that is controlled through a different I²C address
and accessing it is apparently required for the sensor's power-on sequence.

Cc Antti as well.

> 
>   - sensor off (AVDD disabled, reset asserted): 0x3e NACKs, as does 0x36
>   - AVDD on at t=1.0 ms, settled 3.5 ms; reset released 8.9 ms
>   - 0x3e first ACK at 10.1 ms, reading 0x1001 = 0x00; between AVDD and
>     the reset release it did not answer
>   - the driver's 0x1001 = 0x04 at 30.1 ms; 0x36 first ACK at 30.6 ms
>   - reset asserted and AVDD off at 4000.8 ms: 0x3e gone by 4001.9 ms,
>     0x36 by 4003.0 ms
> 
> So it is unreachable without power, appears only once the sensor's own
> reset is released, forgets the value written to it over a power cycle,
> and disappears with the sensor. It has no ACPI device of its own, 0x300a
> there reads zero (it is not an alias of the main map), and 0x36 has
> nothing at 0x1000. The same register pair exists in OV08X40 at that
> sensor's main address, named AO_STANDBY (0x1000) and MS_SELECT (0x1001,
> 0x04 for streaming) in ov08x40.c. The vendor Windows driver writes it
> from the sensor driver as well, once, after reset and before the chip id
> read, and never reads it back. I take all of that to mean the block is
> part of the sensor and the sensor driver is its owner.
> 
> What changed accordingly:
> 
>  - The driver claims the second address with devm_i2c_new_dummy_device()
>    and writes it through a CCI regmap of its own; the bare i2c_transfer()
>    is gone.
>  - ipu-bridge no longer instantiates a VCM for this sensor. The SSDB
>    says vcmtype 2 and the bridge would put a dw9714 on 0x3e; dw9714 has
>    no id register and binds to anything, and that client would hold the
>    address the sensor driver needs. Patch 3 carries the exception, so
>    patches 2 and 3 go together.
> 
> Two smaller things turned up while re-reading the driver for this:
> 
>  - The 10 ms after the software reset was a busy wait. The reset sat in
>    the mode table with a delay_us, and regmap_multi_reg_write() turns
>    that into udelay() on a regmap without can_sleep, which the CCI one
>    is. The driver now issues the stream-off and the reset itself and
>    sleeps; the table is the vendor's sequence minus those two entries.
>  - power_on() returned 0 when the enable write failed. It now fails and
>    undoes the clock, the supply and the reset.
> 
> The power-up timing, your "0 and 5 ms" on v1: I did not follow it then,
> and I think I do now - nothing after the supply, because the regulator
> core waits for it, and 5 ms after reset. The measurement above agrees:
> the block answers about 1 ms after reset release and the main address
> within 1 ms of the enable write. v4 uses 0, 5 ms and 1 ms, verified over
> a cold boot, 20 runtime power cycles and 15 stream starts without a
> failure.
> 
> Where the numbers come from, stated plainly this time, because v3 said
> both "copied 1:1" and "measured by me" about the same table:
> 
>   From the vendor Windows driver (ov32c4.sys, FileVersion
>   70.26100.2.18255):
>   - the mode register table (1787 writes, at file offset 0x31300), of
>     which the driver drops the first two entries, stream-off and reset,
>     and issues them itself;
>   - the 400 MHz link frequency, carried there as bits per second;
>   - the chip id 0x563243;
>   - the write of 0x04 to 0x1001 at the second address;
>   - the registers the controls use (exposure 0x3500, analogue gain
>     0x3508, digital gain 0x350a, VTS 0x380e) and the rule
>     exposure_max = VTS - 32.
> 
>   Measured on the sensor:
>   - the chip id, the register meanings above and the exposure rule,
>     confirmed against what the chip reports;
>   - the gain ranges: analogue exactly proportional between 0x100 and
>     0x7c0 (1x to 7.75x, 0x100 being the power-up value), digital
>     proportional with 1024 as unity, clipping to black one step above
>     16383 - the obvious donor, ov13b10 on the same registers, puts
>     analogue unity at 0x80, which is wrong here;
>   - the timings: 320000000 / (4080 * 2614) = 30.005 fps against a
>     measured 30.00; the power-up sequence as above;
>   - flips preserve the Bayer order, so the media bus code never changes
>     and the crop compensation ov13b10 does would introduce the shift it
>     undoes there;
>   - the 6560x4928 array and 6528x4896 active area, from the window
>     registers of the table, agreeing with the vendor's product brief;
>   - the second address, as above.
> 
> The rest of the series is as before. It adds a driver for the OmniVision
> OV32C4, a 32 megapixel RGBC CMOS image sensor. It ships as the
> under-display camera in the Lenovo Yoga Slim 9 14ILL10, where it is
> enumerated through ACPI (_HID "OVTI32C4") and feeds an Intel IPU7. The
> driver supports 3264x1840 at 30 fps, 10-bit Bayer, 4 CSI-2 lanes at a
> 400 MHz link frequency, with exposure, analogue gain, digital gain,
> vblank, hblank and flip controls, runtime PM and .get_selection. Tested
> on that machine: the sensor probes, streams at a measured 30.00 fps,
> frames arrive complete, and the full path to a processed image runs
> through libcamera's software ISP. The driver has what libcamera's sensor
> driver requirements ask for: the five mandatory controls, the crop
> selection targets, flips that keep the Bayer order, and the orientation
> and rotation properties.
> 
> v4l2-compliance on the subdev, kernel 7.0.0-38:
> 
>   Total for device /dev/v4l-subdev4: 46, Succeeded: 46, Failed: 0, Warnings: 0
> 
> Static checks: checkpatch.pl --strict, sparse (C=1), W=1 and
> dt_binding_check.
> 
> The series applies to media_stage.git; base-commit is below.
> 
> Thanks,
> Robert
> 
> Robert Bozik (3):
>   dt-bindings: media: i2c: Add OmniVision OV32C4
>   media: i2c: Add driver for OmniVision OV32C4
>   media: ipu-bridge: Add OmniVision OV32C4
> 
>  .../bindings/media/i2c/ovti,ov32c4.yaml       |  105 +
>  MAINTAINERS                                   |    8 +
>  drivers/media/i2c/Kconfig                     |   10 +
>  drivers/media/i2c/Makefile                    |    1 +
>  drivers/media/i2c/ov32c4.c                    | 2716 +++++++++++++++++
>  drivers/media/pci/intel/ipu-bridge.c          |   26 +-
>  6 files changed, 2865 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
>  create mode 100644 drivers/media/i2c/ov32c4.c
> 
> 
> base-commit: 4900cad020c0580dfb1be27776ff10a4ef110cfa

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4
  2026-10-05  7:10 ` [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4 Robert Bozik
@ 2026-10-05  8:11   ` Sakari Ailus
  2026-10-05  8:36     ` Robert Bozik
  2026-10-05 11:02     ` Conor Dooley
  0 siblings, 2 replies; 13+ messages in thread
From: Sakari Ailus @ 2026-10-05  8:11 UTC (permalink / raw)
  To: Robert Bozik
  Cc: linux-media, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel,
	Conor Dooley

Hi Robert,

On Mon, Oct 05, 2026 at 09:10:08AM +0200, Robert Bozik wrote:
> Add a binding for the OmniVision OV32C4, a 32 megapixel RGBC CMOS image
> sensor with on-chip 4-cell fusion, a 4-lane MIPI CSI-2 D-PHY transmitter
> and the standard SCCB command interface.
> 
> The sensor ships in laptops as an under-display camera, where it is
> described by ACPI; the binding follows ovti,ov08x40.yaml, which covers
> the closest relative already in tree.
> 
> Acked-by: Conor Dooley <conor.dooley@microchip.com>
> Signed-off-by: Robert Bozik <robertbozik@gmail.com>
> ---
> Changes in v4:
> - No changes to the binding.
> 
>  .../bindings/media/i2c/ovti,ov32c4.yaml       | 105 ++++++++++++++++++
>  1 file changed, 105 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
> new file mode 100644
> index 000000000..804307cd0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
> @@ -0,0 +1,105 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/i2c/ovti,ov32c4.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: OmniVision OV32C4 Image Sensor
> +
> +maintainers:
> +  - Robert Bozik <robertbozik@gmail.com>
> +
> +description:
> +  The OmniVision OV32C4 is a 32 megapixel RGBC (red, green, blue and clear)
> +  CMOS image sensor in a 4-cell arrangement, with on-chip 4-cell fusion and
> +  binning. It has a 6528x4896 active pixel array, a 4-lane MIPI CSI-2 D-PHY
> +  transmitter and the standard SCCB command interface.
> +
> +allOf:
> +  - $ref: /schemas/media/video-interface-devices.yaml#
> +
> +properties:
> +  compatible:
> +    const: ovti,ov32c4
> +
> +  reg:
> +    maxItems: 1

minItems should be 2 here, for the always-on client.

> +
> +  clocks:
> +    maxItems: 1
> +    description: Input clock (XVCLK).
> +
> +  avdd-supply: true
> +
> +  dovdd-supply: true
> +
> +  dvdd-supply: true
> +
> +  reset-gpios:
> +    maxItems: 1
> +    description: Active low GPIO connected to the XSHUTDOWN pad of the sensor.
> +
> +  port:
> +    $ref: /schemas/graph.yaml#/$defs/port-base
> +    additionalProperties: false
> +
> +    properties:
> +      endpoint:
> +        $ref: /schemas/media/video-interfaces.yaml#
> +        additionalProperties: false
> +
> +        properties:
> +          data-lanes:
> +            items:
> +              - const: 1
> +              - const: 2
> +              - const: 3
> +              - const: 4
> +          link-frequencies: true
> +          remote-endpoint: true
> +
> +        required:
> +          - data-lanes
> +          - link-frequencies
> +          - remote-endpoint
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - port
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +
> +    i2c {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        camera@36 {
> +            compatible = "ovti,ov32c4";
> +            reg = <0x36>;
> +
> +            clocks = <&ov32c4_clk>;
> +            assigned-clocks = <&ov32c4_clk>;
> +            assigned-clock-rates = <19200000>;
> +
> +            avdd-supply = <&vreg_2p8>;
> +            dovdd-supply = <&vreg_1p8>;
> +            dvdd-supply = <&vreg_1p1>;
> +
> +            reset-gpios = <&tlmm 111 GPIO_ACTIVE_LOW>;
> +
> +            port {
> +                ov32c4_ep: endpoint {
> +                    remote-endpoint = <&csiphy0_ep>;
> +                    data-lanes = <1 2 3 4>;
> +                    link-frequencies = /bits/ 64 <400000000>;
> +                };
> +            };
> +        };
> +    };
> +...

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4
  2026-10-05  8:11   ` Sakari Ailus
@ 2026-10-05  8:36     ` Robert Bozik
  2026-10-05 11:02     ` Conor Dooley
  1 sibling, 0 replies; 13+ messages in thread
From: Robert Bozik @ 2026-10-05  8:36 UTC (permalink / raw)
  To: sakari.ailus
  Cc: linux-media, mchehab, robh, krzk+dt, conor+dt, conor.dooley,
	devicetree, linux-kernel

Hi Sakari,

On Mon, Oct 05, 2026 at 11:11:46AM +0300, Sakari Ailus wrote:
> On Mon, Oct 05, 2026 at 09:10:08AM +0200, Robert Bozik wrote:
> > +  reg:
> > +    maxItems: 1
> 
> minItems should be 2 here, for the always-on client.

Yes - will do in v5: two entries, the sensor and the always-on block,
with the example as reg = <0x36>, <0x3e>. The driver will take the
second address from reg on DT and keep the _CRS lookup for ACPI, and
fail probe when there is none, now that the binding requires it. I'll
drop Conor's ack since the binding changes.

I can compile the DT path but have no DT platform to run it on; the
ACPI path is what I can test.

Thanks,
Robert

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 2/3] media: i2c: Add driver for OmniVision OV32C4
  2026-10-05  7:10 ` [PATCH v4 2/3] media: i2c: Add driver for " Robert Bozik
@ 2026-10-05  9:23   ` Sakari Ailus
  2026-10-05 10:14     ` Robert Bozik
  0 siblings, 1 reply; 13+ messages in thread
From: Sakari Ailus @ 2026-10-05  9:23 UTC (permalink / raw)
  To: Robert Bozik
  Cc: linux-media, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel

Hi Robert,

On Mon, Oct 05, 2026 at 09:10:09AM +0200, Robert Bozik wrote:
> The OV32C4 is a 32 megapixel RGBC CMOS image sensor with on-chip 4-cell
> fusion and binning, connected over 4 MIPI CSI-2 D-PHY lanes. It is used
> as an under-display camera in laptops, where it is enumerated through
> ACPI (_HID "OVTI32C4") and paired with an Intel IPU.
> 
> The driver supports 3264x1840 at 30 fps in 10-bit Bayer at a link
> frequency of 400 MHz, with exposure, analogue gain, digital gain,
> vblank, hblank and horizontal and vertical flip controls, runtime PM
> and .get_selection reporting the 6560x4928 pixel array.
> 
> The sensor has a second I2C address, the second I2cSerialBus resource of
> its _CRS, behind which sits a small register block of its own; the main
> address does not answer until 0x1001 there is written. The block is part
> of the sensor - it is unreachable while the sensor is unpowered or in
> reset, starts answering about a millisecond after reset is released,
> loses the written value over a power cycle and has no ACPI device of
> its own - so the driver claims the address as a second I2C client and
> writes it on every power-up.
> 
> There is no public datasheet for this sensor. The mode register table is
> the vendor driver's initialisation sequence, and the registers the
> controls use were established by correlating that binary with the values
> read back from the chip; the cover letter has the measurements that back
> the ranges and the timings.

Please clean this up. Most of this goes to the cover letter.

> 
> Signed-off-by: Robert Bozik <robertbozik@gmail.com>
> ---
> Changes in v4:
> - The second I2C address is claimed with devm_i2c_new_dummy_device() and
>   driven through its own CCI regmap instead of a bare i2c_transfer(),
>   now that it is measured to be part of the sensor (cover letter).
> - power_on() fails when the enable write to that block fails, and undoes
>   the clock, the supply and the reset, instead of returning 0.
> - The stream-off and the software reset are issued by the driver before
>   the mode table rather than from inside it: the delay_us of a
>   reg_sequence is a udelay() on a regmap without can_sleep, which made
>   the 10 ms settle a busy wait. The table is now the vendor's list minus
>   those two entries.
> - Power-up timing from the measurement, in line with the "0 and 5 ms"
>   remark on v1: no wait after the supply (the regulator core waits for
>   it), 5 ms after reset release, 1 ms after the enable write. Verified
>   over a cold boot, 20 runtime power cycles and 15 stream starts.
> - Copyright line.
> 
>  MAINTAINERS                |    8 +
>  drivers/media/i2c/Kconfig  |   10 +
>  drivers/media/i2c/Makefile |    1 +
>  drivers/media/i2c/ov32c4.c | 2716 ++++++++++++++++++++++++++++++++++++
>  4 files changed, 2735 insertions(+)
>  create mode 100644 drivers/media/i2c/ov32c4.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3785b8c1d..7b28717fc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -20008,6 +20008,14 @@ S:	Maintained
>  T:	git git://linuxtv.org/media.git
>  F:	drivers/media/i2c/ov2740.c
>  
> +OMNIVISION OV32C4 SENSOR DRIVER
> +M:	Robert Bozik <robertbozik@gmail.com>
> +L:	linux-media@vger.kernel.org
> +S:	Maintained
> +T:	git git://linuxtv.org/media.git
> +F:	Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
> +F:	drivers/media/i2c/ov32c4.c
> +
>  OMNIVISION OV4689 SENSOR DRIVER
>  M:	Mikhail Rudenko <mike.rudenko@gmail.com>
>  L:	linux-media@vger.kernel.org
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 5c52007f9..1c363d581 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -547,6 +547,16 @@ config VIDEO_OV2740
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called ov2740.
>  
> +config VIDEO_OV32C4
> +	tristate "OmniVision OV32C4 sensor support"
> +	select V4L2_CCI_I2C
> +	help
> +	  This is a Video4Linux2 sensor driver for the OmniVision
> +	  OV32C4 camera.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called ov32c4.
> +
>  config VIDEO_OV4689
>  	tristate "OmniVision OV4689 sensor support"
>  	depends on GPIOLIB
> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> index d04bd5724..79bf2e393 100644
> --- a/drivers/media/i2c/Makefile
> +++ b/drivers/media/i2c/Makefile
> @@ -102,6 +102,7 @@ obj-$(CONFIG_VIDEO_OV2685) += ov2685.o
>  obj-$(CONFIG_VIDEO_OV2732) += ov2732.o
>  obj-$(CONFIG_VIDEO_OV2735) += ov2735.o
>  obj-$(CONFIG_VIDEO_OV2740) += ov2740.o
> +obj-$(CONFIG_VIDEO_OV32C4) += ov32c4.o
>  obj-$(CONFIG_VIDEO_OV4689) += ov4689.o
>  obj-$(CONFIG_VIDEO_OV5640) += ov5640.o
>  obj-$(CONFIG_VIDEO_OV5645) += ov5645.o
> diff --git a/drivers/media/i2c/ov32c4.c b/drivers/media/i2c/ov32c4.c
> new file mode 100644
> index 000000000..151d6b32e
> --- /dev/null
> +++ b/drivers/media/i2c/ov32c4.c
> @@ -0,0 +1,2716 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * OmniVision OV32C4 image sensor driver.
> + *
> + * Copyright (C) 2026 Robert Bozik
> + *
> + * The sensor ships in laptops with an Intel IPU7, where it is enumerated
> + * through ACPI _HID "OVTI32C4". There is no public datasheet; the 400 MHz
> + * link frequency comes from the vendor driver, which carries it as bits per
> + * second, and is confirmed on hardware: the receiver locks and the sensor
> + * streams 3264x1840 at a measured 30.00 fps, which is pixel_rate divided by
> + * ppl times vts.

I think you could just drop this paragraph.

> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/minmax.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <media/v4l2-cci.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-fwnode.h>
> +
> +#define OV32C4_LINK_FREQ_400MHZ		400000000ULL	/* 800 Mbps/lane */
> +#define OV32C4_MCLK			19200000
> +#define OV32C4_RGB_DEPTH		10
> +#define OV32C4_DATA_LANES		4
> +
> +/* Horizontal timing */
> +#define OV32C4_REG_HTS			CCI_REG16(0x380c)
> +
> +/*
> + * Pixel array geometry, derived from the mode registers: 0x3800..0x3807 read
> + * a 6560x3712 window out of a 6560x4928 array, 2x2 binned to 3280x1856, of
> + * which 0x3810..0x3813 take 3264x1840 at offset (8, 9). The 32 columns and
> + * rows by which the array exceeds the 6528x4896 active area are blind.
> + */
> +#define OV32C4_NATIVE_WIDTH		6560U
> +#define OV32C4_NATIVE_HEIGHT		4928U
> +#define OV32C4_ACTIVE_LEFT		16U
> +#define OV32C4_ACTIVE_TOP		16U
> +#define OV32C4_ACTIVE_WIDTH		6528U
> +#define OV32C4_ACTIVE_HEIGHT		4896U
> +#define OV32C4_CROP_LEFT		16U
> +#define OV32C4_CROP_TOP			626U
> +#define OV32C4_CROP_WIDTH		6528U
> +#define OV32C4_CROP_HEIGHT		3680U
> +
> +#define OV32C4_REG_CHIP_ID		CCI_REG24(0x300a)
> +#define OV32C4_CHIP_ID			0x563243
> +
> +#define OV32C4_REG_STREAM_CONTROL	CCI_REG8(0x0100)
> +#define OV32C4_REG_SW_RESET		CCI_REG8(0x0103)
> +/* The vendor driver issues the reset itself and waits this long after it. */
> +#define OV32C4_SW_RESET_SETTLE_US	10000
> +
> +/*
> + * The sensor has a second I2C address, listed as the second I2cSerialBus
> + * resource of its ACPI _CRS, behind which sits a small register block of
> + * its own. Until 0x1001 there is written, the main address does not answer
> + * at all. The block is part of the sensor: it is unreachable while the
> + * sensor is unpowered or held in reset, starts answering about a millisecond
> + * after reset is released, loses the value written to 0x1001 over a power
> + * cycle, and has no ACPI device of its own. The same register pair exists in
> + * OV08X40 (AO_STANDBY at 0x1000, MS_SELECT at 0x1001, 0x04 for streaming)
> + * at that sensor's main address.
> + */
> +#define OV32C4_COMPANION_ENABLE_REG	CCI_REG8(0x1001)
> +#define OV32C4_COMPANION_ENABLE_VAL	0x04

How about:

#define OV32C4_AON_SMIA_R1001		CCI_REG8(0x1001)
#define OV32C4_AON_SMIA_R1001_MAIN_MODE	BIT(2)

for these?

> +
> +/* Vertical timing */
> +#define OV32C4_REG_VTS			CCI_REG16(0x380e)
> +#define OV32C4_VTS_MAX			0xffff
> +
> +/* Exposure; the sensor has two exposure contexts and ov32c4.sys writes both */
> +#define OV32C4_REG_EXPOSURE		CCI_REG24(0x3500)

This is for RGB.

> +#define OV32C4_REG_EXPOSURE_CTX2	CCI_REG24(0x3540)

And this is for IR.

I think we can keep them behind the same control for now.

> +#define OV32C4_EXPOSURE_MIN		4
> +#define OV32C4_EXPOSURE_STEP		1
> +/* VTS = max(vts, exposure + 32) in ov32c4.sys -> keep 32 lines of margin */
> +#define OV32C4_EXPOSURE_MAX_MARGIN	32
> +
> +/*
> + * Mirror and flip: bit 2 in each register, but with opposite polarity. The
> + * mode table leaves 0x3821 set and 0x3820 clear, and that is the un-flipped
> + * state. Neither changes the Bayer order.
> + */
> +#define OV32C4_REG_FLIP			CCI_REG8(0x3820)
> +#define OV32C4_REG_MIRROR		CCI_REG8(0x3821)
> +#define OV32C4_FLIP_BIT			BIT(2)
> +
> +/* Analogue gain: 0x100 is unity and 0x7c0, 7.75x, is the maximum. */
> +#define OV32C4_REG_ANALOG_GAIN		CCI_REG16(0x3508)
> +#define OV32C4_REG_ANALOG_GAIN_CTX2	CCI_REG16(0x3548)

Same for these (RGB and IR).

> +#define OV32C4_ANA_GAIN_MIN		0x100
> +#define OV32C4_ANA_GAIN_MAX		0x07c0
> +#define OV32C4_ANA_GAIN_STEP		1
> +#define OV32C4_ANA_GAIN_DEFAULT		0x100
> +
> +/*
> + * Digital gain. The register holds the gain shifted left by 6; the control
> + * carries the value itself, of which 1024 is unity.
> + */
> +#define OV32C4_REG_DIGITAL_GAIN		CCI_REG24(0x350a)
> +#define OV32C4_REG_DIGITAL_GAIN_CTX2	CCI_REG24(0x354a)
> +#define OV32C4_DGAIN_SHIFT		6
> +#define OV32C4_DGAIN_MIN		1024
> +#define OV32C4_DGAIN_MAX		16383
> +#define OV32C4_DGAIN_STEP		1
> +#define OV32C4_DGAIN_DEFAULT		1024
> +
> +struct ov32c4_mode {
> +	u32 width;
> +	u32 height;
> +	/*
> +	 * Line length in pixels, in the units of the PIXEL_RATE control.
> +	 * OV32C4_REG_HTS holds the same line in the sensor's own clock
> +	 * units, which for this mode is 1224 against these 4080 pixels.
> +	 */

?

> +	u32 ppl;
> +	/* Frame length in lines, as written to OV32C4_REG_VTS */
> +	u32 vts_min;
> +
> +	const struct reg_sequence *reg_sequence;
> +	int sequence_length;
> +};
> +
> +static const char * const ov32c4_supply_names[] = {
> +	"avdd",		/* Analog power */
> +};
> +
> +/*
> + * Power-up timing; there is no public datasheet for this sensor. The
> + * regulator core already waits for the supply to settle. Measured on the
> + * hardware, the block behind the second address answers about 1 ms after
> + * reset is released, and the main address answers within 1 ms of the
> + * enable write; 5 ms and 1 ms leave a margin over that.
> + */
> +#define OV32C4_RESET_SETTLE_US		5000
> +#define OV32C4_ENABLE_SETTLE_US		1000
> +
> +/*
> + * Mode 3264x1840 @ 30 fps, 4 lanes, SGRBG10. The 15 fps variant of the same
> + * table differs only in VTS, which V4L2_CID_VBLANK covers.

I think you can omit the second sentence here.

> + *
> + * This is the vendor driver's list for the mode, minus its first two
> + * entries: the stream-off and the software reset, which the driver issues
> + * itself in ov32c4_enable_streams() so that the settle time after the reset
> + * can be a sleep rather than a delay inside a register sequence.
> + */
> +static const struct reg_sequence ov32c4_mode_3264x1840_regs[] = {
> +	{ 0x0301, 0xc8 },
> +	{ 0x0303, 0x04 },
> +	{ 0x0304, 0x02 },
> +	{ 0x0305, 0x71 },
> +	{ 0x0306, 0x04 },
> +	{ 0x0307, 0x01 },
> +	{ 0x0308, 0x03 },
> +	{ 0x0316, 0x3c },
> +	{ 0x0325, 0xd0 },
> +	{ 0x0343, 0x04 },
> +	{ 0x0344, 0x02 },
> +	{ 0x0345, 0x32 },
> +	{ 0x034b, 0x03 },
> +	{ 0x034f, 0xe4 },
> +	{ 0x3012, 0x41 },
> +	{ 0x3025, 0x89 },
> +	{ 0x3107, 0x86 },
> +	{ 0x3400, 0x00 },
> +	{ 0x3402, 0x8c },
> +	{ 0x3404, 0x1a },
> +	{ 0x3405, 0xb6 },
> +	{ 0x3406, 0x88 },
> +	{ 0x3407, 0x01 },
> +	{ 0x3408, 0xb6 },
> +	{ 0x3409, 0x88 },
> +	{ 0x340a, 0x01 },
> +	{ 0x340c, 0x50 },
> +	{ 0x340d, 0x52 },
> +	{ 0x3419, 0x15 },
> +	{ 0x341a, 0xfc },
> +	{ 0x341b, 0x30 },
> +	{ 0x3420, 0x00 },
> +	{ 0x3421, 0x00 },
> +	{ 0x3422, 0x00 },
> +	{ 0x3423, 0x00 },
> +	{ 0x3424, 0x00 },
> +	{ 0x3425, 0x00 },
> +	{ 0x3426, 0x00 },
> +	{ 0x3427, 0x00 },
> +	{ 0x3428, 0xff },
> +	{ 0x342a, 0x00 },
> +	{ 0x342b, 0x00 },
> +	{ 0x342c, 0x00 },
> +	{ 0x342d, 0x0f },
> +	{ 0x342e, 0x00 },
> +	{ 0x342f, 0x00 },
> +	{ 0x3430, 0x00 },
> +	{ 0x3431, 0x00 },
> +	{ 0x3432, 0x00 },
> +	{ 0x3436, 0x10 },
> +	{ 0x3437, 0x00 },
> +	{ 0x3438, 0x00 },
> +	{ 0x3439, 0x00 },
> +	{ 0x3452, 0x14 },
> +	{ 0x3453, 0x88 },
> +	{ 0x3458, 0x02 },
> +	{ 0x3459, 0x02 },
> +	{ 0x3504, 0x4c },
> +	{ 0x3506, 0x30 },
> +	{ 0x3507, 0x00 },
> +	{ 0x3544, 0x4c },
> +	{ 0x3546, 0x30 },
> +	{ 0x3547, 0x00 },
> +	{ 0x3602, 0x24 },
> +	{ 0x3605, 0xd0 },
> +	{ 0x3608, 0x21 },
> +	{ 0x3609, 0x90 },
> +	{ 0x360c, 0x08 },
> +	{ 0x3616, 0x31 },
> +	{ 0x361a, 0x0a },
> +	{ 0x3682, 0x80 },
> +	{ 0x368e, 0x71 },
> +	{ 0x3696, 0xd1 },
> +	{ 0x36af, 0x00 },
> +	{ 0x3714, 0x22 },
> +	{ 0x3718, 0x02 },
> +	{ 0x37b0, 0x00 },
> +	{ 0x37b1, 0x8a },
> +	{ 0x37b2, 0x01 },
> +	{ 0x37b3, 0x5f },
> +	{ 0x37b4, 0x00 },
> +	{ 0x37b5, 0xd3 },
> +	{ 0x37b6, 0x01 },
> +	{ 0x37b7, 0xbe },
> +	{ 0x3800, 0x00 },
> +	{ 0x3801, 0x00 },
> +	{ 0x3802, 0x02 },
> +	{ 0x3803, 0x60 },
> +	{ 0x3804, 0x19 },
> +	{ 0x3805, 0x9f },
> +	{ 0x3806, 0x10 },
> +	{ 0x3807, 0xdf },
> +	{ 0x3808, 0x0c },
> +	{ 0x3809, 0xc0 },
> +	{ 0x380a, 0x07 },
> +	{ 0x380b, 0x30 },
> +	{ 0x380c, 0x04 },
> +	{ 0x380d, 0xc8 },
> +	{ 0x380e, 0x0a },
> +	{ 0x380f, 0x36 },
> +	{ 0x3810, 0x00 },
> +	{ 0x3811, 0x08 },
> +	{ 0x3812, 0x00 },
> +	{ 0x3813, 0x09 },
> +	{ 0x3814, 0x11 },
> +	{ 0x3815, 0x11 },
> +	{ 0x3820, 0x02 },
> +	{ 0x3821, 0x06 },
> +	{ 0x3828, 0x0d },
> +	{ 0x382a, 0x80 },
> +	{ 0x3837, 0x08 },
> +	{ 0x383a, 0x81 },
> +	{ 0x383b, 0x81 },
> +	{ 0x383c, 0x11 },
> +	{ 0x383d, 0x11 },
> +	{ 0x3840, 0x00 },
> +	{ 0x3902, 0x12 },
> +	{ 0x3903, 0x12 },
> +	{ 0x3904, 0x12 },
> +	{ 0x3905, 0x12 },
> +	{ 0x3906, 0x12 },
> +	{ 0x3907, 0x12 },
> +	{ 0x3908, 0x12 },
> +	{ 0x3909, 0x12 },
> +	{ 0x390a, 0x03 },
> +	{ 0x390b, 0x0d },
> +	{ 0x390c, 0x12 },
> +	{ 0x390d, 0x14 },
> +	{ 0x390e, 0x03 },
> +	{ 0x390f, 0x0d },
> +	{ 0x3910, 0x12 },
> +	{ 0x3911, 0x14 },
> +	{ 0x3913, 0x00 },
> +	{ 0x3914, 0x00 },
> +	{ 0x3915, 0x00 },
> +	{ 0x3916, 0x00 },
> +	{ 0x391a, 0x78 },
> +	{ 0x391c, 0x78 },
> +	{ 0x391e, 0x78 },
> +	{ 0x3920, 0x78 },
> +	{ 0x3922, 0x78 },
> +	{ 0x3924, 0x78 },
> +	{ 0x3926, 0x78 },
> +	{ 0x3928, 0x78 },
> +	{ 0x392a, 0x04 },
> +	{ 0x3930, 0x55 },
> +	{ 0x3937, 0x09 },
> +	{ 0x3938, 0x13 },
> +	{ 0x3939, 0x25 },
> +	{ 0x393a, 0x4b },
> +	{ 0x393b, 0x05 },
> +	{ 0x393f, 0xa6 },
> +	{ 0x3940, 0x03 },
> +	{ 0x3941, 0x01 },
> +	{ 0x3942, 0x03 },
> +	{ 0x3943, 0x01 },
> +	{ 0x3944, 0x03 },
> +	{ 0x3945, 0x02 },
> +	{ 0x3946, 0x07 },
> +	{ 0x3947, 0x06 },
> +	{ 0x394e, 0xaa },
> +	{ 0x394f, 0xaa },
> +	{ 0x3950, 0x03 },
> +	{ 0x395a, 0x60 },
> +	{ 0x3a05, 0x03 },
> +	{ 0x3a10, 0x84 },
> +	{ 0x3a11, 0x20 },
> +	{ 0x3a14, 0x13 },
> +	{ 0x3a1a, 0x78 },
> +	{ 0x3a1d, 0x48 },
> +	{ 0x3ae1, 0x7b },
> +	{ 0x3b21, 0x71 },
> +	{ 0x3b25, 0x71 },
> +	{ 0x3b29, 0x71 },
> +	{ 0x3b2d, 0x71 },
> +	{ 0x3b31, 0x71 },
> +	{ 0x3b35, 0x71 },
> +	{ 0x3b39, 0x71 },
> +	{ 0x3b3d, 0x71 },
> +	{ 0x3b64, 0x20 },
> +	{ 0x3b68, 0x7f },
> +	{ 0x3b69, 0xe3 },
> +	{ 0x3b6c, 0x7f },
> +	{ 0x3b6d, 0xe3 },
> +	{ 0x3b71, 0x83 },
> +	{ 0x3b73, 0xbf },
> +	{ 0x3ba9, 0x9d },
> +	{ 0x3bab, 0xe2 },
> +	{ 0x3baf, 0x9d },
> +	{ 0x3bb1, 0xe2 },
> +	{ 0x3bb5, 0x9d },
> +	{ 0x3bb7, 0xe2 },
> +	{ 0x3bbb, 0x9d },
> +	{ 0x3bbd, 0xe2 },
> +	{ 0x3f00, 0x11 },
> +	{ 0x4010, 0xe8 },
> +	{ 0x4011, 0x01 },
> +	{ 0x4012, 0x0c },
> +	{ 0x4015, 0x00 },
> +	{ 0x4016, 0x0f },
> +	{ 0x4017, 0x00 },
> +	{ 0x4018, 0x07 },
> +	{ 0x401a, 0x40 },
> +	{ 0x402e, 0x00 },
> +	{ 0x4040, 0x00 },
> +	{ 0x4041, 0x00 },
> +	{ 0x4042, 0x00 },
> +	{ 0x4043, 0x00 },
> +	{ 0x4044, 0x00 },
> +	{ 0x4045, 0x00 },
> +	{ 0x4046, 0x00 },
> +	{ 0x4047, 0x00 },
> +	{ 0x4048, 0x00 },
> +	{ 0x4049, 0x00 },
> +	{ 0x404a, 0x00 },
> +	{ 0x404b, 0x00 },
> +	{ 0x404c, 0x00 },
> +	{ 0x404d, 0x00 },
> +	{ 0x404e, 0x00 },
> +	{ 0x404f, 0x00 },
> +	{ 0x40dc, 0x02 },
> +	{ 0x4501, 0x11 },
> +	{ 0x4504, 0x80 },
> +	{ 0x4603, 0x15 },
> +	{ 0x4609, 0x20 },
> +	{ 0x460e, 0x00 },
> +	{ 0x4680, 0x01 },
> +	{ 0x4686, 0x00 },
> +	{ 0x4687, 0x00 },
> +	{ 0x4691, 0x00 },
> +	{ 0x4800, 0x64 },
> +	{ 0x4802, 0x00 },
> +	{ 0x4806, 0x40 },
> +	{ 0x481b, 0x3c },
> +	{ 0x481f, 0x30 },
> +	{ 0x4829, 0x70 },
> +	{ 0x4837, 0x10 },
> +	{ 0x4850, 0x42 },
> +	{ 0x4853, 0x04 },
> +	{ 0x4860, 0x00 },
> +	{ 0x4861, 0xec },
> +	{ 0x4862, 0x04 },
> +	{ 0x4883, 0x00 },
> +	{ 0x4888, 0x10 },
> +	{ 0x4889, 0x03 },
> +	{ 0x488a, 0x04 },
> +	{ 0x48f8, 0x05 },
> +	{ 0x48f9, 0xdc },
> +	{ 0x4910, 0xe8 },
> +	{ 0x4911, 0x01 },
> +	{ 0x4912, 0x0c },
> +	{ 0x4915, 0x00 },
> +	{ 0x4916, 0x0f },
> +	{ 0x4917, 0x00 },
> +	{ 0x4918, 0x07 },
> +	{ 0x491a, 0x40 },
> +	{ 0x4940, 0x00 },
> +	{ 0x4941, 0x00 },
> +	{ 0x4942, 0x00 },
> +	{ 0x4943, 0x00 },
> +	{ 0x4944, 0x00 },
> +	{ 0x4945, 0x00 },
> +	{ 0x4946, 0x00 },
> +	{ 0x4947, 0x00 },
> +	{ 0x4948, 0x00 },
> +	{ 0x4949, 0x00 },
> +	{ 0x494a, 0x00 },
> +	{ 0x494b, 0x00 },
> +	{ 0x494c, 0x00 },
> +	{ 0x494d, 0x00 },
> +	{ 0x494e, 0x00 },
> +	{ 0x494f, 0x00 },
> +	{ 0x49dc, 0x02 },
> +	{ 0x4d00, 0x04 },
> +	{ 0x4d01, 0xea },
> +	{ 0x4d02, 0xb9 },
> +	{ 0x4d03, 0x40 },
> +	{ 0x4d04, 0x72 },
> +	{ 0x4d05, 0xf7 },
> +	{ 0x5000, 0x1f },
> +	{ 0x5001, 0x10 },
> +	{ 0x5004, 0x17 },
> +	{ 0x5007, 0x06 },
> +	{ 0x5008, 0x04 },
> +	{ 0x50c1, 0x00 },
> +	{ 0x5110, 0x00 },
> +	{ 0x5111, 0x14 },
> +	{ 0x5112, 0x03 },
> +	{ 0x5113, 0x93 },
> +	{ 0x5152, 0xa3 },
> +	{ 0x5180, 0xc1 },
> +	{ 0x518a, 0x04 },
> +	{ 0x51b0, 0x30 },
> +	{ 0x52c1, 0x00 },
> +	{ 0x52c2, 0x00 },
> +	{ 0x5310, 0x00 },
> +	{ 0x5311, 0x14 },
> +	{ 0x5312, 0x03 },
> +	{ 0x5313, 0x93 },
> +	{ 0x5352, 0x63 },
> +	{ 0x5380, 0xc1 },
> +	{ 0x538a, 0x04 },
> +	{ 0x53b0, 0x00 },
> +	{ 0x5400, 0x3f },
> +	{ 0x5401, 0x10 },
> +	{ 0x5408, 0x0c },
> +	{ 0x5409, 0xc0 },
> +	{ 0x540a, 0x09 },
> +	{ 0x540b, 0x90 },
> +	{ 0x6ad0, 0x00 },
> +	{ 0x6ad1, 0x75 },

Are there any gaps in this deluge of 0x0 and 0x75? If not, could you write
it programmatically rather than using a huge array?

> +	{ 0x6ad2, 0x00 },
> +	{ 0x6ad3, 0x75 },
> +	{ 0x6ad4, 0x00 },
> +	{ 0x6ad5, 0x75 },
> +	{ 0x6ad6, 0x00 },
> +	{ 0x6ad7, 0x75 },
> +	{ 0x6ad8, 0x00 },
> +	{ 0x6ad9, 0x75 },
> +	{ 0x6ada, 0x00 },
> +	{ 0x6adb, 0x75 },
> +	{ 0x6adc, 0x00 },
> +	{ 0x6add, 0x75 },
> +	{ 0x6ade, 0x00 },
> +	{ 0x6adf, 0x75 },
> +	{ 0x6ae0, 0x00 },
> +	{ 0x6ae1, 0x75 },
> +	{ 0x6ae2, 0x00 },
> +	{ 0x6ae3, 0x75 },
> +	{ 0x6ae4, 0x00 },
> +	{ 0x6ae5, 0x75 },
> +	{ 0x6ae6, 0x00 },
> +	{ 0x6ae7, 0x75 },
> +	{ 0x6ae8, 0x00 },
> +	{ 0x6ae9, 0x75 },
> +	{ 0x6aea, 0x00 },
> +	{ 0x6aeb, 0x75 },
> +	{ 0x6aec, 0x00 },
> +	{ 0x6aed, 0x75 },
> +	{ 0x6aee, 0x00 },
> +	{ 0x6aef, 0x75 },
> +	{ 0x6af0, 0x00 },
> +	{ 0x6af1, 0x75 },
> +	{ 0x6af2, 0x00 },
> +	{ 0x6af3, 0x75 },
> +	{ 0x6af4, 0x00 },
> +	{ 0x6af5, 0x75 },
> +	{ 0x6af6, 0x00 },
> +	{ 0x6af7, 0x75 },
> +	{ 0x6af8, 0x00 },
> +	{ 0x6af9, 0x75 },
> +	{ 0x6afa, 0x00 },
> +	{ 0x6afb, 0x75 },
> +	{ 0x6afc, 0x00 },
> +	{ 0x6afd, 0x75 },
> +	{ 0x6afe, 0x00 },
> +	{ 0x6aff, 0x75 },
> +	{ 0x6b00, 0x00 },
> +	{ 0x6b01, 0x75 },
> +	{ 0x6b02, 0x00 },
> +	{ 0x6b03, 0x75 },
> +	{ 0x6b04, 0x00 },
> +	{ 0x6b05, 0x75 },
> +	{ 0x6b06, 0x00 },
> +	{ 0x6b07, 0x75 },
> +	{ 0x6b08, 0x00 },
> +	{ 0x6b09, 0x75 },
> +	{ 0x6b0a, 0x00 },
> +	{ 0x6b0b, 0x75 },
> +	{ 0x6b0c, 0x00 },
> +	{ 0x6b0d, 0x75 },
> +	{ 0x6b0e, 0x00 },
> +	{ 0x6b0f, 0x75 },
> +	{ 0x6b10, 0x00 },
> +	{ 0x6b11, 0x75 },
> +	{ 0x6b12, 0x00 },
> +	{ 0x6b13, 0x75 },
> +	{ 0x6b14, 0x00 },
> +	{ 0x6b15, 0x75 },
> +	{ 0x6b16, 0x00 },
> +	{ 0x6b17, 0x75 },
> +	{ 0x6b18, 0x00 },
> +	{ 0x6b19, 0x75 },
> +	{ 0x6b1a, 0x00 },
> +	{ 0x6b1b, 0x75 },
> +	{ 0x6b1c, 0x00 },
> +	{ 0x6b1d, 0x75 },
> +	{ 0x6b1e, 0x00 },
> +	{ 0x6b1f, 0x75 },
> +	{ 0x6b20, 0x00 },
> +	{ 0x6b21, 0x75 },
> +	{ 0x6b22, 0x00 },
> +	{ 0x6b23, 0x75 },
> +	{ 0x6b24, 0x00 },
> +	{ 0x6b25, 0x75 },
> +	{ 0x6b26, 0x00 },
> +	{ 0x6b27, 0x75 },
> +	{ 0x6b28, 0x00 },
> +	{ 0x6b29, 0x75 },
> +	{ 0x6b2a, 0x00 },
> +	{ 0x6b2b, 0x75 },
> +	{ 0x6b2c, 0x00 },
> +	{ 0x6b2d, 0x75 },
> +	{ 0x6b2e, 0x00 },
> +	{ 0x6b2f, 0x75 },
> +	{ 0x6b30, 0x00 },
> +	{ 0x6b31, 0x75 },
> +	{ 0x6b32, 0x00 },
> +	{ 0x6b33, 0x75 },
> +	{ 0x6b34, 0x00 },
> +	{ 0x6b35, 0x75 },
> +	{ 0x6b36, 0x00 },
> +	{ 0x6b37, 0x75 },
> +	{ 0x6b38, 0x00 },
> +	{ 0x6b39, 0x75 },
> +	{ 0x6b3a, 0x00 },
> +	{ 0x6b3b, 0x75 },
> +	{ 0x6b3c, 0x00 },
> +	{ 0x6b3d, 0x75 },
> +	{ 0x6b3e, 0x00 },
> +	{ 0x6b3f, 0x75 },
> +	{ 0x6b40, 0x00 },
> +	{ 0x6b41, 0x75 },
> +	{ 0x6b42, 0x00 },
> +	{ 0x6b43, 0x75 },
> +	{ 0x6b44, 0x00 },
> +	{ 0x6b45, 0x75 },
> +	{ 0x6b46, 0x00 },
> +	{ 0x6b47, 0x75 },
> +	{ 0x6b48, 0x00 },
> +	{ 0x6b49, 0x75 },
> +	{ 0x6b4a, 0x00 },
> +	{ 0x6b4b, 0x75 },
> +	{ 0x6b4c, 0x00 },
> +	{ 0x6b4d, 0x75 },
> +	{ 0x6b4e, 0x00 },
> +	{ 0x6b4f, 0x75 },
> +	{ 0x6b50, 0x00 },
> +	{ 0x6b51, 0x75 },
> +	{ 0x6b52, 0x00 },
> +	{ 0x6b53, 0x75 },
> +	{ 0x6b54, 0x00 },
> +	{ 0x6b55, 0x75 },
> +	{ 0x6b56, 0x00 },
> +	{ 0x6b57, 0x75 },
> +	{ 0x6b58, 0x00 },
> +	{ 0x6b59, 0x75 },
> +	{ 0x6b5a, 0x00 },
> +	{ 0x6b5b, 0x75 },
> +	{ 0x6b5c, 0x00 },
> +	{ 0x6b5d, 0x75 },
> +	{ 0x6b5e, 0x00 },
> +	{ 0x6b5f, 0x75 },
> +	{ 0x6b60, 0x00 },
> +	{ 0x6b61, 0x75 },
> +	{ 0x6b62, 0x00 },
> +	{ 0x6b63, 0x75 },
> +	{ 0x6b64, 0x00 },
> +	{ 0x6b65, 0x75 },
> +	{ 0x6b66, 0x00 },
> +	{ 0x6b67, 0x75 },
> +	{ 0x6b68, 0x00 },
> +	{ 0x6b69, 0x75 },
> +	{ 0x6b6a, 0x00 },
> +	{ 0x6b6b, 0x75 },
> +	{ 0x6b6c, 0x00 },
> +	{ 0x6b6d, 0x75 },
> +	{ 0x6b6e, 0x00 },
> +	{ 0x6b6f, 0x75 },
> +	{ 0x6b70, 0x00 },
> +	{ 0x6b71, 0x75 },
> +	{ 0x6b72, 0x00 },
> +	{ 0x6b73, 0x75 },
> +	{ 0x6b74, 0x00 },
> +	{ 0x6b75, 0x75 },
> +	{ 0x6b76, 0x00 },
> +	{ 0x6b77, 0x75 },
> +	{ 0x6b78, 0x00 },
> +	{ 0x6b79, 0x75 },
> +	{ 0x6b7a, 0x00 },
> +	{ 0x6b7b, 0x75 },
> +	{ 0x6b7c, 0x00 },
> +	{ 0x6b7d, 0x75 },
> +	{ 0x6b7e, 0x00 },
> +	{ 0x6b7f, 0x75 },
> +	{ 0x6b80, 0x00 },
> +	{ 0x6b81, 0x75 },
> +	{ 0x6b82, 0x00 },
> +	{ 0x6b83, 0x75 },
> +	{ 0x6b84, 0x00 },
> +	{ 0x6b85, 0x75 },
> +	{ 0x6b86, 0x00 },
> +	{ 0x6b87, 0x75 },
> +	{ 0x6b88, 0x00 },
> +	{ 0x6b89, 0x75 },
> +	{ 0x6b8a, 0x00 },
> +	{ 0x6b8b, 0x75 },
> +	{ 0x6b8c, 0x00 },
> +	{ 0x6b8d, 0x75 },
> +	{ 0x6b8e, 0x00 },
> +	{ 0x6b8f, 0x75 },
> +	{ 0x6b90, 0x00 },
> +	{ 0x6b91, 0x75 },
> +	{ 0x6b92, 0x00 },
> +	{ 0x6b93, 0x75 },
> +	{ 0x6b94, 0x00 },
> +	{ 0x6b95, 0x75 },
> +	{ 0x6b96, 0x00 },
> +	{ 0x6b97, 0x75 },
> +	{ 0x6b98, 0x00 },
> +	{ 0x6b99, 0x75 },
> +	{ 0x6b9a, 0x00 },
> +	{ 0x6b9b, 0x75 },
> +	{ 0x6b9c, 0x00 },
> +	{ 0x6b9d, 0x75 },
> +	{ 0x6b9e, 0x00 },
> +	{ 0x6b9f, 0x75 },
> +	{ 0x6ba0, 0x00 },
> +	{ 0x6ba1, 0x75 },
> +	{ 0x6ba2, 0x00 },
> +	{ 0x6ba3, 0x75 },
> +	{ 0x6ba4, 0x00 },
> +	{ 0x6ba5, 0x75 },
> +	{ 0x6ba6, 0x00 },
> +	{ 0x6ba7, 0x75 },
> +	{ 0x6ba8, 0x00 },
> +	{ 0x6ba9, 0x75 },
> +	{ 0x6baa, 0x00 },
> +	{ 0x6bab, 0x75 },
> +	{ 0x6bac, 0x00 },
> +	{ 0x6bad, 0x75 },
> +	{ 0x6bae, 0x00 },
> +	{ 0x6baf, 0x75 },
> +	{ 0x6bb0, 0x00 },
> +	{ 0x6bb1, 0x75 },
> +	{ 0x6bb2, 0x00 },
> +	{ 0x6bb3, 0x75 },
> +	{ 0x6bb4, 0x00 },
> +	{ 0x6bb5, 0x75 },
> +	{ 0x6bb6, 0x00 },
> +	{ 0x6bb7, 0x75 },
> +	{ 0x6bb8, 0x00 },
> +	{ 0x6bb9, 0x75 },
> +	{ 0x6bba, 0x00 },
> +	{ 0x6bbb, 0x75 },
> +	{ 0x6bbc, 0x00 },
> +	{ 0x6bbd, 0x75 },
> +	{ 0x6bbe, 0x00 },
> +	{ 0x6bbf, 0x75 },
> +	{ 0x6bc0, 0x00 },
> +	{ 0x6bc1, 0x75 },
> +	{ 0x6bc2, 0x00 },
> +	{ 0x6bc3, 0x75 },
> +	{ 0x6bc4, 0x00 },
> +	{ 0x6bc5, 0x75 },
> +	{ 0x6bc6, 0x00 },
> +	{ 0x6bc7, 0x75 },
> +	{ 0x6bc8, 0x00 },
> +	{ 0x6bc9, 0x75 },
> +	{ 0x6bca, 0x00 },
> +	{ 0x6bcb, 0x75 },
> +	{ 0x6bcc, 0x00 },
> +	{ 0x6bcd, 0x75 },
> +	{ 0x6bce, 0x00 },
> +	{ 0x6bcf, 0x75 },
> +	{ 0x6bd0, 0x00 },
> +	{ 0x6bd1, 0x75 },
> +	{ 0x6bd2, 0x00 },
> +	{ 0x6bd3, 0x75 },
> +	{ 0x6bd4, 0x00 },
> +	{ 0x6bd5, 0x75 },
> +	{ 0x6bd6, 0x00 },
> +	{ 0x6bd7, 0x75 },
> +	{ 0x6bd8, 0x00 },
> +	{ 0x6bd9, 0x75 },
> +	{ 0x6bda, 0x00 },
> +	{ 0x6bdb, 0x75 },
> +	{ 0x6bdc, 0x00 },
> +	{ 0x6bdd, 0x75 },
> +	{ 0x6bde, 0x00 },
> +	{ 0x6bdf, 0x75 },
> +	{ 0x6be0, 0x00 },
> +	{ 0x6be1, 0x75 },
> +	{ 0x6be2, 0x00 },
> +	{ 0x6be3, 0x75 },
> +	{ 0x6be4, 0x00 },
> +	{ 0x6be5, 0x75 },
> +	{ 0x6be6, 0x00 },
> +	{ 0x6be7, 0x75 },
> +	{ 0x6be8, 0x00 },
> +	{ 0x6be9, 0x75 },
> +	{ 0x6bea, 0x00 },
> +	{ 0x6beb, 0x75 },
> +	{ 0x6bec, 0x00 },
> +	{ 0x6bed, 0x75 },
> +	{ 0x6bee, 0x00 },
> +	{ 0x6bef, 0x75 },
> +	{ 0x6c00, 0x00 },
> +	{ 0x6c01, 0x75 },
> +	{ 0x6c02, 0x00 },
> +	{ 0x6c03, 0x75 },
> +	{ 0x6c04, 0x00 },
> +	{ 0x6c05, 0x75 },
> +	{ 0x6c06, 0x00 },
> +	{ 0x6c07, 0x75 },
> +	{ 0x6c08, 0x00 },
> +	{ 0x6c09, 0x75 },
> +	{ 0x6c0a, 0x00 },
> +	{ 0x6c0b, 0x75 },
> +	{ 0x6c0c, 0x00 },
> +	{ 0x6c0d, 0x75 },
> +	{ 0x6c0e, 0x00 },
> +	{ 0x6c0f, 0x75 },
> +	{ 0x6c10, 0x00 },
> +	{ 0x6c11, 0x75 },
> +	{ 0x6c12, 0x00 },
> +	{ 0x6c13, 0x75 },
> +	{ 0x6c14, 0x00 },
> +	{ 0x6c15, 0x75 },
> +	{ 0x6c16, 0x00 },
> +	{ 0x6c17, 0x75 },
> +	{ 0x6c18, 0x00 },
> +	{ 0x6c19, 0x75 },
> +	{ 0x6c1a, 0x00 },
> +	{ 0x6c1b, 0x75 },
> +	{ 0x6c1c, 0x00 },
> +	{ 0x6c1d, 0x75 },
> +	{ 0x6c1e, 0x00 },
> +	{ 0x6c1f, 0x75 },
> +	{ 0x6c20, 0x00 },
> +	{ 0x6c21, 0x75 },
> +	{ 0x6c22, 0x00 },
> +	{ 0x6c23, 0x75 },
> +	{ 0x6c24, 0x00 },
> +	{ 0x6c25, 0x75 },
> +	{ 0x6c26, 0x00 },
> +	{ 0x6c27, 0x75 },
> +	{ 0x6c28, 0x00 },
> +	{ 0x6c29, 0x75 },
> +	{ 0x6c2a, 0x00 },
> +	{ 0x6c2b, 0x75 },
> +	{ 0x6c2c, 0x00 },
> +	{ 0x6c2d, 0x75 },
> +	{ 0x6c2e, 0x00 },
> +	{ 0x6c2f, 0x75 },
> +	{ 0x6c30, 0x00 },
> +	{ 0x6c31, 0x75 },
> +	{ 0x6c32, 0x00 },
> +	{ 0x6c33, 0x75 },
> +	{ 0x6c34, 0x00 },
> +	{ 0x6c35, 0x75 },
> +	{ 0x6c36, 0x00 },
> +	{ 0x6c37, 0x75 },
> +	{ 0x6c38, 0x00 },
> +	{ 0x6c39, 0x75 },
> +	{ 0x6c3a, 0x00 },
> +	{ 0x6c3b, 0x75 },
> +	{ 0x6c3c, 0x00 },
> +	{ 0x6c3d, 0x75 },
> +	{ 0x6c3e, 0x00 },
> +	{ 0x6c3f, 0x75 },
> +	{ 0x6c40, 0x00 },
> +	{ 0x6c41, 0x75 },
> +	{ 0x6c42, 0x00 },
> +	{ 0x6c43, 0x75 },
> +	{ 0x6c44, 0x00 },
> +	{ 0x6c45, 0x75 },
> +	{ 0x6c46, 0x00 },
> +	{ 0x6c47, 0x75 },
> +	{ 0x6c48, 0x00 },
> +	{ 0x6c49, 0x75 },
> +	{ 0x6c4a, 0x00 },
> +	{ 0x6c4b, 0x75 },
> +	{ 0x6c4c, 0x00 },
> +	{ 0x6c4d, 0x75 },
> +	{ 0x6c4e, 0x00 },
> +	{ 0x6c4f, 0x75 },
> +	{ 0x6c50, 0x00 },
> +	{ 0x6c51, 0x75 },
> +	{ 0x6c52, 0x00 },
> +	{ 0x6c53, 0x75 },
> +	{ 0x6c54, 0x00 },
> +	{ 0x6c55, 0x75 },
> +	{ 0x6c56, 0x00 },
> +	{ 0x6c57, 0x75 },
> +	{ 0x6c58, 0x00 },
> +	{ 0x6c59, 0x75 },
> +	{ 0x6c5a, 0x00 },
> +	{ 0x6c5b, 0x75 },
> +	{ 0x6c5c, 0x00 },
> +	{ 0x6c5d, 0x75 },
> +	{ 0x6c5e, 0x00 },
> +	{ 0x6c5f, 0x75 },
> +	{ 0x6c60, 0x00 },
> +	{ 0x6c61, 0x75 },
> +	{ 0x6c62, 0x00 },
> +	{ 0x6c63, 0x75 },
> +	{ 0x6c64, 0x00 },
> +	{ 0x6c65, 0x75 },
> +	{ 0x6c66, 0x00 },
> +	{ 0x6c67, 0x75 },
> +	{ 0x6c68, 0x00 },
> +	{ 0x6c69, 0x75 },
> +	{ 0x6c6a, 0x00 },
> +	{ 0x6c6b, 0x75 },
> +	{ 0x6c6c, 0x00 },
> +	{ 0x6c6d, 0x75 },
> +	{ 0x6c6e, 0x00 },
> +	{ 0x6c6f, 0x75 },
> +	{ 0x6c70, 0x00 },
> +	{ 0x6c71, 0x75 },
> +	{ 0x6c72, 0x00 },
> +	{ 0x6c73, 0x75 },
> +	{ 0x6c74, 0x00 },
> +	{ 0x6c75, 0x75 },
> +	{ 0x6c76, 0x00 },
> +	{ 0x6c77, 0x75 },
> +	{ 0x6c78, 0x00 },
> +	{ 0x6c79, 0x75 },
> +	{ 0x6c7a, 0x00 },
> +	{ 0x6c7b, 0x75 },
> +	{ 0x6c7c, 0x00 },
> +	{ 0x6c7d, 0x75 },
> +	{ 0x6c7e, 0x00 },
> +	{ 0x6c7f, 0x75 },
> +	{ 0x6c80, 0x00 },
> +	{ 0x6c81, 0x75 },
> +	{ 0x6c82, 0x00 },
> +	{ 0x6c83, 0x75 },
> +	{ 0x6c84, 0x00 },
> +	{ 0x6c85, 0x75 },
> +	{ 0x6c86, 0x00 },
> +	{ 0x6c87, 0x75 },
> +	{ 0x6c88, 0x00 },
> +	{ 0x6c89, 0x75 },
> +	{ 0x6c8a, 0x00 },
> +	{ 0x6c8b, 0x75 },
> +	{ 0x6c8c, 0x00 },
> +	{ 0x6c8d, 0x75 },
> +	{ 0x6c8e, 0x00 },
> +	{ 0x6c8f, 0x75 },
> +	{ 0x6c90, 0x00 },
> +	{ 0x6c91, 0x75 },
> +	{ 0x6c92, 0x00 },
> +	{ 0x6c93, 0x75 },
> +	{ 0x6c94, 0x00 },
> +	{ 0x6c95, 0x75 },
> +	{ 0x6c96, 0x00 },
> +	{ 0x6c97, 0x75 },
> +	{ 0x6c98, 0x00 },
> +	{ 0x6c99, 0x75 },
> +	{ 0x6c9a, 0x00 },
> +	{ 0x6c9b, 0x75 },
> +	{ 0x6c9c, 0x00 },
> +	{ 0x6c9d, 0x75 },
> +	{ 0x6c9e, 0x00 },
> +	{ 0x6c9f, 0x75 },
> +	{ 0x6ca0, 0x00 },
> +	{ 0x6ca1, 0x75 },
> +	{ 0x6ca2, 0x00 },
> +	{ 0x6ca3, 0x75 },
> +	{ 0x6ca4, 0x00 },
> +	{ 0x6ca5, 0x75 },
> +	{ 0x6ca6, 0x00 },
> +	{ 0x6ca7, 0x75 },
> +	{ 0x6ca8, 0x00 },
> +	{ 0x6ca9, 0x75 },
> +	{ 0x6caa, 0x00 },
> +	{ 0x6cab, 0x75 },
> +	{ 0x6cac, 0x00 },
> +	{ 0x6cad, 0x75 },
> +	{ 0x6cae, 0x00 },
> +	{ 0x6caf, 0x75 },
> +	{ 0x6cb0, 0x00 },
> +	{ 0x6cb1, 0x75 },
> +	{ 0x6cb2, 0x00 },
> +	{ 0x6cb3, 0x75 },
> +	{ 0x6cb4, 0x00 },
> +	{ 0x6cb5, 0x75 },
> +	{ 0x6cb6, 0x00 },
> +	{ 0x6cb7, 0x75 },
> +	{ 0x6cb8, 0x00 },
> +	{ 0x6cb9, 0x75 },
> +	{ 0x6cba, 0x00 },
> +	{ 0x6cbb, 0x75 },
> +	{ 0x6cbc, 0x00 },
> +	{ 0x6cbd, 0x75 },
> +	{ 0x6cbe, 0x00 },
> +	{ 0x6cbf, 0x75 },
> +	{ 0x6cc0, 0x00 },
> +	{ 0x6cc1, 0x75 },
> +	{ 0x6cc2, 0x00 },
> +	{ 0x6cc3, 0x75 },
> +	{ 0x6cc4, 0x00 },
> +	{ 0x6cc5, 0x75 },
> +	{ 0x6cc6, 0x00 },
> +	{ 0x6cc7, 0x75 },
> +	{ 0x6cc8, 0x00 },
> +	{ 0x6cc9, 0x75 },
> +	{ 0x6cca, 0x00 },
> +	{ 0x6ccb, 0x75 },
> +	{ 0x6ccc, 0x00 },
> +	{ 0x6ccd, 0x75 },
> +	{ 0x6cce, 0x00 },
> +	{ 0x6ccf, 0x75 },
> +	{ 0x6cd0, 0x00 },
> +	{ 0x6cd1, 0x75 },
> +	{ 0x6cd2, 0x00 },
> +	{ 0x6cd3, 0x75 },
> +	{ 0x6cd4, 0x00 },
> +	{ 0x6cd5, 0x75 },
> +	{ 0x6cd6, 0x00 },
> +	{ 0x6cd7, 0x75 },
> +	{ 0x6cd8, 0x00 },
> +	{ 0x6cd9, 0x75 },
> +	{ 0x6cda, 0x00 },
> +	{ 0x6cdb, 0x75 },
> +	{ 0x6cdc, 0x00 },
> +	{ 0x6cdd, 0x75 },
> +	{ 0x6cde, 0x00 },
> +	{ 0x6cdf, 0x75 },
> +	{ 0x6ce0, 0x00 },
> +	{ 0x6ce1, 0x75 },
> +	{ 0x6ce2, 0x00 },
> +	{ 0x6ce3, 0x75 },
> +	{ 0x6ce4, 0x00 },
> +	{ 0x6ce5, 0x75 },
> +	{ 0x6ce6, 0x00 },
> +	{ 0x6ce7, 0x75 },
> +	{ 0x6ce8, 0x00 },
> +	{ 0x6ce9, 0x75 },
> +	{ 0x6cea, 0x00 },
> +	{ 0x6ceb, 0x75 },
> +	{ 0x6cec, 0x00 },
> +	{ 0x6ced, 0x75 },
> +	{ 0x6cee, 0x00 },
> +	{ 0x6cef, 0x75 },
> +	{ 0x6cf0, 0x00 },
> +	{ 0x6cf1, 0x75 },
> +	{ 0x6cf2, 0x00 },
> +	{ 0x6cf3, 0x75 },
> +	{ 0x6cf4, 0x00 },
> +	{ 0x6cf5, 0x75 },
> +	{ 0x6cf6, 0x00 },
> +	{ 0x6cf7, 0x75 },
> +	{ 0x6cf8, 0x00 },
> +	{ 0x6cf9, 0x75 },
> +	{ 0x6cfa, 0x00 },
> +	{ 0x6cfb, 0x75 },
> +	{ 0x6cfc, 0x00 },
> +	{ 0x6cfd, 0x75 },
> +	{ 0x6cfe, 0x00 },
> +	{ 0x6cff, 0x75 },
> +	{ 0x6d00, 0x00 },
> +	{ 0x6d01, 0x75 },
> +	{ 0x6d02, 0x00 },
> +	{ 0x6d03, 0x75 },
> +	{ 0x6d04, 0x00 },
> +	{ 0x6d05, 0x75 },
> +	{ 0x6d06, 0x00 },
> +	{ 0x6d07, 0x75 },
> +	{ 0x6d08, 0x00 },
> +	{ 0x6d09, 0x75 },
> +	{ 0x6d0a, 0x00 },
> +	{ 0x6d0b, 0x75 },
> +	{ 0x6d0c, 0x00 },
> +	{ 0x6d0d, 0x75 },
> +	{ 0x6d0e, 0x00 },
> +	{ 0x6d0f, 0x75 },
> +	{ 0x6d10, 0x00 },
> +	{ 0x6d11, 0x75 },
> +	{ 0x6d12, 0x00 },
> +	{ 0x6d13, 0x75 },
> +	{ 0x6d14, 0x00 },
> +	{ 0x6d15, 0x75 },
> +	{ 0x6d16, 0x00 },
> +	{ 0x6d17, 0x75 },
> +	{ 0x6d18, 0x00 },
> +	{ 0x6d19, 0x75 },
> +	{ 0x6d1a, 0x00 },
> +	{ 0x6d1b, 0x75 },
> +	{ 0x6d1c, 0x00 },
> +	{ 0x6d1d, 0x75 },
> +	{ 0x6d1e, 0x00 },
> +	{ 0x6d1f, 0x75 },
> +	{ 0x6d20, 0x00 },
> +	{ 0x6d21, 0x75 },
> +	{ 0x6d22, 0x00 },
> +	{ 0x6d23, 0x75 },
> +	{ 0x6d24, 0x00 },
> +	{ 0x6d25, 0x75 },
> +	{ 0x6d26, 0x00 },
> +	{ 0x6d27, 0x75 },
> +	{ 0x6d28, 0x00 },
> +	{ 0x6d29, 0x75 },
> +	{ 0x6d2a, 0x00 },
> +	{ 0x6d2b, 0x75 },
> +	{ 0x6d2c, 0x00 },
> +	{ 0x6d2d, 0x75 },
> +	{ 0x6d2e, 0x00 },
> +	{ 0x6d2f, 0x75 },
> +	{ 0x6d30, 0x00 },
> +	{ 0x6d31, 0x75 },
> +	{ 0x6d32, 0x00 },
> +	{ 0x6d33, 0x75 },
> +	{ 0x6d34, 0x00 },
> +	{ 0x6d35, 0x75 },
> +	{ 0x6d36, 0x00 },
> +	{ 0x6d37, 0x75 },
> +	{ 0x6d38, 0x00 },
> +	{ 0x6d39, 0x75 },
> +	{ 0x6d3a, 0x00 },
> +	{ 0x6d3b, 0x75 },
> +	{ 0x6d3c, 0x00 },
> +	{ 0x6d3d, 0x75 },
> +	{ 0x6d3e, 0x00 },
> +	{ 0x6d3f, 0x75 },
> +	{ 0x6d40, 0x00 },
> +	{ 0x6d41, 0x75 },
> +	{ 0x6d42, 0x00 },
> +	{ 0x6d43, 0x75 },
> +	{ 0x6d44, 0x00 },
> +	{ 0x6d45, 0x75 },
> +	{ 0x6d46, 0x00 },
> +	{ 0x6d47, 0x75 },
> +	{ 0x6d48, 0x00 },
> +	{ 0x6d49, 0x75 },
> +	{ 0x6d4a, 0x00 },
> +	{ 0x6d4b, 0x75 },
> +	{ 0x6d4c, 0x00 },
> +	{ 0x6d4d, 0x75 },
> +	{ 0x6d4e, 0x00 },
> +	{ 0x6d4f, 0x75 },
> +	{ 0x6d50, 0x00 },
> +	{ 0x6d51, 0x75 },
> +	{ 0x6d52, 0x00 },
> +	{ 0x6d53, 0x75 },
> +	{ 0x6d54, 0x00 },
> +	{ 0x6d55, 0x75 },
> +	{ 0x6d56, 0x00 },
> +	{ 0x6d57, 0x75 },
> +	{ 0x6d58, 0x00 },
> +	{ 0x6d59, 0x75 },
> +	{ 0x6d5a, 0x00 },
> +	{ 0x6d5b, 0x75 },
> +	{ 0x6d5c, 0x00 },
> +	{ 0x6d5d, 0x75 },
> +	{ 0x6d5e, 0x00 },
> +	{ 0x6d5f, 0x75 },
> +	{ 0x6d60, 0x00 },
> +	{ 0x6d61, 0x75 },
> +	{ 0x6d62, 0x00 },
> +	{ 0x6d63, 0x75 },
> +	{ 0x6d64, 0x00 },
> +	{ 0x6d65, 0x75 },
> +	{ 0x6d66, 0x00 },
> +	{ 0x6d67, 0x75 },
> +	{ 0x6d68, 0x00 },
> +	{ 0x6d69, 0x75 },
> +	{ 0x6d6a, 0x00 },
> +	{ 0x6d6b, 0x75 },
> +	{ 0x6d6c, 0x00 },
> +	{ 0x6d6d, 0x75 },
> +	{ 0x6d6e, 0x00 },
> +	{ 0x6d6f, 0x75 },
> +	{ 0x6d70, 0x00 },
> +	{ 0x6d71, 0x75 },
> +	{ 0x6d72, 0x00 },
> +	{ 0x6d73, 0x75 },
> +	{ 0x6d74, 0x00 },
> +	{ 0x6d75, 0x75 },
> +	{ 0x6d76, 0x00 },
> +	{ 0x6d77, 0x75 },
> +	{ 0x6d78, 0x00 },
> +	{ 0x6d79, 0x75 },
> +	{ 0x6d7a, 0x00 },
> +	{ 0x6d7b, 0x75 },
> +	{ 0x6d7c, 0x00 },
> +	{ 0x6d7d, 0x75 },
> +	{ 0x6d7e, 0x00 },
> +	{ 0x6d7f, 0x75 },
> +	{ 0x6d80, 0x00 },
> +	{ 0x6d81, 0x75 },
> +	{ 0x6d82, 0x00 },
> +	{ 0x6d83, 0x75 },
> +	{ 0x6d84, 0x00 },
> +	{ 0x6d85, 0x75 },
> +	{ 0x6d86, 0x00 },
> +	{ 0x6d87, 0x75 },
> +	{ 0x6d88, 0x00 },
> +	{ 0x6d89, 0x75 },
> +	{ 0x6d8a, 0x00 },
> +	{ 0x6d8b, 0x75 },
> +	{ 0x6d8c, 0x00 },
> +	{ 0x6d8d, 0x75 },
> +	{ 0x6d8e, 0x00 },
> +	{ 0x6d8f, 0x75 },
> +	{ 0x6d90, 0x00 },
> +	{ 0x6d91, 0x75 },
> +	{ 0x6d92, 0x00 },
> +	{ 0x6d93, 0x75 },
> +	{ 0x6d94, 0x00 },
> +	{ 0x6d95, 0x75 },
> +	{ 0x6d96, 0x00 },
> +	{ 0x6d97, 0x75 },
> +	{ 0x6d98, 0x00 },
> +	{ 0x6d99, 0x75 },
> +	{ 0x6d9a, 0x00 },
> +	{ 0x6d9b, 0x75 },
> +	{ 0x6d9c, 0x00 },
> +	{ 0x6d9d, 0x75 },
> +	{ 0x6d9e, 0x00 },
> +	{ 0x6d9f, 0x75 },
> +	{ 0x6da0, 0x00 },
> +	{ 0x6da1, 0x75 },
> +	{ 0x6da2, 0x00 },
> +	{ 0x6da3, 0x75 },
> +	{ 0x6da4, 0x00 },
> +	{ 0x6da5, 0x75 },
> +	{ 0x6da6, 0x00 },
> +	{ 0x6da7, 0x75 },
> +	{ 0x6da8, 0x00 },
> +	{ 0x6da9, 0x75 },
> +	{ 0x6daa, 0x00 },
> +	{ 0x6dab, 0x75 },
> +	{ 0x6dac, 0x00 },
> +	{ 0x6dad, 0x75 },
> +	{ 0x6dae, 0x00 },
> +	{ 0x6daf, 0x75 },
> +	{ 0x6db0, 0x00 },
> +	{ 0x6db1, 0x75 },
> +	{ 0x6db2, 0x00 },
> +	{ 0x6db3, 0x75 },
> +	{ 0x6db4, 0x00 },
> +	{ 0x6db5, 0x75 },
> +	{ 0x6db6, 0x00 },
> +	{ 0x6db7, 0x75 },
> +	{ 0x6db8, 0x00 },
> +	{ 0x6db9, 0x75 },
> +	{ 0x6dba, 0x00 },
> +	{ 0x6dbb, 0x75 },
> +	{ 0x6dbc, 0x00 },
> +	{ 0x6dbd, 0x75 },
> +	{ 0x6dbe, 0x00 },
> +	{ 0x6dbf, 0x75 },
> +	{ 0x6dc0, 0x00 },
> +	{ 0x6dc1, 0x75 },
> +	{ 0x6dc2, 0x00 },
> +	{ 0x6dc3, 0x75 },
> +	{ 0x6dc4, 0x00 },
> +	{ 0x6dc5, 0x75 },
> +	{ 0x6dc6, 0x00 },
> +	{ 0x6dc7, 0x75 },
> +	{ 0x6dc8, 0x00 },
> +	{ 0x6dc9, 0x75 },
> +	{ 0x6dca, 0x00 },
> +	{ 0x6dcb, 0x75 },
> +	{ 0x6dcc, 0x00 },
> +	{ 0x6dcd, 0x75 },
> +	{ 0x6dce, 0x00 },
> +	{ 0x6dcf, 0x75 },
> +	{ 0x6dd0, 0x00 },
> +	{ 0x6dd1, 0x75 },
> +	{ 0x6dd2, 0x00 },
> +	{ 0x6dd3, 0x75 },
> +	{ 0x6dd4, 0x00 },
> +	{ 0x6dd5, 0x75 },
> +	{ 0x6dd6, 0x00 },
> +	{ 0x6dd7, 0x75 },
> +	{ 0x6dd8, 0x00 },
> +	{ 0x6dd9, 0x75 },
> +	{ 0x6dda, 0x00 },
> +	{ 0x6ddb, 0x75 },
> +	{ 0x6ddc, 0x00 },
> +	{ 0x6ddd, 0x75 },
> +	{ 0x6dde, 0x00 },
> +	{ 0x6ddf, 0x75 },
> +	{ 0x6de0, 0x00 },
> +	{ 0x6de1, 0x75 },
> +	{ 0x6de2, 0x00 },
> +	{ 0x6de3, 0x75 },
> +	{ 0x6de4, 0x00 },
> +	{ 0x6de5, 0x75 },
> +	{ 0x6de6, 0x00 },
> +	{ 0x6de7, 0x75 },
> +	{ 0x6de8, 0x00 },
> +	{ 0x6de9, 0x75 },
> +	{ 0x6dea, 0x00 },
> +	{ 0x6deb, 0x75 },
> +	{ 0x6dec, 0x00 },
> +	{ 0x6ded, 0x75 },
> +	{ 0x6dee, 0x00 },
> +	{ 0x6def, 0x75 },
> +	{ 0x6df0, 0x00 },
> +	{ 0x6df1, 0x75 },
> +	{ 0x6df2, 0x00 },
> +	{ 0x6df3, 0x75 },
> +	{ 0x6df4, 0x00 },
> +	{ 0x6df5, 0x75 },
> +	{ 0x6df6, 0x00 },
> +	{ 0x6df7, 0x75 },
> +	{ 0x6df8, 0x00 },
> +	{ 0x6df9, 0x75 },
> +	{ 0x6dfa, 0x00 },
> +	{ 0x6dfb, 0x75 },
> +	{ 0x6dfc, 0x00 },
> +	{ 0x6dfd, 0x75 },
> +	{ 0x6dfe, 0x00 },
> +	{ 0x6dff, 0x75 },
> +	{ 0x6e00, 0x00 },
> +	{ 0x6e01, 0x75 },
> +	{ 0x6e02, 0x00 },
> +	{ 0x6e03, 0x75 },
> +	{ 0x6e04, 0x00 },
> +	{ 0x6e05, 0x75 },
> +	{ 0x6e06, 0x00 },
> +	{ 0x6e07, 0x75 },
> +	{ 0x6e08, 0x00 },
> +	{ 0x6e09, 0x75 },
> +	{ 0x6e0a, 0x00 },
> +	{ 0x6e0b, 0x75 },
> +	{ 0x6e0c, 0x00 },
> +	{ 0x6e0d, 0x75 },
> +	{ 0x6e0e, 0x00 },
> +	{ 0x6e0f, 0x75 },
> +	{ 0x6e10, 0x00 },
> +	{ 0x6e11, 0x75 },
> +	{ 0x6e12, 0x00 },
> +	{ 0x6e13, 0x75 },
> +	{ 0x6e14, 0x00 },
> +	{ 0x6e15, 0x75 },
> +	{ 0x6e16, 0x00 },
> +	{ 0x6e17, 0x75 },
> +	{ 0x6e18, 0x00 },
> +	{ 0x6e19, 0x75 },
> +	{ 0x6e1a, 0x00 },
> +	{ 0x6e1b, 0x75 },
> +	{ 0x6e1c, 0x00 },
> +	{ 0x6e1d, 0x75 },
> +	{ 0x6e1e, 0x00 },
> +	{ 0x6e1f, 0x75 },
> +	{ 0x6e20, 0x00 },
> +	{ 0x6e21, 0x75 },
> +	{ 0x6e22, 0x00 },
> +	{ 0x6e23, 0x75 },
> +	{ 0x6e24, 0x00 },
> +	{ 0x6e25, 0x75 },
> +	{ 0x6e26, 0x00 },
> +	{ 0x6e27, 0x75 },
> +	{ 0x6e28, 0x00 },
> +	{ 0x6e29, 0x75 },
> +	{ 0x6e2a, 0x00 },
> +	{ 0x6e2b, 0x75 },
> +	{ 0x6e2c, 0x00 },
> +	{ 0x6e2d, 0x75 },
> +	{ 0x6e2e, 0x00 },
> +	{ 0x6e2f, 0x75 },
> +	{ 0x6e30, 0x00 },
> +	{ 0x6e31, 0x75 },
> +	{ 0x6e32, 0x00 },
> +	{ 0x6e33, 0x75 },
> +	{ 0x6e34, 0x00 },
> +	{ 0x6e35, 0x75 },
> +	{ 0x6e36, 0x00 },
> +	{ 0x6e37, 0x75 },
> +	{ 0x6e38, 0x00 },
> +	{ 0x6e39, 0x75 },
> +	{ 0x6e3a, 0x00 },
> +	{ 0x6e3b, 0x75 },
> +	{ 0x6e3c, 0x00 },
> +	{ 0x6e3d, 0x75 },
> +	{ 0x6e3e, 0x00 },
> +	{ 0x6e3f, 0x75 },
> +	{ 0x6e40, 0x00 },
> +	{ 0x6e41, 0x75 },
> +	{ 0x6e42, 0x00 },
> +	{ 0x6e43, 0x75 },
> +	{ 0x6e44, 0x00 },
> +	{ 0x6e45, 0x75 },
> +	{ 0x6e46, 0x00 },
> +	{ 0x6e47, 0x75 },
> +	{ 0x6e48, 0x00 },
> +	{ 0x6e49, 0x75 },
> +	{ 0x6e4a, 0x00 },
> +	{ 0x6e4b, 0x75 },
> +	{ 0x6e4c, 0x00 },
> +	{ 0x6e4d, 0x75 },
> +	{ 0x6e4e, 0x00 },
> +	{ 0x6e4f, 0x75 },
> +	{ 0x6e50, 0x00 },
> +	{ 0x6e51, 0x75 },
> +	{ 0x6e52, 0x00 },
> +	{ 0x6e53, 0x75 },
> +	{ 0x6e54, 0x00 },
> +	{ 0x6e55, 0x75 },
> +	{ 0x6e56, 0x00 },
> +	{ 0x6e57, 0x75 },
> +	{ 0x6e58, 0x00 },
> +	{ 0x6e59, 0x75 },
> +	{ 0x6e5a, 0x00 },
> +	{ 0x6e5b, 0x75 },
> +	{ 0x6e5c, 0x00 },
> +	{ 0x6e5d, 0x75 },
> +	{ 0x6e5e, 0x00 },
> +	{ 0x6e5f, 0x75 },
> +	{ 0x6e60, 0x00 },
> +	{ 0x6e61, 0x75 },
> +	{ 0x6e62, 0x00 },
> +	{ 0x6e63, 0x75 },
> +	{ 0x6e64, 0x00 },
> +	{ 0x6e65, 0x75 },
> +	{ 0x6e66, 0x00 },
> +	{ 0x6e67, 0x75 },
> +	{ 0x6e68, 0x00 },
> +	{ 0x6e69, 0x75 },
> +	{ 0x6e6a, 0x00 },
> +	{ 0x6e6b, 0x75 },
> +	{ 0x6e6c, 0x00 },
> +	{ 0x6e6d, 0x75 },
> +	{ 0x6e6e, 0x00 },
> +	{ 0x6e6f, 0x75 },
> +	{ 0x6e70, 0x00 },
> +	{ 0x6e71, 0x75 },
> +	{ 0x6e72, 0x00 },
> +	{ 0x6e73, 0x75 },
> +	{ 0x6e74, 0x00 },
> +	{ 0x6e75, 0x75 },
> +	{ 0x6e76, 0x00 },
> +	{ 0x6e77, 0x75 },
> +	{ 0x6e78, 0x00 },
> +	{ 0x6e79, 0x75 },
> +	{ 0x6e7a, 0x00 },
> +	{ 0x6e7b, 0x75 },
> +	{ 0x6e7c, 0x00 },
> +	{ 0x6e7d, 0x75 },
> +	{ 0x6e7e, 0x00 },
> +	{ 0x6e7f, 0x75 },
> +	{ 0x6e80, 0x00 },
> +	{ 0x6e81, 0x75 },
> +	{ 0x6e82, 0x00 },
> +	{ 0x6e83, 0x75 },
> +	{ 0x6e84, 0x00 },
> +	{ 0x6e85, 0x75 },
> +	{ 0x6e86, 0x00 },
> +	{ 0x6e87, 0x75 },
> +	{ 0x6e88, 0x00 },
> +	{ 0x6e89, 0x75 },
> +	{ 0x6e8a, 0x00 },
> +	{ 0x6e8b, 0x75 },
> +	{ 0x6e8c, 0x00 },
> +	{ 0x6e8d, 0x75 },
> +	{ 0x6e8e, 0x00 },
> +	{ 0x6e8f, 0x75 },
> +	{ 0x6e90, 0x00 },
> +	{ 0x6e91, 0x75 },
> +	{ 0x6e92, 0x00 },
> +	{ 0x6e93, 0x75 },
> +	{ 0x6e94, 0x00 },
> +	{ 0x6e95, 0x75 },
> +	{ 0x6e96, 0x00 },
> +	{ 0x6e97, 0x75 },
> +	{ 0x6e98, 0x00 },
> +	{ 0x6e99, 0x75 },
> +	{ 0x6e9a, 0x00 },
> +	{ 0x6e9b, 0x75 },
> +	{ 0x6e9c, 0x00 },
> +	{ 0x6e9d, 0x75 },
> +	{ 0x6e9e, 0x00 },
> +	{ 0x6e9f, 0x75 },
> +	{ 0x6ea0, 0x00 },
> +	{ 0x6ea1, 0x75 },
> +	{ 0x6ea2, 0x00 },
> +	{ 0x6ea3, 0x75 },
> +	{ 0x6ea4, 0x00 },
> +	{ 0x6ea5, 0x75 },
> +	{ 0x6ea6, 0x00 },
> +	{ 0x6ea7, 0x75 },
> +	{ 0x6ea8, 0x00 },
> +	{ 0x6ea9, 0x75 },
> +	{ 0x6eaa, 0x00 },
> +	{ 0x6eab, 0x75 },
> +	{ 0x6eac, 0x00 },
> +	{ 0x6ead, 0x75 },
> +	{ 0x6eae, 0x00 },
> +	{ 0x6eaf, 0x75 },
> +	{ 0x6eb0, 0x00 },
> +	{ 0x6eb1, 0x75 },
> +	{ 0x6eb2, 0x00 },
> +	{ 0x6eb3, 0x75 },
> +	{ 0x6eb4, 0x00 },
> +	{ 0x6eb5, 0x75 },
> +	{ 0x6eb6, 0x00 },
> +	{ 0x6eb7, 0x75 },
> +	{ 0x6eb8, 0x00 },
> +	{ 0x6eb9, 0x75 },
> +	{ 0x6eba, 0x00 },
> +	{ 0x6ebb, 0x75 },
> +	{ 0x6ebc, 0x00 },
> +	{ 0x6ebd, 0x75 },
> +	{ 0x6ebe, 0x00 },
> +	{ 0x6ebf, 0x75 },
> +	{ 0x6ec0, 0x00 },
> +	{ 0x6ec1, 0x75 },
> +	{ 0x6ec2, 0x00 },
> +	{ 0x6ec3, 0x75 },
> +	{ 0x6ec4, 0x00 },
> +	{ 0x6ec5, 0x75 },
> +	{ 0x6ec6, 0x00 },
> +	{ 0x6ec7, 0x75 },
> +	{ 0x6ec8, 0x00 },
> +	{ 0x6ec9, 0x75 },
> +	{ 0x6eca, 0x00 },
> +	{ 0x6ecb, 0x75 },
> +	{ 0x6ecc, 0x00 },
> +	{ 0x6ecd, 0x75 },
> +	{ 0x6ece, 0x00 },
> +	{ 0x6ecf, 0x75 },
> +	{ 0x6ed0, 0x00 },
> +	{ 0x6ed1, 0x75 },
> +	{ 0x6ed2, 0x00 },
> +	{ 0x6ed3, 0x75 },
> +	{ 0x6ed4, 0x00 },
> +	{ 0x6ed5, 0x75 },
> +	{ 0x6ed6, 0x00 },
> +	{ 0x6ed7, 0x75 },
> +	{ 0x6ed8, 0x00 },
> +	{ 0x6ed9, 0x75 },
> +	{ 0x6eda, 0x00 },
> +	{ 0x6edb, 0x75 },
> +	{ 0x6edc, 0x00 },
> +	{ 0x6edd, 0x75 },
> +	{ 0x6ede, 0x00 },
> +	{ 0x6edf, 0x75 },
> +	{ 0x6ee0, 0x00 },
> +	{ 0x6ee1, 0x75 },
> +	{ 0x6ee2, 0x00 },
> +	{ 0x6ee3, 0x75 },
> +	{ 0x6ee4, 0x00 },
> +	{ 0x6ee5, 0x75 },
> +	{ 0x6ee6, 0x00 },
> +	{ 0x6ee7, 0x75 },
> +	{ 0x6ee8, 0x00 },
> +	{ 0x6ee9, 0x75 },
> +	{ 0x6eea, 0x00 },
> +	{ 0x6eeb, 0x75 },
> +	{ 0x6eec, 0x00 },
> +	{ 0x6eed, 0x75 },
> +	{ 0x6eee, 0x00 },
> +	{ 0x6eef, 0x75 },
> +	{ 0x6ef0, 0x00 },
> +	{ 0x6ef1, 0x75 },
> +	{ 0x6ef2, 0x00 },
> +	{ 0x6ef3, 0x75 },
> +	{ 0x6ef4, 0x00 },
> +	{ 0x6ef5, 0x75 },
> +	{ 0x6ef6, 0x00 },
> +	{ 0x6ef7, 0x75 },
> +	{ 0x6ef8, 0x00 },
> +	{ 0x6ef9, 0x75 },
> +	{ 0x6efa, 0x00 },
> +	{ 0x6efb, 0x75 },
> +	{ 0x6efc, 0x00 },
> +	{ 0x6efd, 0x75 },
> +	{ 0x6efe, 0x00 },
> +	{ 0x6eff, 0x75 },
> +	{ 0x6f00, 0x00 },
> +	{ 0x6f01, 0x75 },
> +	{ 0x6f02, 0x00 },
> +	{ 0x6f03, 0x75 },
> +	{ 0x6f04, 0x00 },
> +	{ 0x6f05, 0x75 },
> +	{ 0x6f06, 0x00 },
> +	{ 0x6f07, 0x75 },
> +	{ 0x6f08, 0x00 },
> +	{ 0x6f09, 0x75 },
> +	{ 0x6f0a, 0x00 },
> +	{ 0x6f0b, 0x75 },
> +	{ 0x6f0c, 0x00 },
> +	{ 0x6f0d, 0x75 },
> +	{ 0x6f0e, 0x00 },
> +	{ 0x6f0f, 0x75 },
> +	{ 0x6f10, 0x00 },
> +	{ 0x6f11, 0x75 },
> +	{ 0x6f12, 0x00 },
> +	{ 0x6f13, 0x75 },
> +	{ 0x6f14, 0x00 },
> +	{ 0x6f15, 0x75 },
> +	{ 0x6f16, 0x00 },
> +	{ 0x6f17, 0x75 },
> +	{ 0x6f18, 0x00 },
> +	{ 0x6f19, 0x75 },
> +	{ 0x6f1a, 0x00 },
> +	{ 0x6f1b, 0x75 },
> +	{ 0x6f1c, 0x00 },
> +	{ 0x6f1d, 0x75 },
> +	{ 0x6f1e, 0x00 },
> +	{ 0x6f1f, 0x75 },
> +	{ 0x6f20, 0x00 },
> +	{ 0x6f21, 0x75 },
> +	{ 0x6f22, 0x00 },
> +	{ 0x6f23, 0x75 },
> +	{ 0x6f24, 0x00 },
> +	{ 0x6f25, 0x75 },
> +	{ 0x6f26, 0x00 },
> +	{ 0x6f27, 0x75 },
> +	{ 0x6f28, 0x00 },
> +	{ 0x6f29, 0x75 },
> +	{ 0x6f2a, 0x00 },
> +	{ 0x6f2b, 0x75 },
> +	{ 0x6f2c, 0x00 },
> +	{ 0x6f2d, 0x75 },
> +	{ 0x6f2e, 0x00 },
> +	{ 0x6f2f, 0x75 },
> +	{ 0x6f30, 0x00 },
> +	{ 0x6f31, 0x75 },
> +	{ 0x6f32, 0x00 },
> +	{ 0x6f33, 0x75 },
> +	{ 0x6f34, 0x00 },
> +	{ 0x6f35, 0x75 },
> +	{ 0x6f36, 0x00 },
> +	{ 0x6f37, 0x75 },
> +	{ 0x6f38, 0x00 },
> +	{ 0x6f39, 0x75 },
> +	{ 0x6f3a, 0x00 },
> +	{ 0x6f3b, 0x75 },
> +	{ 0x6f3c, 0x00 },
> +	{ 0x6f3d, 0x75 },
> +	{ 0x6f3e, 0x00 },
> +	{ 0x6f3f, 0x75 },
> +	{ 0x6f40, 0x00 },
> +	{ 0x6f41, 0x75 },
> +	{ 0x6f42, 0x00 },
> +	{ 0x6f43, 0x75 },
> +	{ 0x6f44, 0x00 },
> +	{ 0x6f45, 0x75 },
> +	{ 0x6f46, 0x00 },
> +	{ 0x6f47, 0x75 },
> +	{ 0x6f48, 0x00 },
> +	{ 0x6f49, 0x75 },
> +	{ 0x6f4a, 0x00 },
> +	{ 0x6f4b, 0x75 },
> +	{ 0x6f4c, 0x00 },
> +	{ 0x6f4d, 0x75 },
> +	{ 0x6f4e, 0x00 },
> +	{ 0x6f4f, 0x75 },
> +	{ 0x6f50, 0x00 },
> +	{ 0x6f51, 0x75 },
> +	{ 0x6f52, 0x00 },
> +	{ 0x6f53, 0x75 },
> +	{ 0x6f54, 0x00 },
> +	{ 0x6f55, 0x75 },
> +	{ 0x6f56, 0x00 },
> +	{ 0x6f57, 0x75 },
> +	{ 0x6f58, 0x00 },
> +	{ 0x6f59, 0x75 },
> +	{ 0x6f5a, 0x00 },
> +	{ 0x6f5b, 0x75 },
> +	{ 0x6f5c, 0x00 },
> +	{ 0x6f5d, 0x75 },
> +	{ 0x6f5e, 0x00 },
> +	{ 0x6f5f, 0x75 },
> +	{ 0x6f60, 0x00 },
> +	{ 0x6f61, 0x75 },
> +	{ 0x6f62, 0x00 },
> +	{ 0x6f63, 0x75 },
> +	{ 0x6f64, 0x00 },
> +	{ 0x6f65, 0x75 },
> +	{ 0x6f66, 0x00 },
> +	{ 0x6f67, 0x75 },
> +	{ 0x6f68, 0x00 },
> +	{ 0x6f69, 0x75 },
> +	{ 0x6f6a, 0x00 },
> +	{ 0x6f6b, 0x75 },
> +	{ 0x6f6c, 0x00 },
> +	{ 0x6f6d, 0x75 },
> +	{ 0x6f6e, 0x00 },
> +	{ 0x6f6f, 0x75 },
> +	{ 0x6f70, 0x00 },
> +	{ 0x6f71, 0x75 },
> +	{ 0x6f72, 0x00 },
> +	{ 0x6f73, 0x75 },
> +	{ 0x6f74, 0x00 },
> +	{ 0x6f75, 0x75 },
> +	{ 0x6f76, 0x00 },
> +	{ 0x6f77, 0x75 },
> +	{ 0x6f78, 0x00 },
> +	{ 0x6f79, 0x75 },
> +	{ 0x6f7a, 0x00 },
> +	{ 0x6f7b, 0x75 },
> +	{ 0x6f7c, 0x00 },
> +	{ 0x6f7d, 0x75 },
> +	{ 0x6f7e, 0x00 },
> +	{ 0x6f7f, 0x75 },
> +	{ 0x6f80, 0x00 },
> +	{ 0x6f81, 0x75 },
> +	{ 0x6f82, 0x00 },
> +	{ 0x6f83, 0x75 },
> +	{ 0x6f84, 0x00 },
> +	{ 0x6f85, 0x75 },
> +	{ 0x6f86, 0x00 },
> +	{ 0x6f87, 0x75 },
> +	{ 0x6f88, 0x00 },
> +	{ 0x6f89, 0x75 },
> +	{ 0x6f8a, 0x00 },
> +	{ 0x6f8b, 0x75 },
> +	{ 0x6f8c, 0x00 },
> +	{ 0x6f8d, 0x75 },
> +	{ 0x6f8e, 0x00 },
> +	{ 0x6f8f, 0x75 },
> +	{ 0x6f90, 0x00 },
> +	{ 0x6f91, 0x75 },
> +	{ 0x6f92, 0x00 },
> +	{ 0x6f93, 0x75 },
> +	{ 0x6f94, 0x00 },
> +	{ 0x6f95, 0x75 },
> +	{ 0x6f96, 0x00 },
> +	{ 0x6f97, 0x75 },
> +	{ 0x6f98, 0x00 },
> +	{ 0x6f99, 0x75 },
> +	{ 0x6f9a, 0x00 },
> +	{ 0x6f9b, 0x75 },
> +	{ 0x6f9c, 0x00 },
> +	{ 0x6f9d, 0x75 },
> +	{ 0x6f9e, 0x00 },
> +	{ 0x6f9f, 0x75 },
> +	{ 0x6fa0, 0x00 },
> +	{ 0x6fa1, 0x75 },
> +	{ 0x6fa2, 0x00 },
> +	{ 0x6fa3, 0x75 },
> +	{ 0x6fa4, 0x00 },
> +	{ 0x6fa5, 0x75 },
> +	{ 0x6fa6, 0x00 },
> +	{ 0x6fa7, 0x75 },
> +	{ 0x6fa8, 0x00 },
> +	{ 0x6fa9, 0x75 },
> +	{ 0x6faa, 0x00 },
> +	{ 0x6fab, 0x75 },
> +	{ 0x6fac, 0x00 },
> +	{ 0x6fad, 0x75 },
> +	{ 0x6fae, 0x00 },
> +	{ 0x6faf, 0x75 },
> +	{ 0x6fb0, 0x00 },
> +	{ 0x6fb1, 0x75 },
> +	{ 0x6fb2, 0x00 },
> +	{ 0x6fb3, 0x75 },
> +	{ 0x6fb4, 0x00 },
> +	{ 0x6fb5, 0x75 },
> +	{ 0x6fb6, 0x00 },
> +	{ 0x6fb7, 0x75 },
> +	{ 0x6fb8, 0x00 },
> +	{ 0x6fb9, 0x75 },
> +	{ 0x6fba, 0x00 },
> +	{ 0x6fbb, 0x75 },
> +	{ 0x6fbc, 0x00 },
> +	{ 0x6fbd, 0x75 },
> +	{ 0x6fbe, 0x00 },
> +	{ 0x6fbf, 0x75 },
> +	{ 0x6fc0, 0x00 },
> +	{ 0x6fc1, 0x75 },
> +	{ 0x6fc2, 0x00 },
> +	{ 0x6fc3, 0x75 },
> +	{ 0x6fc4, 0x00 },
> +	{ 0x6fc5, 0x75 },
> +	{ 0x6fc6, 0x00 },
> +	{ 0x6fc7, 0x75 },
> +	{ 0x6fc8, 0x00 },
> +	{ 0x6fc9, 0x75 },
> +	{ 0x6fca, 0x00 },
> +	{ 0x6fcb, 0x75 },
> +	{ 0x6fcc, 0x00 },
> +	{ 0x6fcd, 0x75 },
> +	{ 0x6fce, 0x00 },
> +	{ 0x6fcf, 0x75 },
> +	{ 0x6fd0, 0x00 },
> +	{ 0x6fd1, 0x75 },
> +	{ 0x6fd2, 0x00 },
> +	{ 0x6fd3, 0x75 },
> +	{ 0x6fd4, 0x00 },
> +	{ 0x6fd5, 0x75 },
> +	{ 0x6fd6, 0x00 },
> +	{ 0x6fd7, 0x75 },
> +	{ 0x6fd8, 0x00 },
> +	{ 0x6fd9, 0x75 },
> +	{ 0x6fda, 0x00 },
> +	{ 0x6fdb, 0x75 },
> +	{ 0x6fdc, 0x00 },
> +	{ 0x6fdd, 0x75 },
> +	{ 0x6fde, 0x00 },
> +	{ 0x6fdf, 0x75 },
> +	{ 0x6fe0, 0x00 },
> +	{ 0x6fe1, 0x75 },
> +	{ 0x6fe2, 0x00 },
> +	{ 0x6fe3, 0x75 },
> +	{ 0x6fe4, 0x00 },
> +	{ 0x6fe5, 0x75 },
> +	{ 0x6fe6, 0x00 },
> +	{ 0x6fe7, 0x75 },
> +	{ 0x6fe8, 0x00 },
> +	{ 0x6fe9, 0x75 },
> +	{ 0x6fea, 0x00 },
> +	{ 0x6feb, 0x75 },
> +	{ 0x6fec, 0x00 },
> +	{ 0x6fed, 0x75 },
> +	{ 0x6fee, 0x00 },
> +	{ 0x6fef, 0x75 },
> +	{ 0x6ff0, 0x00 },
> +	{ 0x6ff1, 0x75 },
> +	{ 0x6ff2, 0x00 },
> +	{ 0x6ff3, 0x75 },
> +	{ 0x6ff4, 0x00 },
> +	{ 0x6ff5, 0x75 },
> +	{ 0x6ff6, 0x00 },
> +	{ 0x6ff7, 0x75 },
> +	{ 0x6ff8, 0x00 },
> +	{ 0x6ff9, 0x75 },
> +	{ 0x6ffa, 0x00 },
> +	{ 0x6ffb, 0x75 },
> +	{ 0x6ffc, 0x00 },
> +	{ 0x6ffd, 0x75 },
> +	{ 0x6ffe, 0x00 },
> +	{ 0x6fff, 0x75 },
> +	{ 0x7000, 0x00 },
> +	{ 0x7001, 0x75 },
> +	{ 0x7002, 0x00 },
> +	{ 0x7003, 0x75 },
> +	{ 0x7004, 0x00 },
> +	{ 0x7005, 0x75 },
> +	{ 0x7006, 0x00 },
> +	{ 0x7007, 0x75 },
> +	{ 0x7008, 0x00 },
> +	{ 0x7009, 0x75 },
> +	{ 0x700a, 0x00 },
> +	{ 0x700b, 0x75 },
> +	{ 0x700c, 0x00 },
> +	{ 0x700d, 0x75 },
> +	{ 0x700e, 0x00 },
> +	{ 0x700f, 0x75 },
> +	{ 0x7010, 0x00 },
> +	{ 0x7011, 0x75 },
> +	{ 0x7012, 0x00 },
> +	{ 0x7013, 0x75 },
> +	{ 0x7014, 0x00 },
> +	{ 0x7015, 0x75 },
> +	{ 0x7016, 0x00 },
> +	{ 0x7017, 0x75 },
> +	{ 0x7018, 0x00 },
> +	{ 0x7019, 0x75 },
> +	{ 0x701a, 0x00 },
> +	{ 0x701b, 0x75 },
> +	{ 0x701c, 0x00 },
> +	{ 0x701d, 0x75 },
> +	{ 0x701e, 0x00 },
> +	{ 0x701f, 0x75 },
> +	{ 0x7020, 0x00 },
> +	{ 0x7021, 0x75 },
> +	{ 0x7022, 0x00 },
> +	{ 0x7023, 0x75 },
> +	{ 0x7024, 0x00 },
> +	{ 0x7025, 0x75 },
> +	{ 0x7026, 0x00 },
> +	{ 0x7027, 0x75 },
> +	{ 0x7028, 0x00 },
> +	{ 0x7029, 0x75 },
> +	{ 0x702a, 0x00 },
> +	{ 0x702b, 0x75 },
> +	{ 0x702c, 0x00 },
> +	{ 0x702d, 0x75 },
> +	{ 0x702e, 0x00 },
> +	{ 0x702f, 0x75 },
> +	{ 0x7030, 0x00 },
> +	{ 0x7031, 0x75 },
> +	{ 0x7032, 0x00 },
> +	{ 0x7033, 0x75 },
> +	{ 0x7034, 0x00 },
> +	{ 0x7035, 0x75 },
> +	{ 0x7036, 0x00 },
> +	{ 0x7037, 0x75 },
> +	{ 0x7038, 0x00 },
> +	{ 0x7039, 0x75 },
> +	{ 0x703a, 0x00 },
> +	{ 0x703b, 0x75 },
> +	{ 0x703c, 0x00 },
> +	{ 0x703d, 0x75 },
> +	{ 0x703e, 0x00 },
> +	{ 0x703f, 0x75 },
> +	{ 0x7040, 0x00 },
> +	{ 0x7041, 0x75 },
> +	{ 0x7042, 0x00 },
> +	{ 0x7043, 0x75 },
> +	{ 0x7044, 0x00 },
> +	{ 0x7045, 0x75 },
> +	{ 0x7046, 0x00 },
> +	{ 0x7047, 0x75 },
> +	{ 0x7048, 0x00 },
> +	{ 0x7049, 0x75 },
> +	{ 0x704a, 0x00 },
> +	{ 0x704b, 0x75 },
> +	{ 0x704c, 0x00 },
> +	{ 0x704d, 0x75 },
> +	{ 0x704e, 0x00 },
> +	{ 0x704f, 0x75 },
> +	{ 0x7050, 0x00 },
> +	{ 0x7051, 0x75 },
> +	{ 0x7052, 0x00 },
> +	{ 0x7053, 0x75 },
> +	{ 0x7054, 0x00 },
> +	{ 0x7055, 0x75 },
> +	{ 0x7056, 0x00 },
> +	{ 0x7057, 0x75 },
> +	{ 0x7058, 0x00 },
> +	{ 0x7059, 0x75 },
> +	{ 0x705a, 0x00 },
> +	{ 0x705b, 0x75 },
> +	{ 0x705c, 0x00 },
> +	{ 0x705d, 0x75 },
> +	{ 0x705e, 0x00 },
> +	{ 0x705f, 0x75 },
> +	{ 0x7060, 0x00 },
> +	{ 0x7061, 0x75 },
> +	{ 0x7062, 0x00 },
> +	{ 0x7063, 0x75 },
> +	{ 0x7064, 0x00 },
> +	{ 0x7065, 0x75 },
> +	{ 0x7066, 0x00 },
> +	{ 0x7067, 0x75 },
> +	{ 0x7068, 0x00 },
> +	{ 0x7069, 0x75 },
> +	{ 0x706a, 0x00 },
> +	{ 0x706b, 0x75 },
> +	{ 0x706c, 0x00 },
> +	{ 0x706d, 0x75 },
> +	{ 0x706e, 0x00 },
> +	{ 0x706f, 0x75 },
> +	{ 0x7070, 0x00 },
> +	{ 0x7071, 0x75 },
> +	{ 0x7072, 0x00 },
> +	{ 0x7073, 0x75 },
> +	{ 0x7074, 0x00 },
> +	{ 0x7075, 0x75 },
> +	{ 0x7076, 0x00 },
> +	{ 0x7077, 0x75 },
> +	{ 0x7078, 0x00 },
> +	{ 0x7079, 0x75 },
> +	{ 0x707a, 0x00 },
> +	{ 0x707b, 0x75 },
> +	{ 0x707c, 0x00 },
> +	{ 0x707d, 0x75 },
> +	{ 0x707e, 0x00 },
> +	{ 0x707f, 0x75 },
> +	{ 0x70e4, 0x02 },
> +	{ 0x70e6, 0x06 },
> +	{ 0x70e7, 0x08 },
> +	{ 0x70e8, 0x0a },
> +	{ 0x70e9, 0x0c },
> +	{ 0x70ea, 0x10 },
> +	{ 0x70eb, 0x16 },
> +	{ 0x70ec, 0x1a },
> +	{ 0x70ed, 0x20 },
> +	{ 0x70ee, 0x04 },
> +	{ 0x70ef, 0x06 },
> +	{ 0x70f0, 0x08 },
> +	{ 0x70f1, 0x0a },
> +	{ 0x70f2, 0x10 },
> +	{ 0x70f3, 0x16 },
> +	{ 0x70f4, 0x1a },
> +	{ 0x70f5, 0x20 },
> +	{ 0x7119, 0x16 },
> +	{ 0x711b, 0x1a },
> +	{ 0x713a, 0x19 },
> +	{ 0x713b, 0x17 },
> +	{ 0x713c, 0x15 },
> +	{ 0x713d, 0x13 },
> +	{ 0x713e, 0x11 },
> +	{ 0x713f, 0x11 },
> +	{ 0x7140, 0x11 },
> +	{ 0x7141, 0x11 },
> +	{ 0x7142, 0x12 },
> +	{ 0x7143, 0x0d },
> +	{ 0x7144, 0x0b },
> +	{ 0x7145, 0x0b },
> +	{ 0x7146, 0x09 },
> +	{ 0x7147, 0x09 },
> +	{ 0x7148, 0x09 },
> +	{ 0x7149, 0x08 },
> +	{ 0x7150, 0x00 },
> +};
> +
> +static const s64 link_freq_menu_items[] = {
> +	OV32C4_LINK_FREQ_400MHZ,
> +};
> +
> +static const struct ov32c4_mode supported_modes[] = {
> +	{
> +		.width = 3264,
> +		.height = 1840,
> +		.ppl = 4080,
> +		.vts_min = 2614,
> +		.reg_sequence = ov32c4_mode_3264x1840_regs,
> +		.sequence_length = ARRAY_SIZE(ov32c4_mode_3264x1840_regs),
> +	},
> +};
> +
> +struct ov32c4 {
> +	struct device *dev;
> +
> +	struct v4l2_subdev sd;
> +	struct media_pad pad;
> +	struct v4l2_ctrl_handler ctrl_handler;
> +	struct regmap *regmap;
> +
> +	/* The sensor's second I2C address, see OV32C4_COMPANION_ENABLE_REG */
> +	struct regmap *companion;
> +	u16 companion_addr;
> +
> +	/* V4L2 controls */
> +	struct v4l2_ctrl *link_freq;
> +	struct v4l2_ctrl *pixel_rate;
> +	struct v4l2_ctrl *vblank;
> +	struct v4l2_ctrl *hblank;
> +	struct v4l2_ctrl *exposure;
> +
> +	struct clk *img_clk;
> +	struct gpio_desc *reset;
> +	struct regulator_bulk_data supplies[ARRAY_SIZE(ov32c4_supply_names)];
> +
> +	u32 link_freq_index;
> +	u8 mipi_lanes;
> +};
> +
> +#ifdef CONFIG_ACPI
> +/*
> + * Walk the sensor's ACPI _CRS and return the address of the n-th
> + * I2cSerialBus resource. Index 0 is the sensor itself (the kernel binds the
> + * i2c client to it), index 1 is the companion, index 2 the module EEPROM.
> + */
> +struct ov32c4_i2c_res_ctx {
> +	int index;
> +	int want;
> +	u16 addr;
> +};
> +
> +static int ov32c4_i2c_res_cb(struct acpi_resource *ares, void *data)
> +{
> +	struct ov32c4_i2c_res_ctx *ctx = data;
> +	struct acpi_resource_i2c_serialbus *sb;
> +
> +	if (i2c_acpi_get_i2c_resource(ares, &sb)) {
> +		if (ctx->index == ctx->want)
> +			ctx->addr = sb->slave_address;
> +		ctx->index++;
> +	}
> +
> +	return 1;
> +}
> +
> +static u16 ov32c4_acpi_i2c_addr(struct device *dev, int index)
> +{
> +	struct ov32c4_i2c_res_ctx ctx = { .want = index };
> +	struct acpi_device *adev = ACPI_COMPANION(dev);
> +	LIST_HEAD(resources);
> +	int ret;
> +
> +	if (!adev)
> +		return 0;
> +
> +	ret = acpi_dev_get_resources(adev, &resources, ov32c4_i2c_res_cb, &ctx);

The presence of additional chips like VCM is very much dependent on the
module, and I think we should have parsing of the I²C address outside the
sensor driver.

One option could be to stuff it into the reg property in the ipu-bridge,
that way it'd work the same way for the driver on both DT and ACPI. In the
ipu-bridge, I'd use a static value and provide the reg property for this
sensor only (based on _HID). i2c_new_ancillary_device() will only use OF so
the driver will need to dig the address manually still.

Better ideas are welcome of course.

> +	acpi_dev_free_resource_list(&resources);
> +
> +	return ret < 0 ? 0 : ctx.addr;
> +}
> +#else
> +static u16 ov32c4_acpi_i2c_addr(struct device *dev, int index)
> +{
> +	return 0;
> +}
> +#endif
> +
> +static inline struct ov32c4 *to_ov32c4(struct v4l2_subdev *subdev)
> +{
> +	return container_of(subdev, struct ov32c4, sd);
> +}
> +
> +/* MIPI D-PHY is DDR -> link frequency * 2 */
> +static u64 ov32c4_pixel_rate(struct ov32c4 *ov32c4)
> +{
> +	return div_u64(link_freq_menu_items[ov32c4->link_freq_index] *
> +		       2 * ov32c4->mipi_lanes, OV32C4_RGB_DEPTH);
> +}
> +
> +static int ov32c4_set_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct ov32c4 *ov32c4 = container_of(ctrl->handler,
> +					     struct ov32c4, ctrl_handler);
> +	const u32 height = supported_modes[0].height;
> +	s64 exposure_max;
> +	int ret = 0;
> +	int pm;
> +
> +	if (ctrl->id == V4L2_CID_VBLANK) {
> +		exposure_max = height + ctrl->val - OV32C4_EXPOSURE_MAX_MARGIN;
> +		ret = __v4l2_ctrl_modify_range(ov32c4->exposure,
> +					       ov32c4->exposure->minimum,
> +					       exposure_max,
> +					       ov32c4->exposure->step,
> +					       exposure_max);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	/*
> +	 * A negative return means runtime PM is disabled for the device, in
> +	 * which case it is powered and the registers can be written, but no
> +	 * reference was taken and none may be dropped below.
> +	 */
> +	pm = pm_runtime_get_if_active(ov32c4->dev);
> +	if (!pm)
> +		return 0;
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_ANALOGUE_GAIN:
> +		cci_write(ov32c4->regmap, OV32C4_REG_ANALOG_GAIN,
> +			  ctrl->val, &ret);
> +		cci_write(ov32c4->regmap, OV32C4_REG_ANALOG_GAIN_CTX2,
> +			  ctrl->val, &ret);
> +		break;
> +
> +	case V4L2_CID_EXPOSURE:
> +		cci_write(ov32c4->regmap, OV32C4_REG_EXPOSURE,
> +			  ctrl->val, &ret);
> +		cci_write(ov32c4->regmap, OV32C4_REG_EXPOSURE_CTX2,
> +			  ctrl->val, &ret);
> +		break;
> +
> +	case V4L2_CID_VBLANK:
> +		cci_write(ov32c4->regmap, OV32C4_REG_VTS, height + ctrl->val,
> +			  &ret);
> +		break;
> +
> +	case V4L2_CID_DIGITAL_GAIN:
> +		cci_write(ov32c4->regmap, OV32C4_REG_DIGITAL_GAIN,
> +			  (u64)ctrl->val << OV32C4_DGAIN_SHIFT, &ret);
> +		cci_write(ov32c4->regmap, OV32C4_REG_DIGITAL_GAIN_CTX2,
> +			  (u64)ctrl->val << OV32C4_DGAIN_SHIFT, &ret);
> +		break;
> +
> +	case V4L2_CID_HFLIP:
> +		cci_update_bits(ov32c4->regmap, OV32C4_REG_MIRROR,
> +				OV32C4_FLIP_BIT,
> +				ctrl->val ? 0 : OV32C4_FLIP_BIT, &ret);
> +		break;
> +
> +	case V4L2_CID_VFLIP:
> +		cci_update_bits(ov32c4->regmap, OV32C4_REG_FLIP,
> +				OV32C4_FLIP_BIT,
> +				ctrl->val ? OV32C4_FLIP_BIT : 0, &ret);
> +		break;
> +
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	if (pm > 0)
> +		pm_runtime_put(ov32c4->dev);
> +
> +	return ret;
> +}
> +
> +static const struct v4l2_ctrl_ops ov32c4_ctrl_ops = {
> +	.s_ctrl = ov32c4_set_ctrl,
> +};
> +
> +static int ov32c4_init_controls(struct ov32c4 *ov32c4)
> +{
> +	struct v4l2_ctrl_handler *ctrl_hdlr = &ov32c4->ctrl_handler;
> +	const struct ov32c4_mode *mode = &supported_modes[0];
> +	u32 vblank_min, vblank_max, vblank_default;
> +	struct v4l2_fwnode_device_properties props;
> +	s64 exposure_max, h_blank, pixel_rate;
> +	int ret;
> +
> +	ret = v4l2_fwnode_device_parse(ov32c4->dev, &props);
> +	if (ret)
> +		return ret;
> +
> +	v4l2_ctrl_handler_init(ctrl_hdlr, 13);
> +
> +	ov32c4->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov32c4_ctrl_ops,
> +						   V4L2_CID_LINK_FREQ,
> +						   ARRAY_SIZE(link_freq_menu_items) - 1,
> +						   ov32c4->link_freq_index,
> +						   link_freq_menu_items);
> +
> +	pixel_rate = ov32c4_pixel_rate(ov32c4);
> +	ov32c4->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops,
> +					       V4L2_CID_PIXEL_RATE, 0,
> +					       pixel_rate, 1, pixel_rate);
> +
> +	vblank_min = mode->vts_min - mode->height;
> +	vblank_max = OV32C4_VTS_MAX - mode->height;
> +	vblank_default = vblank_min;
> +	ov32c4->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops,
> +					   V4L2_CID_VBLANK, vblank_min,
> +					   vblank_max, 1, vblank_default);
> +
> +	h_blank = mode->ppl - mode->width;
> +	ov32c4->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops,
> +					   V4L2_CID_HBLANK, h_blank, h_blank,
> +					   1, h_blank);
> +
> +	v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
> +			  OV32C4_ANA_GAIN_MIN, OV32C4_ANA_GAIN_MAX,
> +			  OV32C4_ANA_GAIN_STEP, OV32C4_ANA_GAIN_DEFAULT);
> +
> +	exposure_max = mode->vts_min - OV32C4_EXPOSURE_MAX_MARGIN;
> +	ov32c4->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops,
> +					     V4L2_CID_EXPOSURE,
> +					     OV32C4_EXPOSURE_MIN, exposure_max,
> +					     OV32C4_EXPOSURE_STEP,
> +					     exposure_max);
> +
> +	v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
> +			  OV32C4_DGAIN_MIN, OV32C4_DGAIN_MAX,
> +			  OV32C4_DGAIN_STEP, OV32C4_DGAIN_DEFAULT);
> +
> +	v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops, V4L2_CID_HFLIP,
> +			  0, 1, 1, 0);
> +	v4l2_ctrl_new_std(ctrl_hdlr, &ov32c4_ctrl_ops, V4L2_CID_VFLIP,
> +			  0, 1, 1, 0);
> +
> +	v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov32c4_ctrl_ops, &props);
> +
> +	if (ctrl_hdlr->error)
> +		return ctrl_hdlr->error;
> +
> +	ov32c4->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +	ov32c4->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +
> +	ov32c4->sd.ctrl_handler = ctrl_hdlr;
> +
> +	return 0;
> +}
> +
> +static void ov32c4_update_pad_format(const struct ov32c4_mode *mode,

I'd call this e.g. ov32c4_format_from_mode().

> +				     struct v4l2_mbus_framefmt *fmt)
> +{
> +	fmt->width = mode->width;
> +	fmt->height = mode->height;
> +	fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
> +	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 ov32c4_enable_streams(struct v4l2_subdev *sd,
> +				 struct v4l2_subdev_state *state,
> +				 u32 pad, u64 streams_mask)
> +{
> +	const struct ov32c4_mode *mode = &supported_modes[0];
> +	struct ov32c4 *ov32c4 = to_ov32c4(sd);
> +	int ret;
> +
> +	ret = pm_runtime_resume_and_get(ov32c4->dev);
> +	if (ret)
> +		return ret;
> +
> +	cci_write(ov32c4->regmap, OV32C4_REG_STREAM_CONTROL, 0, &ret);
> +	cci_write(ov32c4->regmap, OV32C4_REG_SW_RESET, 1, &ret);
> +	if (ret) {
> +		dev_err(ov32c4->dev, "failed to reset the sensor: %d\n", ret);
> +		goto out;
> +	}
> +	fsleep(OV32C4_SW_RESET_SETTLE_US);
> +
> +	ret = regmap_multi_reg_write(ov32c4->regmap, mode->reg_sequence,
> +				     mode->sequence_length);
> +	if (ret) {
> +		dev_err(ov32c4->dev, "failed to set mode: %d\n", ret);
> +		goto out;
> +	}
> +
> +	ret = __v4l2_ctrl_handler_setup(ov32c4->sd.ctrl_handler);
> +	if (ret)
> +		goto out;
> +
> +	ret = cci_write(ov32c4->regmap, OV32C4_REG_STREAM_CONTROL, 1, NULL);

A newline here?

> +out:
> +	if (ret)
> +		pm_runtime_put(ov32c4->dev);
> +
> +	return ret;
> +}
> +
> +static int ov32c4_disable_streams(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *state,
> +				  u32 pad, u64 streams_mask)
> +{
> +	struct ov32c4 *ov32c4 = to_ov32c4(sd);
> +	int ret;
> +
> +	ret = cci_write(ov32c4->regmap, OV32C4_REG_STREAM_CONTROL, 0, NULL);
> +	pm_runtime_put(ov32c4->dev);
> +
> +	return ret;
> +}
> +
> +static int ov32c4_get_pm_resources(struct device *dev)
> +{
> +	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> +	struct ov32c4 *ov32c4 = to_ov32c4(sd);
> +
> +	/* The reset pin is active low, so a logical 1 means "held in reset". */
> +	ov32c4->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
> +	if (IS_ERR(ov32c4->reset))
> +		return dev_err_probe(dev, PTR_ERR(ov32c4->reset),
> +				     "failed to get reset gpio\n");
> +
> +	for (unsigned int i = 0; i < ARRAY_SIZE(ov32c4_supply_names); i++)
> +		ov32c4->supplies[i].supply = ov32c4_supply_names[i];
> +
> +	return devm_regulator_bulk_get(dev, ARRAY_SIZE(ov32c4_supply_names),
> +				       ov32c4->supplies);
> +}
> +
> +/* Ungate the main address, see OV32C4_COMPANION_ENABLE_REG. */
> +static int ov32c4_companion_enable(struct ov32c4 *ov32c4)
> +{
> +	return cci_write(ov32c4->companion, OV32C4_COMPANION_ENABLE_REG,
> +			 OV32C4_COMPANION_ENABLE_VAL, NULL);
> +}
> +
> +static int ov32c4_power_off(struct device *dev)
> +{
> +	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> +	struct ov32c4 *ov32c4 = to_ov32c4(sd);
> +
> +	gpiod_set_value_cansleep(ov32c4->reset, 1);
> +	regulator_bulk_disable(ARRAY_SIZE(ov32c4_supply_names),
> +			       ov32c4->supplies);
> +	clk_disable_unprepare(ov32c4->img_clk);
> +
> +	return 0;
> +}
> +
> +static int ov32c4_power_on(struct device *dev)
> +{
> +	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> +	struct ov32c4 *ov32c4 = to_ov32c4(sd);
> +	int ret;
> +
> +	ret = clk_prepare_enable(ov32c4->img_clk);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to enable imaging clock: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = regulator_bulk_enable(ARRAY_SIZE(ov32c4_supply_names),
> +				    ov32c4->supplies);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to enable regulators: %d\n", ret);
> +		clk_disable_unprepare(ov32c4->img_clk);

This calls for a new label below.

> +		return ret;
> +	}
> +
> +	if (ov32c4->reset) {
> +		gpiod_set_value_cansleep(ov32c4->reset, 0);
> +		fsleep(OV32C4_RESET_SETTLE_US);
> +	}
> +
> +	if (ov32c4->companion) {
> +		ret = ov32c4_companion_enable(ov32c4);
> +		if (ret) {
> +			dev_err(dev, "the block at 0x%02x did not accept the enable write: %d\n",
> +				ov32c4->companion_addr, ret);
> +			goto err_power_off;
> +		}
> +		fsleep(OV32C4_ENABLE_SETTLE_US);
> +	}
> +
> +	return 0;
> +
> +err_power_off:
> +	if (ov32c4->reset)
> +		gpiod_set_value_cansleep(ov32c4->reset, 1);
> +	regulator_bulk_disable(ARRAY_SIZE(ov32c4_supply_names),
> +			       ov32c4->supplies);
> +	clk_disable_unprepare(ov32c4->img_clk);
> +
> +	return ret;
> +}
> +
> +static int ov32c4_set_format(struct v4l2_subdev *sd,
> +			     struct v4l2_subdev_state *sd_state,
> +			     struct v4l2_subdev_format *fmt)
> +{
> +	const struct ov32c4_mode *mode = &supported_modes[0];
> +	struct ov32c4 *ov32c4 = to_ov32c4(sd);
> +	s32 vblank_def, h_blank;
> +	int ret;
> +
> +	ov32c4_update_pad_format(mode, &fmt->format);
> +	*v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
> +
> +	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
> +		return 0;
> +
> +	vblank_def = mode->vts_min - mode->height;
> +	ret = __v4l2_ctrl_modify_range(ov32c4->vblank, vblank_def,
> +				       OV32C4_VTS_MAX - mode->height, 1,
> +				       vblank_def);
> +	if (ret)
> +		return ret;
> +
> +	ret = __v4l2_ctrl_s_ctrl(ov32c4->vblank, vblank_def);
> +	if (ret)
> +		return ret;
> +
> +	h_blank = mode->ppl - mode->width;
> +
> +	return __v4l2_ctrl_modify_range(ov32c4->hblank, h_blank, h_blank, 1,
> +					h_blank);
> +}
> +
> +static int ov32c4_enum_mbus_code(struct v4l2_subdev *sd,
> +				 struct v4l2_subdev_state *sd_state,
> +				 struct v4l2_subdev_mbus_code_enum *code)
> +{
> +	if (code->index > 0)
> +		return -EINVAL;
> +
> +	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
> +
> +	return 0;
> +}
> +
> +static int ov32c4_enum_frame_size(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *sd_state,
> +				  struct v4l2_subdev_frame_size_enum *fse)
> +{
> +	if (fse->index >= ARRAY_SIZE(supported_modes))
> +		return -EINVAL;
> +
> +	if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
> +		return -EINVAL;
> +
> +	fse->min_width = supported_modes[fse->index].width;
> +	fse->max_width = fse->min_width;
> +	fse->min_height = supported_modes[fse->index].height;
> +	fse->max_height = fse->min_height;
> +
> +	return 0;
> +}
> +
> +static int ov32c4_init_state(struct v4l2_subdev *sd,
> +			     struct v4l2_subdev_state *sd_state)
> +{
> +	ov32c4_update_pad_format(&supported_modes[0],
> +				 v4l2_subdev_state_get_format(sd_state, 0));
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_subdev_video_ops ov32c4_video_ops = {
> +	.s_stream = v4l2_subdev_s_stream_helper,
> +};
> +
> +static int ov32c4_get_selection(struct v4l2_subdev *sd,
> +				struct v4l2_subdev_state *state,
> +				struct v4l2_subdev_selection *sel)
> +{
> +	if (sel->pad != 0)
> +		return -EINVAL;
> +
> +	switch (sel->target) {
> +	case V4L2_SEL_TGT_CROP:
> +		sel->r.left = OV32C4_CROP_LEFT;
> +		sel->r.top = OV32C4_CROP_TOP;
> +		sel->r.width = OV32C4_CROP_WIDTH;
> +		sel->r.height = OV32C4_CROP_HEIGHT;
> +		return 0;
> +	case V4L2_SEL_TGT_NATIVE_SIZE:
> +		sel->r.left = 0;
> +		sel->r.top = 0;
> +		sel->r.width = OV32C4_NATIVE_WIDTH;
> +		sel->r.height = OV32C4_NATIVE_HEIGHT;
> +		return 0;
> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +		sel->r.left = OV32C4_ACTIVE_LEFT;
> +		sel->r.top = OV32C4_ACTIVE_TOP;
> +		sel->r.width = OV32C4_ACTIVE_WIDTH;
> +		sel->r.height = OV32C4_ACTIVE_HEIGHT;
> +		return 0;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct v4l2_subdev_pad_ops ov32c4_pad_ops = {
> +	.set_fmt = ov32c4_set_format,
> +	.get_fmt = v4l2_subdev_get_fmt,
> +	.get_selection = ov32c4_get_selection,
> +	.enum_mbus_code = ov32c4_enum_mbus_code,
> +	.enum_frame_size = ov32c4_enum_frame_size,
> +	.enable_streams = ov32c4_enable_streams,
> +	.disable_streams = ov32c4_disable_streams,
> +};
> +
> +static const struct v4l2_subdev_ops ov32c4_subdev_ops = {
> +	.video = &ov32c4_video_ops,
> +	.pad = &ov32c4_pad_ops,
> +};
> +
> +static const struct media_entity_operations ov32c4_subdev_entity_ops = {
> +	.link_validate = v4l2_subdev_link_validate,
> +};
> +
> +static const struct v4l2_subdev_internal_ops ov32c4_internal_ops = {
> +	.init_state = ov32c4_init_state,
> +};
> +
> +static int ov32c4_identify_module(struct ov32c4 *ov32c4)
> +{
> +	u64 chip_id;
> +	int ret;
> +
> +	ret = cci_read(ov32c4->regmap, OV32C4_REG_CHIP_ID, &chip_id, NULL);
> +	if (ret)
> +		return dev_err_probe(ov32c4->dev, ret,
> +				     "failed to read the chip id\n");
> +
> +	if (chip_id != OV32C4_CHIP_ID)
> +		return dev_err_probe(ov32c4->dev, -ENXIO,
> +				     "chip id mismatch: %x != %llx\n",
> +				     OV32C4_CHIP_ID, chip_id);
> +
> +	return 0;
> +}
> +
> +static int ov32c4_check_hwcfg(struct ov32c4 *ov32c4)
> +{
> +	struct v4l2_fwnode_endpoint bus_cfg = {
> +		.bus_type = V4L2_MBUS_CSI2_DPHY
> +	};
> +	struct device *dev = ov32c4->dev;
> +	struct fwnode_handle *ep, *fwnode = dev_fwnode(dev);
> +	unsigned long link_freq_bitmap;
> +	int ret;
> +
> +	ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
> +
> +	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
> +	fwnode_handle_put(ep);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "parsing endpoint failed\n");
> +
> +	ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,
> +				       bus_cfg.nr_of_link_frequencies,
> +				       link_freq_menu_items,
> +				       ARRAY_SIZE(link_freq_menu_items),
> +				       &link_freq_bitmap);
> +	if (ret)
> +		goto check_hwcfg_error;
> +
> +	/* v4l2_link_freq_to_bitmap() guarantees at least one bit is set */
> +	ov32c4->link_freq_index = ffs(link_freq_bitmap) - 1;
> +
> +	if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV32C4_DATA_LANES) {
> +		ret = dev_err_probe(dev, -EINVAL,
> +				    "number of CSI2 data lanes %u is not supported\n",
> +				    bus_cfg.bus.mipi_csi2.num_data_lanes);
> +		goto check_hwcfg_error;
> +	}
> +
> +	ov32c4->mipi_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
> +
> +check_hwcfg_error:
> +	v4l2_fwnode_endpoint_free(&bus_cfg);
> +	return ret;
> +}
> +
> +static void ov32c4_remove(struct i2c_client *client)
> +{
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct ov32c4 *ov32c4 = to_ov32c4(sd);
> +
> +	v4l2_async_unregister_subdev(sd);
> +	v4l2_subdev_cleanup(sd);
> +	media_entity_cleanup(&sd->entity);
> +	v4l2_ctrl_handler_free(sd->ctrl_handler);
> +	pm_runtime_disable(ov32c4->dev);
> +	if (!pm_runtime_status_suspended(ov32c4->dev)) {
> +		ov32c4_power_off(ov32c4->dev);
> +		pm_runtime_set_suspended(ov32c4->dev);
> +	}
> +}
> +
> +static int ov32c4_probe(struct i2c_client *client)
> +{
> +	struct ov32c4 *ov32c4;
> +	unsigned long freq;
> +	int ret;
> +
> +	ov32c4 = devm_kzalloc(&client->dev, sizeof(*ov32c4), GFP_KERNEL);
> +	if (!ov32c4)
> +		return -ENOMEM;
> +
> +	ov32c4->dev = &client->dev;
> +
> +	ov32c4->img_clk = devm_v4l2_sensor_clk_get(ov32c4->dev, NULL);
> +	if (IS_ERR(ov32c4->img_clk))
> +		return dev_err_probe(ov32c4->dev, PTR_ERR(ov32c4->img_clk),
> +				     "failed to get imaging clock\n");
> +
> +	freq = clk_get_rate(ov32c4->img_clk);
> +	if (freq != OV32C4_MCLK)
> +		return dev_err_probe(ov32c4->dev, -EINVAL,
> +				     "external clock %lu is not supported\n",
> +				     freq);
> +
> +	v4l2_i2c_subdev_init(&ov32c4->sd, client, &ov32c4_subdev_ops);
> +
> +	ret = ov32c4_check_hwcfg(ov32c4);
> +	if (ret)
> +		return ret;
> +
> +	ret = ov32c4_get_pm_resources(ov32c4->dev);
> +	if (ret)
> +		return ret;
> +
> +	ov32c4->regmap = devm_cci_regmap_init_i2c(client, 16);
> +	if (IS_ERR(ov32c4->regmap))
> +		return PTR_ERR(ov32c4->regmap);
> +
> +	/*
> +	 * On the ACPI machines this sensor ships in, the main address only
> +	 * answers after a write to the sensor's second address, listed as the
> +	 * second I2C resource of _CRS (see OV32C4_COMPANION_ENABLE_REG). The
> +	 * address is claimed here so that nothing else binds to it; the
> +	 * platform's SSDB wrongly calls it a VCM, and ipu-bridge knows not to
> +	 * instantiate one for this sensor.
> +	 */

I think you can assume it's always there, and not related to ACPI.

> +	ov32c4->companion_addr = ov32c4_acpi_i2c_addr(ov32c4->dev, 1);
> +	if (ov32c4->companion_addr) {
> +		struct i2c_client *companion;
> +
> +		companion = devm_i2c_new_dummy_device(ov32c4->dev,
> +						      client->adapter,
> +						      ov32c4->companion_addr);
> +		if (IS_ERR(companion))
> +			return dev_err_probe(ov32c4->dev, PTR_ERR(companion),
> +					     "failed to claim the second address 0x%02x\n",
> +					     ov32c4->companion_addr);
> +
> +		ov32c4->companion = devm_cci_regmap_init_i2c(companion, 16);
> +		if (IS_ERR(ov32c4->companion))
> +			return PTR_ERR(ov32c4->companion);
> +	} else if (ACPI_COMPANION(ov32c4->dev)) {
> +		dev_warn(ov32c4->dev,
> +			 "no second I2C address in _CRS, the sensor may not answer\n");
> +	}
> +
> +	ret = ov32c4_power_on(ov32c4->dev);
> +	if (ret) {
> +		dev_err_probe(ov32c4->dev, ret, "failed to power on\n");
> +		return ret;
> +	}
> +
> +	ret = ov32c4_identify_module(ov32c4);
> +	if (ret)
> +		goto probe_error_power_off;
> +
> +	ret = ov32c4_init_controls(ov32c4);
> +	if (ret) {
> +		dev_err_probe(ov32c4->dev, ret, "failed to init controls\n");
> +		goto probe_error_v4l2_ctrl_handler_free;
> +	}
> +
> +	ov32c4->sd.internal_ops = &ov32c4_internal_ops;
> +	ov32c4->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +	ov32c4->sd.entity.ops = &ov32c4_subdev_entity_ops;
> +	ov32c4->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
> +	ov32c4->pad.flags = MEDIA_PAD_FL_SOURCE;
> +	ret = media_entity_pads_init(&ov32c4->sd.entity, 1, &ov32c4->pad);
> +	if (ret) {
> +		dev_err_probe(ov32c4->dev, ret, "failed to init entity pads\n");
> +		goto probe_error_v4l2_ctrl_handler_free;
> +	}
> +
> +	ov32c4->sd.state_lock = ov32c4->ctrl_handler.lock;
> +	ret = v4l2_subdev_init_finalize(&ov32c4->sd);
> +	if (ret < 0) {
> +		dev_err_probe(ov32c4->dev, ret, "failed to init subdev\n");
> +		goto probe_error_media_entity_cleanup;
> +	}
> +
> +	pm_runtime_set_active(ov32c4->dev);
> +	pm_runtime_enable(ov32c4->dev);
> +
> +	ret = v4l2_async_register_subdev_sensor(&ov32c4->sd);
> +	if (ret < 0) {
> +		dev_err_probe(ov32c4->dev, ret, "failed to register subdev\n");
> +		goto probe_error_v4l2_subdev_cleanup;
> +	}
> +
> +	pm_runtime_idle(ov32c4->dev);
> +
> +	return 0;
> +
> +probe_error_v4l2_subdev_cleanup:
> +	pm_runtime_disable(ov32c4->dev);
> +	pm_runtime_set_suspended(ov32c4->dev);
> +	v4l2_subdev_cleanup(&ov32c4->sd);
> +
> +probe_error_media_entity_cleanup:
> +	media_entity_cleanup(&ov32c4->sd.entity);
> +
> +probe_error_v4l2_ctrl_handler_free:
> +	v4l2_ctrl_handler_free(&ov32c4->ctrl_handler);
> +
> +probe_error_power_off:
> +	ov32c4_power_off(ov32c4->dev);
> +
> +	return ret;
> +}
> +
> +static DEFINE_RUNTIME_DEV_PM_OPS(ov32c4_pm_ops, ov32c4_power_off,
> +				 ov32c4_power_on, NULL);
> +
> +#ifdef CONFIG_ACPI
> +static const struct acpi_device_id ov32c4_acpi_ids[] = {
> +	{ "OVTI32C4" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(acpi, ov32c4_acpi_ids);
> +#endif
> +
> +static const struct of_device_id ov32c4_of_match[] = {
> +	{ .compatible = "ovti,ov32c4" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, ov32c4_of_match);
> +
> +static struct i2c_driver ov32c4_i2c_driver = {
> +	.driver = {
> +		.name = "ov32c4",
> +		.pm = pm_ptr(&ov32c4_pm_ops),
> +		.acpi_match_table = ACPI_PTR(ov32c4_acpi_ids),
> +		.of_match_table = ov32c4_of_match,
> +	},
> +	.probe = ov32c4_probe,
> +	.remove = ov32c4_remove,
> +};
> +module_i2c_driver(ov32c4_i2c_driver);
> +
> +MODULE_DESCRIPTION("OmniVision OV32C4 sensor driver");
> +MODULE_LICENSE("GPL");

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 2/3] media: i2c: Add driver for OmniVision OV32C4
  2026-10-05  9:23   ` Sakari Ailus
@ 2026-10-05 10:14     ` Robert Bozik
  2026-10-05 10:36       ` Sakari Ailus
  0 siblings, 1 reply; 13+ messages in thread
From: Robert Bozik @ 2026-10-05 10:14 UTC (permalink / raw)
  To: sakari.ailus
  Cc: linux-media, mchehab, robh, krzk+dt, conor+dt, devicetree,
	linux-kernel, antti.laakso

Hi Sakari,

Thank you for the review.

On Mon, Oct 05, 2026 at 12:23:20PM +0300, Sakari Ailus wrote:
> > +	{ 0x6ad0, 0x00 },
> > +	{ 0x6ad1, 0x75 },
> 
> Are there any gaps in this deluge of 0x0 and 0x75? If not, could you write
> it programmatically rather than using a huge array?

Two contiguous ranges, 0x6ad0-0x6bef and 0x6c00-0x707f, with one gap of
16 bytes between them; every even address holds 0x00 and the odd one
0x75, so it is 720 16-bit registers set to 0x0075. v5 writes them from a
loop and the table shrinks to 345 entries. I'll verify the stream and
the image after the change, since it alters the bus transactions.

> > +	ret = acpi_dev_get_resources(adev, &resources, ov32c4_i2c_res_cb, &ctx);
> 
> The presence of additional chips like VCM is very much dependent on the
> module, and I think we should have parsing of the I²C address outside the
> sensor driver.
> 
> One option could be to stuff it into the reg property in the ipu-bridge,
> that way it'd work the same way for the driver on both DT and ACPI. In the
> ipu-bridge, I'd use a static value and provide the reg property for this
> sensor only (based on _HID). i2c_new_ancillary_device() will only use OF so
> the driver will need to dig the address manually still.

Agreed, that is better. For v5 I'd give ipu-bridge a small table of
sensors whose second I2C address belongs to the sensor itself,
{ "OVTI32C4", 0x3e }; for a sensor in it the bridge adds reg = <main,
aon> to the sensor's software node and does not instantiate the VCM
from SSDB - so the no-VCM exception of patch 3 folds into the same
table. The driver reads reg with device_property_read_u32_array() on
both DT and ACPI and the _CRS walk goes away with its CONFIG_ACPI
guard. The property fits into the existing dev_properties slot that
lens-focus uses when there is a VCM, so no change to the header.

The rest will be in v5 as suggested - the register names, the RGB/IR
comments, the function name, the error label and the comments; the HTS
define was unused and goes too.

Thanks,
Robert

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 2/3] media: i2c: Add driver for OmniVision OV32C4
  2026-10-05 10:14     ` Robert Bozik
@ 2026-10-05 10:36       ` Sakari Ailus
  2026-10-05 10:46         ` Robert Bozik
  0 siblings, 1 reply; 13+ messages in thread
From: Sakari Ailus @ 2026-10-05 10:36 UTC (permalink / raw)
  To: Robert Bozik
  Cc: linux-media, mchehab, robh, krzk+dt, conor+dt, devicetree,
	linux-kernel, antti.laakso

Hi Robert,

On Mon, Oct 05, 2026 at 12:14:46PM +0200, Robert Bozik wrote:
> Hi Sakari,
> 
> Thank you for the review.
> 
> On Mon, Oct 05, 2026 at 12:23:20PM +0300, Sakari Ailus wrote:
> > > +	{ 0x6ad0, 0x00 },
> > > +	{ 0x6ad1, 0x75 },
> > 
> > Are there any gaps in this deluge of 0x0 and 0x75? If not, could you write
> > it programmatically rather than using a huge array?
> 
> Two contiguous ranges, 0x6ad0-0x6bef and 0x6c00-0x707f, with one gap of
> 16 bytes between them; every even address holds 0x00 and the odd one
> 0x75, so it is 720 16-bit registers set to 0x0075. v5 writes them from a
> loop and the table shrinks to 345 entries. I'll verify the stream and
> the image after the change, since it alters the bus transactions.
> 
> > > +	ret = acpi_dev_get_resources(adev, &resources, ov32c4_i2c_res_cb, &ctx);
> > 
> > The presence of additional chips like VCM is very much dependent on the
> > module, and I think we should have parsing of the I²C address outside the
> > sensor driver.
> > 
> > One option could be to stuff it into the reg property in the ipu-bridge,
> > that way it'd work the same way for the driver on both DT and ACPI. In the
> > ipu-bridge, I'd use a static value and provide the reg property for this
> > sensor only (based on _HID). i2c_new_ancillary_device() will only use OF so
> > the driver will need to dig the address manually still.
> 
> Agreed, that is better. For v5 I'd give ipu-bridge a small table of
> sensors whose second I2C address belongs to the sensor itself,
> { "OVTI32C4", 0x3e }; for a sensor in it the bridge adds reg = <main,
> aon> to the sensor's software node and does not instantiate the VCM
> from SSDB - so the no-VCM exception of patch 3 folds into the same
> table. The driver reads reg with device_property_read_u32_array() on
> both DT and ACPI and the _CRS walk goes away with its CONFIG_ACPI
> guard. The property fits into the existing dev_properties slot that
> lens-focus uses when there is a VCM, so no change to the header.

You shouldn't assume there won't be a VCM; please do add an array entry for
reg instead.

> 
> The rest will be in v5 as suggested - the register names, the RGB/IR
> comments, the function name, the error label and the comments; the HTS
> define was unused and goes too.

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 2/3] media: i2c: Add driver for OmniVision OV32C4
  2026-10-05 10:36       ` Sakari Ailus
@ 2026-10-05 10:46         ` Robert Bozik
  0 siblings, 0 replies; 13+ messages in thread
From: Robert Bozik @ 2026-10-05 10:46 UTC (permalink / raw)
  To: sakari.ailus
  Cc: linux-media, mchehab, robh, krzk+dt, conor+dt, devicetree,
	linux-kernel, antti.laakso

Hi Sakari,

On Mon, Oct 05, 2026 at 01:36:00PM +0300, Sakari Ailus wrote:
> > Agreed, that is better. For v5 I'd give ipu-bridge a small table of
> > sensors whose second I2C address belongs to the sensor itself,
> > { "OVTI32C4", 0x3e }; for a sensor in it the bridge adds reg = <main,
> > aon> to the sensor's software node and does not instantiate the VCM
> > from SSDB - so the no-VCM exception of patch 3 folds into the same
> > table. The driver reads reg with device_property_read_u32_array() on
> > both DT and ACPI and the _CRS walk goes away with its CONFIG_ACPI
> > guard. The property fits into the existing dev_properties slot that
> > lens-focus uses when there is a VCM, so no change to the header.
> 
> You shouldn't assume there won't be a VCM; please do add an array entry for
> reg instead.

OK - a separate entry for reg, independent of the VCM.

For the VCM I won't assume either way then. The bridge instantiates it
from the second I2C resource of _CRS, so v5 skips it only when that
resource's address is the sensor's AON address from the table, as it
is on this machine; a module with a real VCM there is handled as
before.

Thanks,
Robert

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4
  2026-10-05  8:11   ` Sakari Ailus
  2026-10-05  8:36     ` Robert Bozik
@ 2026-10-05 11:02     ` Conor Dooley
  2026-10-05 12:01       ` Robert Bozik
  1 sibling, 1 reply; 13+ messages in thread
From: Conor Dooley @ 2026-10-05 11:02 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Robert Bozik, linux-media, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel,
	Conor Dooley

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

On Mon, Oct 05, 2026 at 11:11:46AM +0300, Sakari Ailus wrote:
> Hi Robert,
> 
> On Mon, Oct 05, 2026 at 09:10:08AM +0200, Robert Bozik wrote:
> > Add a binding for the OmniVision OV32C4, a 32 megapixel RGBC CMOS image
> > sensor with on-chip 4-cell fusion, a 4-lane MIPI CSI-2 D-PHY transmitter
> > and the standard SCCB command interface.
> > 
> > The sensor ships in laptops as an under-display camera, where it is
> > described by ACPI; the binding follows ovti,ov08x40.yaml, which covers
> > the closest relative already in tree.
> > 
> > Acked-by: Conor Dooley <conor.dooley@microchip.com>
> > Signed-off-by: Robert Bozik <robertbozik@gmail.com>
> > ---
> > Changes in v4:
> > - No changes to the binding.
> > 
> >  .../bindings/media/i2c/ovti,ov32c4.yaml       | 105 ++++++++++++++++++
> >  1 file changed, 105 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
> > new file mode 100644
> > index 000000000..804307cd0
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov32c4.yaml
> > @@ -0,0 +1,105 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/media/i2c/ovti,ov32c4.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: OmniVision OV32C4 Image Sensor
> > +
> > +maintainers:
> > +  - Robert Bozik <robertbozik@gmail.com>
> > +
> > +description:
> > +  The OmniVision OV32C4 is a 32 megapixel RGBC (red, green, blue and clear)
> > +  CMOS image sensor in a 4-cell arrangement, with on-chip 4-cell fusion and
> > +  binning. It has a 6528x4896 active pixel array, a 4-lane MIPI CSI-2 D-PHY
> > +  transmitter and the standard SCCB command interface.
> > +
> > +allOf:
> > +  - $ref: /schemas/media/video-interface-devices.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    const: ovti,ov32c4
> > +
> > +  reg:
> > +    maxItems: 1
> 
> minItems should be 2 here, for the always-on client.

Instead, make it an items list, so that what each item is is explained.

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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4
  2026-10-05 11:02     ` Conor Dooley
@ 2026-10-05 12:01       ` Robert Bozik
  0 siblings, 0 replies; 13+ messages in thread
From: Robert Bozik @ 2026-10-05 12:01 UTC (permalink / raw)
  To: conor
  Cc: sakari.ailus, linux-media, mchehab, robh, krzk+dt, conor+dt,
	conor.dooley, devicetree, linux-kernel

Hi Conor,

On Mon, Oct 05, 2026 at 12:02:32PM +0100, Conor Dooley wrote:
> On Mon, Oct 05, 2026 at 11:11:46AM +0300, Sakari Ailus wrote:
> > > +  reg:
> > > +    maxItems: 1
> > 
> > minItems should be 2 here, for the always-on client.
> 
> Instead, make it an items list, so that what each item is is explained.

Will do - two items with a description each, the sensor and the
always-on block.

Thanks,
Robert

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-10-05 12:01 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-05  7:10 [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver Robert Bozik
2026-10-05  7:10 ` [PATCH v4 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4 Robert Bozik
2026-10-05  8:11   ` Sakari Ailus
2026-10-05  8:36     ` Robert Bozik
2026-10-05 11:02     ` Conor Dooley
2026-10-05 12:01       ` Robert Bozik
2026-10-05  7:10 ` [PATCH v4 2/3] media: i2c: Add driver for " Robert Bozik
2026-10-05  9:23   ` Sakari Ailus
2026-10-05 10:14     ` Robert Bozik
2026-10-05 10:36       ` Sakari Ailus
2026-10-05 10:46         ` Robert Bozik
2026-10-05  7:10 ` [PATCH v4 3/3] media: ipu-bridge: Add " Robert Bozik
2026-10-05  8:04 ` [PATCH v4 0/3] media: Add OmniVision OV32C4 sensor driver Sakari Ailus

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

all inboxes | Powered by JetHome®