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