From: Sakari Ailus <sakari.ailus@linux.intel.com>
To: Robert Bozik <robertbozik@gmail.com>
Cc: linux-media@vger.kernel.org,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v4 2/3] media: i2c: Add driver for OmniVision OV32C4
Date: Mon, 5 Oct 2026 12:23:20 +0300 [thread overview]
Message-ID: <asNsiKal6GgcqUSK@kekkonen.localdomain> (raw)
In-Reply-To: <20261005071010.7191-3-robertbozik@gmail.com>
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
next prev parent reply other threads:[~2026-10-05 9:23 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=asNsiKal6GgcqUSK@kekkonen.localdomain \
--to=sakari.ailus@linux.intel.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=robertbozik@gmail.com \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®