mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/3] media: Add OmniVision OV32C4 sensor driver
@ 2026-08-29 11:58 Robert Bozik
  2026-08-29 11:58 ` [PATCH v3 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4 Robert Bozik
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Robert Bozik @ 2026-08-29 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, mchehab, robh, krzk+dt, conor+dt, devicetree,
	linux-kernel, Robert Bozik

Hi,

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

Changes in v3 are Sakari's review of v1, carried out in full; the
per-patch changelogs have the detail. The three that are more than
mechanical:

 - The line length. OV32C4_SCLK and the scaling function are gone; the
   mode carries .ppl directly, in pixels in the units of PIXEL_RATE, as
   you said it should be. The numbers come out identical, checked
   against the controls before and after: hblank 816, vblank 774,
   exposure max 2582, pixel rate 320000000.

 - The chip id retries are dropped. Measured over 31 power-ups of the
   sensor - one cold boot and 30 unbind/bind cycles - the first read
   answered every time, so the power-up sequence is sufficient on its
   own.

 - .get_frame_desc() is dropped, and the argument I made for it in v1
   does not hold. I re-measured it properly this time: the same scene,
   60 frames, with the op and without it. Both give 10 "Received packet
   is too long" errors and an identical picture. The receiver reports
   that extra long packet either way; the op never suppressed it, and I
   had attributed to it something it does not do.

One measurement I would rather report than sit on, on dropping the
endpoint check. On the 7.0 kernel this machine runs,
v4l2_fwnode_endpoint_alloc_parse() returns -EINVAL rather than
-EPROBE_DEFER when the endpoint is not there yet, and the probe is then
not retried, so the sensor does not bind at boot when it loses the race
with ipu-bridge - which it does on roughly half the boots here. The
deferring path with the comment naming the IPU bridge is in
media_stage. So the check is redundant against the tree this is merged
into, which is why it is gone, and I mention the older behaviour only as
data.

The companion chip, which was the first of the two questions in v2: it
is not a VCM, and my guess that it might be one with an integrated LDO
was wrong. Measured, with the sensor powered and the VCM driver unbound:

    w2@0x3e 0x10 0x01  r1@0x3e   ->  0x04     (what we write, read back)
    w2@0x3e 0x10 0x00  r8@0x3e   ->  00 04 00 00 00 00 00 00
    w2@0x3e 0x10 0x00 r32@0x3e   ->  a sparse block at 0x1010-0x1018
    w2@0x3e 0x00 0x00 r32@0x3e   ->  all zeroes

It has a 16-bit addressed register file and it remembers writes, so it
is not a dw9714, which is a write-only DAC with no register addressing
at all. Where the name comes from is ipu-bridge: it takes vcmtype
straight out of the ACPI SSDB and indexes ipu_vcm_types[] with it
without checking anything, and dw9714 has no id register, so its driver
binds unconditionally. The chip has no ACPI device of its own - the
subdev ends up with 0 pads and 0 links - and I found no id register in
it, so I cannot name it. The vendor Windows driver issues the same write
from its sensor driver and has no separate driver for it either.

So the position is unchanged but better founded: the write has to happen
or the sensor does not answer on I2C, and there is no handle for the
chip in the device model other than that mis-named VCM client. I still
agree it does not belong in a sensor driver. What I do not know is the
shape you want, since a regulator would mean a driver for a chip nobody
can name, and something would first have to stop ipu-bridge from
claiming the address as a VCM. Guidance welcome; I am happy to do the
work.

Still open from your review: the power-up timings. "These are 0 and 5
ms, respectively" - I did not follow, and the question stands. The
values in the patch are 5 ms after the supply and 20 ms after reset,
arrived at during bring-up; there is no datasheet.

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
last patch adds the sensor to ipu-bridge; without it the bridge builds
no fwnode graph for the sensor and the driver never binds.

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 the machine above: the sensor probes, streams continuously at
a measured 30.00 fps, and the frames arrive complete (60 frames =
720691200 bytes = 60 * 3264 * 1840 * 2). The full path up to a processed
image was exercised with libcamera's software ISP.

There is no public datasheet for this sensor, so a note on where the
numbers come from. The comments that carried this in v2 are gone from
the code, as you asked, so it is here:

  - The mode register table is the verbatim initialisation sequence from
    the vendor Windows driver: 1787 writes, strictly ascending, copied
    1:1 with nothing added or reordered.
  - The register meanings the controls depend on (exposure 0x3500,
    analogue gain 0x3508, digital gain 0x350a, VTS 0x380e, and the rule
    exposure_max = VTS - 32) were read out of the same binary and then
    confirmed against the values the chip reports.
  - The derived timings were checked against reality: the computed
    320000000 / (4080 * 2614) = 30.005 fps matches the measured 30.00.
  - The 6560x4928 pixel array and the 6528x4896 active area reported by
    .get_selection follow from the window registers of the mode table
    and agree with the vendor's published product brief.
  - The gain ranges were measured on the sensor, not inherited. The
    vendor driver clamps gain a layer above and carries no limits of its
    own, and the obvious donor - ov13b10, same registers - puts analogue
    unity at 0x80, which is wrong here. Analogue response is exactly
    proportional between 0x100 and 0x7c0 (1x to 7.75x, 0x100 also being
    the power-up value); digital gain is proportional with 1024 as unity
    and clips to black one step above 16383.
  - Flip handling was measured the same way. This sensor preserves the
    Bayer order across mirror and flip, so the driver only toggles the
    bits and the media bus code never changes. ov13b10 compensates the
    crop window by one pixel on the same registers to undo a Bayer
    shift; doing that here introduces one rather than removing it.

Tooling disclosure, as asked for by Documentation/process/generated-content.rst:
this series was written with the help of an AI coding assistant (Claude,
Anthropic; claude-opus-5 for the early work, claude-fable-5 for the rest)
in an extended interactive session. The assistant drafted the driver
source, the binding and this cover letter from my descriptions of the
hardware and of the vendor driver; every register meaning, gain range and
timing in it was measured by me on the sensor as described above, I ran
all of the tests, and I have reviewed and understand all of the code and
take responsibility for it. The mode register table was copied 1:1 from
the vendor driver, not generated. Static checks used: checkpatch.pl
--strict, sparse (C=1), W=1 and dt_binding_check. The individual patches
carry Assisted-by tags.

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                    | 2664 +++++++++++++++++
 drivers/media/pci/intel/ipu-bridge.c          |    2 +
 6 files changed, 2790 insertions(+)
 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] 4+ messages in thread

* [PATCH v3 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4
  2026-08-29 11:58 [PATCH v3 0/3] media: Add OmniVision OV32C4 sensor driver Robert Bozik
@ 2026-08-29 11:58 ` Robert Bozik
  2026-08-29 11:58 ` [PATCH v3 2/3] media: i2c: Add driver for " Robert Bozik
  2026-08-29 11:58 ` [PATCH v3 3/3] media: ipu-bridge: Add " Robert Bozik
  2 siblings, 0 replies; 4+ messages in thread
From: Robert Bozik @ 2026-08-29 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, mchehab, robh, krzk+dt, conor+dt, devicetree,
	linux-kernel, Robert Bozik

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.

Assisted-by: Claude:claude-opus-5 sparse
Assisted-by: Claude:claude-fable-5 sparse
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Robert Bozik <robertbozik@gmail.com>
---
Changes in v3:
- No changes to the binding itself; picked up Conor Dooley's Acked-by.

 .../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] 4+ messages in thread

* [PATCH v3 2/3] media: i2c: Add driver for OmniVision OV32C4
  2026-08-29 11:58 [PATCH v3 0/3] media: Add OmniVision OV32C4 sensor driver Robert Bozik
  2026-08-29 11:58 ` [PATCH v3 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4 Robert Bozik
@ 2026-08-29 11:58 ` Robert Bozik
  2026-08-29 11:58 ` [PATCH v3 3/3] media: ipu-bridge: Add " Robert Bozik
  2 siblings, 0 replies; 4+ messages in thread
From: Robert Bozik @ 2026-08-29 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, mchehab, robh, krzk+dt, conor+dt, 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.

There is no public datasheet for this sensor. The mode register table is
the verbatim initialisation sequence from the vendor driver, 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.

Assisted-by: Claude:claude-opus-5 sparse
Assisted-by: Claude:claude-fable-5 sparse
Signed-off-by: Robert Bozik <robertbozik@gmail.com>
---
Changes in v3, all from Sakari Ailus' review of v1:
- Commit message and the provenance comments in the file cut down; what
  was measured is in the cover letter instead.
- Kconfig: dropped "depends on ACPI || COMPILE_TEST".
- OV32C4_SCLK and ov32c4_ppl() are gone. The line length is carried by
  the mode as .ppl, in pixels in the units of the PIXEL_RATE control,
  and OV32C4_REG_HTS names the register that holds the same line in the
  sensor's own clock units. The values are unchanged: ppl 4080,
  hblank 816, pixel_rate 320000000.
- Dropped the chip id read retries. Measured over 31 power-ups of the
  sensor - one cold boot and 30 unbind/bind cycles, each cutting the
  supply and the reset - the first read answered every time.
- Dropped .get_frame_desc(). Re-measured with and without it on the same
  scene: 10 "Received packet is too long" errors per 60 frames either
  way, and the image is unaffected. The justification given in v1 was
  wrong; see the cover letter.
- Dropped the endpoint check in check_hwcfg().
- pm_runtime_get_if_active() instead of pm_runtime_get_if_in_use().
- Control flags set after the handler error check, and the two "if the
  control exists" conditions around them dropped.
- v4l2_fwnode_device_parse() moved ahead of the controls; return values
  of __v4l2_ctrl_modify_range() and of the write in .disable_streams()
  are checked.
- MIPI_CSI2_DT_RAW10 from <media/mipi-csi2.h> (with .get_frame_desc()
  gone, the include went with it), unsigned int for the loop variable,
  debug prints and redundant comments removed.

 MAINTAINERS                |    8 +
 drivers/media/i2c/Kconfig  |   10 +
 drivers/media/i2c/Makefile |    1 +
 drivers/media/i2c/ov32c4.c | 2664 ++++++++++++++++++++++++++++++++++++
 4 files changed, 2683 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..cfeeafcfb
--- /dev/null
+++ b/drivers/media/i2c/ov32c4.c
@@ -0,0 +1,2664 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OmniVision OV32C4 image sensor driver.
+ *
+ * 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)
+
+/*
+ * The sensor does not answer on I2C at all until this register is written in
+ * a companion chip, which the ACPI _CRS of the sensor lists as its second
+ * I2cSerialBus resource. The write is issued as a plain i2c_transfer and the
+ * address is deliberately not claimed with i2c_new_dummy_device(), so that
+ * the driver the platform assigns to that address can still bind.
+ */
+#define OV32C4_COMPANION_ENABLE_REG	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 timings; there is no public datasheet for this sensor. */
+#define OV32C4_AVDD_SETTLE_US		5000
+#define OV32C4_RESET_SETTLE_US		20000
+
+/*
+ * Mode 3264x1840 @ 30 fps, 4 lanes, SGRBG10. The 15 fps variant of the same
+ * table differs only in VTS, which V4L2_CID_VBLANK covers.
+ */
+static const struct reg_sequence ov32c4_mode_3264x1840_regs[] = {
+	{ 0x0100, 0x00 },
+	{ 0x0103, 0x01, 10000 },	/* sw reset + settle */
+	{ 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;
+
+	/* Companion chip that gates the sensor, see OV32C4_COMPANION_ENABLE_REG */
+	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;
+};
+
+/*
+ * 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;
+}
+
+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;
+
+	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;
+	}
+
+	if (!pm_runtime_get_if_active(ov32c4->dev))
+		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;
+	}
+
+	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;
+}
+
+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;
+
+	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 sensor through the companion chip, see
+ * OV32C4_COMPANION_ENABLE_REG.
+ */
+static int ov32c4_companion_enable(struct ov32c4 *ov32c4)
+{
+	struct i2c_client *client = to_i2c_client(ov32c4->dev);
+	u8 wr[3] = {
+		OV32C4_COMPANION_ENABLE_REG >> 8,
+		OV32C4_COMPANION_ENABLE_REG & 0xff,
+		OV32C4_COMPANION_ENABLE_VAL,
+	};
+	struct i2c_msg msg = {
+		.addr = ov32c4->companion_addr,
+		.flags = 0,
+		.len = sizeof(wr),
+		.buf = wr,
+	};
+	int ret;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret == 1)
+		return 0;
+
+	return ret < 0 ? ret : -EIO;
+}
+
+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;
+	}
+
+	fsleep(OV32C4_AVDD_SETTLE_US);
+
+	if (ov32c4->reset) {
+		gpiod_set_value_cansleep(ov32c4->reset, 0);
+		fsleep(OV32C4_RESET_SETTLE_US);
+	}
+
+	if (ov32c4->companion_addr) {
+		ret = ov32c4_companion_enable(ov32c4);
+		if (ret)
+			dev_err(dev, "companion at 0x%02x did not accept the enable write: %d\n",
+				ov32c4->companion_addr, ret);
+		fsleep(1000);
+	}
+
+	return 0;
+}
+
+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 core rail is gated by
+	 * a companion chip listed as the second I2C resource of _CRS; without
+	 * it the sensor does not answer at all. Elsewhere the rail is expected
+	 * to come from a regulator, so its absence is not an error here.
+	 */
+	ov32c4->companion_addr = ov32c4_acpi_i2c_addr(ov32c4->dev, 1);
+	if (!ov32c4->companion_addr && ACPI_COMPANION(ov32c4->dev))
+		dev_warn(ov32c4->dev,
+			 "no second I2C address in _CRS, core rail may stay off\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] 4+ messages in thread

* [PATCH v3 3/3] media: ipu-bridge: Add OmniVision OV32C4
  2026-08-29 11:58 [PATCH v3 0/3] media: Add OmniVision OV32C4 sensor driver Robert Bozik
  2026-08-29 11:58 ` [PATCH v3 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4 Robert Bozik
  2026-08-29 11:58 ` [PATCH v3 2/3] media: i2c: Add driver for " Robert Bozik
@ 2026-08-29 11:58 ` Robert Bozik
  2 siblings, 0 replies; 4+ messages in thread
From: Robert Bozik @ 2026-08-29 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, mchehab, robh, krzk+dt, conor+dt, 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.

Assisted-by: Claude:claude-opus-5 sparse
Assisted-by: Claude:claude-fable-5 sparse
Signed-off-by: Robert Bozik <robertbozik@gmail.com>
---
Changes in v3:
- Comment above the entry cut down to the sensor name; where the link
  frequency comes from is documented in the driver instead.

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

diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
index 1bb3a3e98..385400a58 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 */
-- 
2.53.0


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

end of thread, other threads:[~2026-08-29 11:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-29 11:58 [PATCH v3 0/3] media: Add OmniVision OV32C4 sensor driver Robert Bozik
2026-08-29 11:58 ` [PATCH v3 1/3] dt-bindings: media: i2c: Add OmniVision OV32C4 Robert Bozik
2026-08-29 11:58 ` [PATCH v3 2/3] media: i2c: Add driver for " Robert Bozik
2026-08-29 11:58 ` [PATCH v3 3/3] media: ipu-bridge: Add " Robert Bozik

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®