From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=79.135.106.120 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794340531; b=ihBhj3Zjoo5IxummWm0CJuS0F50Gj6T65eoG9wtX4BrXRgUHvh8xero2/papwI14vv+9 Q+/j3cEiknycnVam49sH9ocTuUzn69pCSI8GRYU3sYmDVYviTO2n2yzfvxqloXMiTA719 dLxowCdHnVbyp4DyAYFOYDsGlASSOMMDuMudY/AwkJtXsKOlXFmnOErQ5xbfsg8IPXbR/ UyWDVLZYz5iPvPBTiTc6AiuyNmy3u2YRSqsbjIm09vnDnosBKA3TiDoHvPCLl1mo6vmBz g+wxccPGiiH7cK2cCUWqVJirom9oZ/DrNjhzCclqJi9cUEaea/OLF+mhCBidF0ZUfrg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794340531; h=DMARC-Filter:DKIM-Signature:Date:To:From:Cc:Subject:Message-ID: In-Reply-To:References:Feedback-ID:X-Pm-Message-ID:MIME-Version: Content-Type:Content-Transfer-Encoding; bh=G+fPteSNjGp3cDe/mz7flkBDpvGGZuLA/rPfw9VXkkQ=; b=zgpEuCaIxURZPsLy50pKH3tv3lbXz/6+ijun/0rknKLyAEJNUKnHuD6cyKfBT6vquocI aO6a6baZhSL95jRRmejiTBtHtsbsnbWCHEvWUnrJ+rkJRI1ihY3q37vzb9sJsizCCUChU 9Xft9j6mJynlBFMakESanUIkdZYm9iWiRJIjt8Dr2a4JZr6oRZDv+GZS8yLsR0FYV0sfv AVWo6/dH4oRsFhJdblqMaEZmaMj83jF0BOnrABikQV1z51OKhIrqcnnm9BmlOU8HyNX4L Io5Vk0Q2ClG3DmHXFEolJdm2dZ2efv06LvdKW28aFIrlP553C5DZdfMdDH92Q2tnyCw== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass header.d=pm.me header.i=@pm.me header.a=rsa-sha256 header.s=protonmail3 header.b=O9krid2L; arc=none smtp.remote-ip=79.135.106.120 Received: from mail-106120.protonmail.ch (mail-106120.protonmail.ch [79.135.106.120]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D410B606A323; Tue, 10 Nov 2026 19:55:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org D410B606A323 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.a=rsa-sha256 header.s=protonmail3 header.b=O9krid2L DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1794340524; x=1794599724; bh=G+fPteSNjGp3cDe/mz7flkBDpvGGZuLA/rPfw9VXkkQ=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=O9krid2LiOZ0bHYTy48jwKIN4QHUA9jxOBNaeO245fc7a0FwXsGcWTeR0LeaA/UPY B/DCk53i39TAS2p597tETbCZ8cfxMhO6XFHaKvtPQ1awi1DtfpMTa4cXzel3D1xlPV IsMAkcNdkGs3VJukqqEHcoODaZISZYZ5kmmlaKQdDJKQ0nXAo9b9oyAZBdgRjkbU8N jYuG4fK75V/RY2yMoYA6qftTQ7D+nBTE2m/YPC+l7zGrt7EQMalIa/fgqcyTR0pq0G grYrcvCocwhZeybNqwWgiqlNdqhntrr9tK4EVfsp6KGSjyR53bSBOlDbkgUYNKogu7 ZrzKNnflLsMXg== Date: Tue, 10 Nov 2026 19:55:20 +0000 To: Sakari Ailus , Benjamin Mugnier , Sylvain Petinot , Mauro Carvalho Chehab From: Sergey Lebedev Cc: Dan Scally , Hans de Goede , =?utf-8?Q?Ilpo_J=C3=A4rvinen?= , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Peter Marshall , George Neacsu , Hao Yao , Fernando Rimoli , "D. Manresa" , Jizhou Tong , linux-media@vger.kernel.org, platform-driver-x86@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 2/6] media: i2c: Add ST VD55G0 global shutter sensor driver Message-ID: <20261110195454.48176-3-lsa.uz@pm.me> In-Reply-To: <20261110195454.48176-1-lsa.uz@pm.me> References: <20261110195454.48176-1-lsa.uz@pm.me> Feedback-ID: 113843758:user:proton X-Pm-Message-ID: eed207f370f81181ae210e334aef54ef49820718 X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable The VD55G0 is a 644x604 monochrome global shutter sensor from STMicroelectronics. It streams Y8 or Y10 over one CSI-2 lane, runs its own auto exposure, can strobe an illuminator from its GPIOs, and needs a firmware patch at every power-on, carried in the driver as vd55g1 does. The driver is ported from ST's own, GPL-2.0, to current interfaces: CCI register access, .enable_streams with the subdev state, fwnode properties, devm_v4l2_sensor_clk_get(), and an ACPI match for x86 machines where the sensor sits behind ipu-bridge: https://github.com/STMicroelectronics/vd55g0-linux-driver ST's st,out-sync and st,in-sync and its two private controls are left out, as vd55g1 has none of them. The supplies keep their DT names on ACPI too, where int3472 maps them. The clock tree is computed from the input clock and the one link frequency the endpoint gives, as in vd55g1. The MIPI rate must be an integer multiple of the input clock, or the sensor would run at another one, so any other link frequency fails probe. Exposure and the two gains form an auto cluster with auto exposure, as in vd55g1: while auto exposure runs, they read back what the sensor applies. Co-developed-by: Benjamin Mugnier Signed-off-by: Benjamin Mugnier Signed-off-by: Sergey Lebedev --- v4: Sakari's review. The controls hold the settings, applied with __v4l2_ctrl_handler_setup() at stream start and written by s_ctrl only while powered; the subdev state holds the format and crop; media_entity_is_streaming() replaces the driver's flag; one supply list, which 3/6 maps on ACPI; and the smaller points. g_volatile_ctrl() still sets ->val, as discussed on v3. Also the handler's lock is the state lock, hflip and vflip form a cluster, AE_TARGET_PERCENTAGE is written as 16 bits, and LINE_LENGTH is written at stream start from the crop and HBLANK. pm_runtime_dont_use_autosuspend() is no longer called: the core does it since d1706f9da9f4, as Joshua Crofts's vd55g1 patch says. v3: Sashiko's three points on v2 (auto exposure readback after a stream, the runtime PM reference across probe, RUNTIME_PM_OPS() and pm_ptr()); registration through v4l2_async_register_subdev_sensor() (Jizhou Tong), with dev_err_probe() on failure. v2: no code change; MAINTAINERS no longer lists a binding for it. MAINTAINERS | 9 + drivers/media/i2c/Kconfig | 11 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/vd55g0.c | 2232 ++++++++++++++++++++++++++++++++++++ 4 files changed, 2253 insertions(+) create mode 100644 drivers/media/i2c/vd55g0.c diff --git a/MAINTAINERS b/MAINTAINERS index 93abbb31506..dbbc5b05954 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26592,6 +26592,14 @@ F:=09Documentation/devicetree/bindings/hwmon/st,ts= c1641.yaml F:=09Documentation/hwmon/tsc1641.rst F:=09drivers/hwmon/tsc1641.c =20 +ST VD55G0 DRIVER +M:=09Benjamin Mugnier +M:=09Sergey Lebedev +M:=09Sylvain Petinot +L:=09linux-media@vger.kernel.org +S:=09Maintained +F:=09drivers/media/i2c/vd55g0.c + ST VD55G1 DRIVER M:=09Benjamin Mugnier M:=09Sylvain Petinot @@ -29317,6 +29325,7 @@ F:=09drivers/media/i2c/mt* F:=09drivers/media/i2c/og* F:=09drivers/media/i2c/ov* F:=09drivers/media/i2c/s5* +F:=09drivers/media/i2c/vd55g0.c F:=09drivers/media/i2c/vd55g1.c F:=09drivers/media/i2c/vd56g3.c F:=09drivers/media/i2c/vgxy61.c diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 11c30252540..f8a653154de 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -891,6 +891,17 @@ config VIDEO_T4KA3 =09 To compile this driver as a module, choose M here: the =09 module will be called t4ka3. =20 +config VIDEO_VD55G0 +=09tristate "ST VD55G0 sensor support" +=09select V4L2_CCI_I2C +=09depends on GPIOLIB +=09help +=09 This is a Video4Linux2 sensor driver for the ST VD55G0 +=09 camera sensor. + +=09 To compile this driver as a module, choose M here: the +=09 module will be called vd55g0. + config VIDEO_VD55G1 =09tristate "ST VD55G1 sensor support" =09select V4L2_CCI_I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 59e31af457c..a7e990ec650 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -171,6 +171,7 @@ obj-$(CONFIG_VIDEO_TW9910) +=3D tw9910.o obj-$(CONFIG_VIDEO_UDA1342) +=3D uda1342.o obj-$(CONFIG_VIDEO_UPD64031A) +=3D upd64031a.o obj-$(CONFIG_VIDEO_UPD64083) +=3D upd64083.o +obj-$(CONFIG_VIDEO_VD55G0) +=3D vd55g0.o obj-$(CONFIG_VIDEO_VD55G1) +=3D vd55g1.o obj-$(CONFIG_VIDEO_VD56G3) +=3D vd56g3.o obj-$(CONFIG_VIDEO_VGXY61) +=3D vgxy61.o diff --git a/drivers/media/i2c/vd55g0.c b/drivers/media/i2c/vd55g0.c new file mode 100644 index 00000000000..99bfb05225d --- /dev/null +++ b/drivers/media/i2c/vd55g0.c @@ -0,0 +1,2232 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the ST VD55G0 global shutter sensor + * + * Copyright (C) 2026 STMicroelectronics SA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VD55G0_REG_MODEL_ID=09=09=09=09CCI_REG16_LE(0x0000) +#define VD55G0_MODEL_ID=09=09=09=09=090x4730 +#define VD55G0_REG_REVISION=09=09=09=09CCI_REG16_LE(0x0004) +#define VD55G0_REVISION_CUT1=09=09=09=090x1111 +#define VD55G0_REVISION_CUT2=09=09=09=090x1120 +#define VD55G0_REG_FWPATCH_REVISION=09=09=09CCI_REG16_LE(0x0022) +#define VD55G0_REG_FWPATCH_START_ADDR=09=09=09CCI_REG8(0x2000) +#define VD55G0_REG_SYSTEM_FSM=09=09=09=09CCI_REG8(0x002c) +#define VD55G0_SYSTEM_FSM_READY_TO_BOOT=09=09=090x01 +#define VD55G0_SYSTEM_FSM_SW_STBY=09=09=090x02 +#define VD55G0_SYSTEM_FSM_STREAMING=09=09=090x03 +#define VD55G0_REG_BOOT=09=09=09=09=09CCI_REG8(0x0200) +#define VD55G0_BOOT_BOOT=09=09=09=091 +#define VD55G0_BOOT_PATCH_SETUP=09=09=09=092 +#define VD55G0_REG_SW_STBY=09=09=09=09CCI_REG8(0x0201) +#define VD55G0_SW_STBY_START_STREAM=09=09=091 +#define VD55G0_REG_STREAMING=09=09=09=09CCI_REG8(0x0202) +#define VD55G0_STREAMING_STOP_STREAM=09=09=091 +#define VD55G0_REG_EXT_CLOCK=09=09=09=09CCI_REG32_LE(0x0220) +#define VD55G0_REG_LINE_LENGTH=09=09=09=09CCI_REG16_LE(0x0300) +#define VD55G0_REG_ORIENTATION=09=09=09=09CCI_REG8(0x0302) +#define VD55G0_REG_FORMAT_CTRL=09=09=09=09CCI_REG8(0x030a) +#define VD55G0_REG_OIF_CTRL=09=09=09=09CCI_REG16_LE(0x030c) +#define VD55G0_REG_OIF_IMG_CTRL=09=09=09=09CCI_REG8(0x030f) +#define VD55G0_REG_ISL_ENABLE=09=09=09=09CCI_REG8(0x0329) +#define VD55G0_REG_CLK_PLL_MIPI=09=09=09=09CCI_REG32_LE(0x0224) +#define VD55G0_REG_PATGEN_CTRL=09=09=09=09CCI_REG16_LE(0x0400) +#define VD55G0_PATGEN_TYPE_SHIFT=09=09=094 +#define VD55G0_PATGEN_ENABLE=09=09=09=09BIT(0) +#define VD55G0_REG_MANUAL_ANALOG_GAIN=09=09=09CCI_REG8(0x044d) +#define VD55G0_REG_MANUAL_COARSE_EXPOSURE=09=09CCI_REG16_LE(0x044e) +#define VD55G0_REG_MANUAL_DIGITAL_GAIN=09=09=09CCI_REG16_LE(0x0450) +#define VD55G0_REG_APPLIED_COARSE_EXPOSURE=09=09CCI_REG16_LE(0x0064) +#define VD55G0_REG_APPLIED_ANALOG_GAIN=09=09=09CCI_REG8(0x0066) +#define VD55G0_REG_APPLIED_DIGITAL_GAIN=09=09=09CCI_REG16_LE(0x0068) +#define VD55G0_REG_AE_COLDSTART_COARSE_EXPOSURE=09=09CCI_REG16_LE(0x042e) +#define VD55G0_REG_AE_COLDSTART_ANALOG_GAIN=09=09CCI_REG8(0x0430) +#define VD55G0_REG_AE_COLDSTART_DIGITAL_GAIN=09=09CCI_REG16_LE(0x0432) +#define VD55G0_REG_EXP_MODE=09=09=09=09CCI_REG8(0x044c) +#define VD55G0_REG_FRAME_LENGTH=09=09=09=09CCI_REG16_LE(0x0458) +#define VD55G0_REG_ROI_X_START=09=09=09=09CCI_REG16_LE(0x045e) +#define VD55G0_REG_ROI_X_END=09=09=09=09CCI_REG16_LE(0x0460) +#define VD55G0_REG_ROI_Y_START=09=09=09=09CCI_REG16_LE(0x0462) +#define VD55G0_REG_ROI_Y_END=09=09=09=09CCI_REG16_LE(0x0464) +#define VD55G0_REG_AE_ROI_START_H=09=09=09CCI_REG16_LE(0x0436) +#define VD55G0_REG_AE_ROI_START_V=09=09=09CCI_REG16_LE(0x0438) +#define VD55G0_REG_AE_ROI_END_H=09=09=09=09CCI_REG16_LE(0x043a) +#define VD55G0_REG_AE_ROI_END_V=09=09=09=09CCI_REG16_LE(0x043c) +#define VD55G0_REG_GPIO_0_CTRL=09=09=09=09CCI_REG8(0x0467) +#define VD55G0_REG_READOUT_CTRL=09=09=09=09CCI_REG8(0x047a) +#define VD55G0_REG_DARKCAL_CTRL=09=09=09=09CCI_REG8(0x032c) +#define VD55G0_DARKCAL_BYPASS=09=09=09=090 +#define VD55G0_DARKCAL_AUTO=09=09=09=091 +#define VD55G0_REG_DUSTER_CTRL=09=09=09=09CCI_REG8(0x0316) +#define VD55G0_DUSTER_ENABLE=09=09=09=09BIT(0) +#define VD55G0_DUSTER_DISABLE=09=09=09=090 +#define VD55G0_DUSTER_DYN_ENABLE=09=09=09BIT(1) +#define VD55G0_DUSTER_RING_ENABLE=09=09=09BIT(4) +#define VD55G0_REG_AE_TARGET_PERCENTAGE=09=09=09CCI_REG16_LE(0x0440) + +#define VD55G0_WIDTH=09=09=09=09=09644 +#define VD55G0_HEIGHT=09=09=09=09=09604 +#define VD55G0_DEFAULT_MODE=09=09=09=091 +#define VD55G0_WRITE_MULTIPLE_CHUNK_MAX=09=09=0916U +#define VD55G0_NB_GPIOS=09=09=09=09=094 +#define VD55G0_MIN_FRAME_LENGTH=09=09=09=09(605 + 76) +#define VD55G0_FRAME_LENGTH_DEF=09=09=09=091860 +#define VD55G0_TIMEOUT_MS=09=09=09=09500 +#define VD55G0_MEDIA_BUS_FMT_DEF=09=09=09MEDIA_BUS_FMT_Y8_1X8 +#define VD55G0_EXPO_MAX_TERM=09=09=09=0964 +#define VD55G0_EXPO_DEF=09=09=09=09=09200 +#define VD55G0_LINE_LENGTH_SLOW=09=09=09=091200 +#define VD55G0_LINE_LENGTH_FAST=09=09=09=091128 +#define VD55G0_XCLK_FREQ_MIN=09=09=09=09(6 * HZ_PER_MHZ) +#define VD55G0_XCLK_FREQ_MAX=09=09=09=09(27 * HZ_PER_MHZ) +#define VD55G0_MIPI_RATE_MIN=09=09=09=09(750 * MEGA) +#define VD55G0_MIPI_RATE_MAX=09=09=09=09(1200 * MEGA) +#define VD55G0_MIPI_RATE_FAST=09=09=09=09(900 * MEGA) + +static const u8 cut1_patch[] =3D { +=090x81, 0x06, 0x0b, 0x02, 0x00, 0x09, 0x42, 0x00, 0xd2, 0x08, 0x42, 0x00, +=090xe6, 0x08, 0x42, 0x00, 0x12, 0x09, 0x42, 0x00, 0xe0, 0x3f, 0x80, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +=090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40, 0x01, 0x60, +=090x10, 0x40, 0x11, 0x81, 0x16, 0x80, 0x93, 0xdd, 0x4c, 0x04, 0x04, 0xfa, +=090x06, 0x4c, 0x94, 0x60, 0xe6, 0x0e, 0xdc, 0xe0, 0x04, 0x18, 0x70, 0x02, +=090x08, 0xe7, 0xce, 0x44, 0x01, 0x60, 0x10, 0x40, 0x31, 0x85, 0x1e, 0x08, +=090x4e, 0x43, 0x01, 0x60, 0x10, 0xc0, 0x31, 0x40, 0x20, 0xe0, 0x04, 0x98, +=090x29, 0x00, 0x50, 0xeb, 0x2e, 0x84, 0x24, 0x84, 0x29, 0x86, 0x2e, 0x84, +=090x24, 0x84, 0x2b, 0xa1, 0x15, 0xfe, 0xd8, 0x41, 0x00, 0xe8, 0xf8, 0x47, +=090x00, 0xe8, 0x78, 0x44, 0x40, 0xef, 0x0a, 0x9c, 0x1a, 0x9e, 0x2a, 0xdc, +=090x3a, 0xde, 0x03, 0x4e, 0x7c, 0xf9, 0x13, 0x4e, 0x78, 0xf9, 0x23, 0x4e, +=090x74, 0xf9, 0x33, 0x4e, 0x70, 0xf9, 0x18, 0x50, 0x40, 0xef, 0x38, 0x49, +=090x44, 0xef, 0x04, 0x18, 0x11, 0x83, 0x11, 0x40, 0x20, 0xe0, 0x4c, 0x0c, +=090x04, 0xf2, 0x93, 0xdd, 0x86, 0x44, 0x88, 0xe0, 0x05, 0x04, 0x40, 0xf8, +=090x09, 0x00, 0x24, 0xe0, 0x4a, 0x40, 0x88, 0x60, 0x06, 0x40, 0x94, 0xe0, +=090x04, 0x80, 0x65, 0x86, 0x31, 0x01, 0x06, 0x02, 0x0c, 0xe1, 0x33, 0x40, +=090xc8, 0xe2, 0x33, 0x40, 0x70, 0xe2, 0x14, 0x84, 0x18, 0x48, 0x1b, 0xa3, +=090x55, 0x8a, 0x0a, 0x02, 0x08, 0x70, 0x16, 0x43, 0x58, 0xe0, 0x26, 0x08, +=090x00, 0x40, 0x16, 0x0a, 0x00, 0xc0, 0x41, 0x44, 0x08, 0x40, 0x06, 0x46, +=090x08, 0xe0, 0x51, 0x44, 0x04, 0xc0, 0x45, 0x85, 0x66, 0x02, 0x04, 0xe0, +=090x13, 0x40, 0x70, 0x62, 0x06, 0x02, 0x0c, 0xe1, 0x14, 0x84, 0x18, 0x48, +=090x1b, 0xa3, 0xb5, 0x86, 0x0a, 0x02, 0x08, 0x70, 0xa6, 0x02, 0x68, 0xe0, +=090x26, 0x0a, 0x00, 0x40, 0x16, 0x18, 0x00, 0xc0, 0x31, 0x01, 0xc6, 0x09, +=090x0c, 0xe0, 0x51, 0x44, 0x08, 0xc0, 0xc1, 0x44, 0x04, 0xc0, 0x95, 0x83, +=090x0a, 0x02, 0x04, 0xf0, 0x16, 0x02, 0x00, 0xc0, 0x11, 0x44, 0x08, 0xc0, +=090x11, 0x44, 0x04, 0x40, 0x11, 0x81, 0x33, 0x40, 0x18, 0xe3, 0x15, 0x83, +=090x0a, 0x02, 0x04, 0x70, 0x11, 0x81, 0x16, 0x0a, 0x00, 0x40, 0x31, 0x9d, +=090x51, 0x44, 0x08, 0x40, 0x06, 0x09, 0x04, 0xe0, 0x51, 0x44, 0x04, 0xc0, +=090x43, 0x40, 0x18, 0xe3, 0x33, 0x40, 0xc8, 0xe2, 0x13, 0x40, 0xc0, 0x62, +=090xa6, 0x05, 0x78, 0xe0, 0x23, 0x40, 0xd0, 0xe3, 0x93, 0xdd, 0xc3, 0xc1, +=090x4c, 0x04, 0x7c, 0xfa, 0x86, 0x42, 0x84, 0x60, 0x06, 0x00, 0x0c, 0xe1, +=090x14, 0x04, 0xf6, 0x50, 0x78, 0xe3, 0x04, 0x00, 0x26, 0x0f, 0x28, 0xe2, +=090x16, 0x15, 0x2c, 0x64, 0xb1, 0xbb, 0x6a, 0x84, 0x0b, 0xa3, 0x36, 0x10, +=090x10, 0x41, 0x2e, 0x54, 0x08, 0xd8, 0x16, 0x4f, 0x44, 0x43, 0x06, 0x16, +=090x00, 0xc0, 0x0b, 0x10, 0x1b, 0x8c, 0xb8, 0x4f, 0x00, 0x6f, 0xa4, 0x12, +=090x80, 0xfb, 0x06, 0x42, 0x1a, 0x60, 0x00, 0x40, 0xfc, 0x73, 0x03, 0xc0, +=090x83, 0x22, 0x0e, 0x02, 0xc1, 0x7f, 0x1f, 0xc0, 0x87, 0xd4, 0x8f, 0x02, +=090x1b, 0x8c, 0x8f, 0x20, 0x0b, 0x8e, 0x98, 0x4e, 0x00, 0xef, 0x06, 0x42, +=090x1a, 0x60, 0x00, 0x40, 0xfc, 0xf0, 0x73, 0xa2, 0x77, 0xcc, 0x70, 0x42, +=090x01, 0x73, 0xff, 0xc7, 0x12, 0x4e, 0x80, 0x79, 0x0b, 0x92, 0xb8, 0x4d, +=090x00, 0x6f, 0x1b, 0x8c, 0x06, 0x42, 0x94, 0x60, 0x06, 0x46, 0x1a, 0xe0, +=090x24, 0x04, 0x00, 0x40, 0xfd, 0x73, 0x03, 0xc0, 0xa3, 0xa6, 0xa7, 0xd4, +=090xb3, 0x44, 0x60, 0xe3, 0x85, 0x44, 0x9c, 0xe0, 0x24, 0x84, 0x75, 0x44, +=090xa0, 0x60, 0x0e, 0x04, 0xc0, 0x7f, 0x1f, 0xc0, 0x14, 0x04, 0xaf, 0x84, +=090xaf, 0xa0, 0xa5, 0x42, 0xa4, 0xe0, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, +=090x0c, 0x04, 0x0c, 0xfa, 0x46, 0x0d, 0xcc, 0xe0, 0x09, 0x0c, 0xbc, 0xee, +=090x0a, 0x40, 0x80, 0xe0, 0x45, 0x82, 0xa6, 0x40, 0x08, 0xe0, 0x06, 0x98, +=090x08, 0x7f, 0x74, 0xef, 0x0b, 0xa1, 0xb5, 0xfe, 0x01, 0x87, 0x06, 0x98, +=090x06, 0x4c, 0x94, 0x60, 0x06, 0x42, 0x0c, 0xe0, 0x05, 0x0c, 0x14, 0xe0, +=090x11, 0x40, 0x30, 0x62, 0x26, 0x42, 0x00, 0xe0, 0x05, 0x0c, 0x14, 0xe0, +=090x11, 0x40, 0xa0, 0x62, 0x56, 0x43, 0x04, 0xe0, 0x05, 0x0c, 0x14, 0xe0, +=090x11, 0x40, 0x40, 0x62, 0x76, 0x43, 0x04, 0xe0, 0x05, 0x0c, 0x14, 0xe0, +=090x11, 0x40, 0x50, 0xe2, 0x04, 0x98, 0x19, 0x00, 0x50, 0xeb, 0x4a, 0x42, +=090x88, 0xe0, 0xc5, 0x80, 0x28, 0x67, 0x54, 0x6f, 0x66, 0x00, 0xa0, 0xe0, +=090x04, 0x98, 0x19, 0x00, 0x30, 0xe0, 0x19, 0xc4, 0x11, 0x40, 0x30, 0x60, +=090x11, 0x83, 0x04, 0x9a, 0x11, 0x40, 0x10, 0xe0, 0x04, 0x98, 0x11, 0x40, +=090x20, 0x60, 0x11, 0x81, 0x04, 0x98, 0x11, 0x40, 0xb0, 0xe7, 0x19, 0x00, +=090x50, 0xeb, 0x4a, 0x02, 0x0c, 0xfc, 0x85, 0xfe, 0xc6, 0x4c, 0xb4, 0xe0, +=090x60, 0x10, 0xb1, 0x64, 0x01, 0xc0, 0x0a, 0xe0, 0x0b, 0xa1, 0x95, 0x8c, +=090x04, 0xe0, 0x0b, 0xa1, 0x25, 0x8c, 0xd8, 0x43, 0x5c, 0xef, 0x0a, 0xe0, +=090x0b, 0xa1, 0x95, 0x8a, 0x04, 0xe0, 0x0b, 0xa1, 0x25, 0x8a, 0xc6, 0x4e, +=090x84, 0xe0, 0x04, 0x9c, 0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, +=090x25, 0x86, 0x08, 0x22, 0x46, 0x43, 0x00, 0xe0, 0x06, 0x40, 0x06, 0xe0, +=090x63, 0x80, 0x09, 0x0c, 0x40, 0xe2, 0x09, 0x86, 0x0b, 0xa5, 0xd5, 0x82, +=090x68, 0x4e, 0x48, 0x6f, 0x01, 0x85, 0x78, 0x44, 0x48, 0x6f, 0x06, 0x00, +=090x80, 0xe1, 0xf8, 0x75, 0x4c, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0x78, 0x48, +=090x48, 0xef, 0x09, 0x0e, 0x48, 0xe0, 0x0b, 0xa1, 0xb5, 0x80, 0x58, 0x7b, +=090x3c, 0xef, 0x78, 0x74, 0x40, 0xef, 0xa6, 0x40, 0x08, 0xe0, 0x0c, 0x0c, +=090x0c, 0xf2, 0x18, 0x12, 0x50, 0xff, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, +=090x7b, 0x00, 0x06, 0x01, 0x08, 0xe1, 0x08, 0x00, 0x6b, 0x82, 0x0b, 0xa1, +=090x15, 0x82, 0xa6, 0x41, 0x84, 0xe0, 0x18, 0x00, 0x01, 0x89, 0x18, 0x42, +=090x00, 0xef, 0x63, 0x80, 0x04, 0x1c, 0x64, 0x02, 0x84, 0xe0, 0x78, 0x40, +=090x00, 0x68, 0x00, 0x00, 0x40, 0xe6, 0x4c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, +=090x1e, 0x80, 0x93, 0xdd, 0x0c, 0x04, 0x3c, 0xfa, 0xf0, 0x1e, 0x40, 0x6c, +=090x86, 0x0f, 0xe0, 0xe0, 0x01, 0x05, 0x91, 0x81, 0x06, 0x02, 0x00, 0x62, +=090x81, 0xb1, 0x01, 0x4e, 0xd8, 0x69, 0x0e, 0x00, 0x00, 0x60, 0x01, 0xc0, +=090x0e, 0x7c, 0x6b, 0x9e, 0x93, 0x4e, 0x14, 0x65, 0x86, 0x00, 0x30, 0xe1, +=090x93, 0x4e, 0x18, 0x65, 0x2b, 0x8c, 0x91, 0x4e, 0x50, 0xe1, 0x81, 0x4e, +=090xc8, 0xe9, 0x1e, 0xbe, 0x1e, 0x7e, 0x11, 0x8f, 0x9e, 0xbc, 0xd8, 0x55, +=090x30, 0xef, 0x06, 0x00, 0x00, 0x64, 0x46, 0x02, 0x54, 0xe1, 0x0e, 0x3e, +=090x06, 0x00, 0x20, 0xe0, 0x0e, 0x7e, 0x86, 0x00, 0x30, 0xe1, 0x1e, 0x7c, +=090x11, 0x91, 0x9e, 0x3c, 0x2b, 0x8c, 0xd8, 0x54, 0x30, 0xef, 0x06, 0x00, +=090x00, 0x66, 0xa1, 0x83, 0x0e, 0x3e, 0xf6, 0x41, 0xfc, 0xe9, 0x0e, 0x7e, +=090x06, 0x00, 0x01, 0x60, 0x20, 0xc0, 0x0e, 0x7c, 0x86, 0x00, 0x30, 0xe1, +=090xae, 0x3c, 0x11, 0x93, 0xc8, 0x53, 0x30, 0x6f, 0x2b, 0x8c, 0x06, 0x40, +=090x88, 0x60, 0xf6, 0x45, 0xfc, 0x63, 0xff, 0xc3, 0x14, 0x00, 0xf1, 0xa0, +=090x95, 0x4e, 0xa8, 0xe2, 0xa1, 0x4e, 0x44, 0xea, 0x81, 0x4e, 0xf0, 0x69, +=090x10, 0x42, 0x00, 0x7c, 0x00, 0xcc, 0x1f, 0x04, 0x21, 0x8b, 0x1e, 0x00, +=090x86, 0x40, 0xfc, 0xe7, 0x05, 0x4e, 0xa4, 0x62, 0xc6, 0x01, 0x5c, 0xe0, +=090x05, 0x4e, 0xac, 0x62, 0x9e, 0x00, 0x00, 0x60, 0x02, 0xc0, 0x05, 0x4e, +=090x94, 0x62, 0x86, 0x40, 0x3c, 0x60, 0x10, 0xe7, 0x0e, 0x9c, 0x09, 0x0e, +=090x0c, 0xe1, 0x15, 0x4e, 0x3c, 0x79, 0x06, 0x02, 0x80, 0xe0, 0x13, 0x4e, +=090xf4, 0x64, 0x86, 0x02, 0x00, 0x60, 0x02, 0xc0, 0x21, 0x4e, 0x5c, 0x69, +=090x00, 0x40, 0xc0, 0xf3, 0x1e, 0x9e, 0x01, 0x4e, 0x0c, 0xe1, 0x0c, 0x0c, +=090x3c, 0xf2, 0x93, 0xdd, 0xc6, 0x01, 0xcc, 0x60, 0x06, 0x42, 0x88, 0xe0, +=090x29, 0x00, 0x98, 0xee, 0x34, 0x84, 0x4a, 0x44, 0x80, 0x60, 0x86, 0x04, +=090x30, 0xe1, 0x24, 0x08, 0x30, 0x46, 0xfd, 0x73, 0xff, 0xc3, 0x3e, 0x04, +=090xa6, 0x08, 0xa0, 0x80, 0x34, 0x06, 0xc8, 0x9c, 0x45, 0x44, 0xa0, 0x80, +=090x35, 0x42, 0x00, 0x00, 0x06, 0x06, 0x00, 0xc0, 0x35, 0x44, 0xa0, 0xc0, +=090x35, 0x02, 0x00, 0xc0, 0x3e, 0x80, 0x93, 0xdd, 0x4c, 0x00, 0x00, 0xfa, +=090x88, 0x40, 0x00, 0xe8, 0x86, 0x02, 0x0c, 0xe1, 0x0e, 0x84, 0x4c, 0x08, +=090x00, 0xf2, 0x93, 0xdd, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x00, 0xf8, +=090xc6, 0x40, 0xb4, 0xe0, 0x00, 0x02, 0xb1, 0x64, 0x01, 0xc0, 0x2a, 0xc4, +=090x2b, 0xa1, 0x35, 0x92, 0x24, 0xc4, 0x2b, 0xa1, 0xc5, 0x90, 0x38, 0x06, +=090x46, 0x45, 0x00, 0xe0, 0x36, 0x46, 0x0a, 0xe0, 0x33, 0x80, 0x49, 0x06, +=090xf0, 0xe2, 0x4d, 0xe6, 0xc6, 0x40, 0x48, 0x41, 0x16, 0x02, 0x00, 0xc0, +=090x11, 0x40, 0x00, 0xc0, 0xd5, 0x8c, 0xc9, 0x06, 0x44, 0x62, 0x06, 0x4b, +=090x00, 0xe0, 0x46, 0x48, 0x16, 0x60, 0x86, 0x4a, 0xc8, 0xe0, 0x53, 0x08, +=090xc0, 0x58, 0x80, 0xf3, 0x49, 0x0a, 0xa4, 0xe7, 0x6b, 0x0a, 0xd8, 0xe3, +=090x49, 0xbe, 0xcf, 0xa8, 0xc1, 0x46, 0x44, 0xe2, 0x48, 0x86, 0xc9, 0x0a, +=090xa0, 0xe7, 0x46, 0x48, 0x0a, 0xe0, 0xc1, 0x46, 0x40, 0xe2, 0xcb, 0x0a, +=090xe0, 0x63, 0x43, 0x80, 0x63, 0x48, 0x28, 0xe1, 0x38, 0x86, 0x36, 0x46, +=090x0a, 0xe0, 0x33, 0x80, 0xc3, 0x46, 0x30, 0xe1, 0x18, 0x86, 0xcb, 0x0a, +=090xd4, 0xe3, 0x2b, 0x0a, 0xdc, 0x63, 0x16, 0x42, 0x0a, 0xe0, 0x5b, 0x0a, +=090xe4, 0xe3, 0xc3, 0x48, 0x24, 0x61, 0x03, 0x82, 0x23, 0x46, 0x2c, 0xe1, +=090x53, 0x40, 0x34, 0xe1, 0x4c, 0x0c, 0x00, 0xf0, 0x93, 0xdd, 0xc3, 0xc1, +=090x0c, 0x00, 0x80, 0xfa, 0x86, 0x43, 0xcc, 0x60, 0x0b, 0xa3, 0x29, 0x02, +=090xc4, 0xee, 0xb5, 0x84, 0x4a, 0x04, 0xfc, 0xfb, 0x45, 0x84, 0xc6, 0x40, +=090x84, 0xe0, 0x14, 0x82, 0x18, 0x84, 0x19, 0x86, 0x1b, 0xa5, 0x85, 0x8c, +=090x04, 0x80, 0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, 0xc5, 0x8a, +=090x0c, 0x08, 0x80, 0xf2, 0x08, 0x34, 0x44, 0xff, 0x0b, 0xa5, 0x15, 0x8a, +=090x0a, 0x04, 0x04, 0xf0, 0xb5, 0x88, 0xc6, 0x40, 0x84, 0xe0, 0x24, 0x82, +=090x28, 0x88, 0x29, 0x86, 0x2b, 0xa5, 0xc5, 0x86, 0x04, 0x80, 0x09, 0x00, +=090x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, 0x05, 0x86, 0x09, 0x02, 0x24, 0xee, +=090x0b, 0xa3, 0xd5, 0x80, 0x08, 0x84, 0x0a, 0x40, 0x80, 0xe0, 0x75, 0xf8, +=090xf5, 0x81, 0x38, 0x72, 0x44, 0xef, 0xf8, 0x51, 0xfc, 0xef, 0x4e, 0x40, +=090x01, 0x60, 0x10, 0xc0, 0x08, 0x80, 0x0b, 0xa1, 0xa5, 0x80, 0x0c, 0x08, +=090x80, 0xf2, 0xb8, 0x11, 0xfc, 0xff, 0x0c, 0x08, 0x80, 0xf2, 0x93, 0xdd, +=090xcc, 0x04, 0x0c, 0xfa, 0x06, 0x4f, 0x84, 0x60, 0x86, 0x50, 0x4c, 0xe1, +=090x04, 0x1c, 0x80, 0x0c, 0x21, 0x6f, 0x01, 0xc0, 0xf0, 0x04, 0x50, 0x64, +=090x11, 0x81, 0x09, 0x00, 0x6c, 0xe0, 0x06, 0x29, 0x0b, 0x8c, 0x58, 0x4c, +=090x58, 0xef, 0x04, 0x9c, 0x19, 0x00, 0x6c, 0xe0, 0x10, 0x44, 0x3c, 0xf0, +=090x2b, 0xa3, 0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, +=090x29, 0xa0, 0x2f, 0xa2, 0x21, 0x40, 0x6c, 0xe0, 0x86, 0x43, 0xcc, 0xe0, +=090x29, 0x02, 0x24, 0xee, 0x2b, 0xa3, 0xd5, 0x80, 0x18, 0x84, 0x4a, 0x42, +=090x80, 0x60, 0x11, 0x8b, 0x65, 0x80, 0x19, 0x00, 0x70, 0xe0, 0x16, 0x29, +=090xf0, 0x04, 0x50, 0xe4, 0x11, 0x03, 0x0b, 0x8c, 0x28, 0x4a, 0x58, 0xef, +=090x04, 0x9c, 0x19, 0x00, 0x70, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, 0xa3, +=090x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, +=090x2f, 0xa2, 0x21, 0x40, 0x70, 0xe0, 0x09, 0x00, 0x74, 0x60, 0xf0, 0x04, +=090x50, 0xe4, 0x11, 0x85, 0x06, 0x29, 0x0b, 0x8c, 0xa8, 0x48, 0x58, 0xef, +=090x04, 0x9c, 0x19, 0x00, 0x74, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, 0xa3, +=090x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, +=090x2f, 0xa2, 0x21, 0x40, 0x74, 0xe0, 0x09, 0x00, 0x78, 0x60, 0xf0, 0x04, +=090x50, 0xe4, 0x11, 0x87, 0x06, 0x29, 0x0b, 0x8c, 0x28, 0x47, 0x58, 0xef, +=090x04, 0x9c, 0x19, 0x00, 0x78, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, 0xa3, +=090x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, +=090x2f, 0xa2, 0x21, 0x40, 0x78, 0xe0, 0x19, 0x0e, 0xd0, 0xe0, 0x1b, 0xa1, +=090x85, 0x86, 0x05, 0x00, 0x24, 0xe0, 0x1a, 0xa2, 0x04, 0x04, 0xc0, 0xe1, +=090x2b, 0x83, 0xd5, 0x80, 0x19, 0x10, 0x10, 0x60, 0x09, 0x9e, 0x0b, 0x83, +=090x85, 0x84, 0x08, 0xa0, 0x0b, 0xa1, 0x38, 0x61, 0x74, 0xcf, 0x58, 0x49, +=090x34, 0xef, 0x14, 0x9c, 0x25, 0x02, 0x24, 0xe0, 0x24, 0x02, 0xc0, 0x61, +=090x29, 0x9e, 0x18, 0x58, 0x74, 0xef, 0x55, 0x81, 0x08, 0xa0, 0x0b, 0xa1, +=090x48, 0x60, 0x74, 0xcf, 0x28, 0x72, 0x4c, 0x6f, 0x46, 0x01, 0x08, 0xe0, +=090xcc, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x65, 0x5e, 0x04, 0xfa, +=090xf0, 0x0c, 0x10, 0xec, 0x60, 0x5e, 0x1c, 0x74, 0x61, 0x88, 0x6e, 0xbc, +=090xfc, 0x07, 0x80, 0xfe, 0xf0, 0x1e, 0x20, 0x6c, 0xe6, 0x40, 0x00, 0xe0, +=090xc8, 0x70, 0x4c, 0xef, 0x0b, 0xa1, 0xb5, 0x88, 0xc6, 0x0d, 0xdc, 0xe0, +=090x09, 0x0c, 0x94, 0xea, 0x0b, 0xa3, 0xf5, 0x80, 0x09, 0x0c, 0x91, 0x79, +=090x01, 0xc0, 0x0a, 0x40, 0x80, 0xe0, 0xe5, 0x82, 0xc8, 0x71, 0x44, 0xef, +=090x04, 0x18, 0x86, 0x02, 0x84, 0xe0, 0x24, 0x04, 0x31, 0x83, 0x01, 0x82, +=090x0e, 0x18, 0xe6, 0x00, 0x48, 0xe1, 0x36, 0x00, 0x21, 0x82, 0x2e, 0x84, +=090x46, 0x00, 0x2c, 0x61, 0x21, 0x83, 0x14, 0x00, 0x46, 0x40, 0x34, 0xe1, +=090x25, 0x42, 0x44, 0xe0, 0x28, 0x51, 0x28, 0xef, 0x88, 0x40, 0x00, 0xe8, +=090xf1, 0x90, 0xfc, 0x0f, 0x80, 0xf6, 0xf4, 0xbc, 0x64, 0xfd, 0x53, 0xc1, +=090x4c, 0x00, 0x00, 0xfa, 0x01, 0x03, 0x11, 0x81, 0x48, 0x79, 0x08, 0xef, +=090x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x00, 0x00, 0xfa, +=090x0d, 0x62, 0x8e, 0x45, 0xf0, 0xff, 0x75, 0x82, 0x4e, 0x05, 0x01, 0x60, +=090x10, 0x40, 0x07, 0xc8, 0x24, 0x88, 0x23, 0x80, 0x1e, 0x8a, 0x78, 0x40, +=090x00, 0xe8, 0x21, 0x81, 0x0b, 0x84, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, +=090x83, 0xc1, 0x93, 0xdd, 0x0c, 0x04, 0x00, 0xfa, 0x41, 0xb9, 0x06, 0x48, +=090x12, 0xe0, 0x33, 0x88, 0x45, 0x06, 0x14, 0xe0, 0x4b, 0xa3, 0xc5, 0x80, +=090x35, 0x06, 0x18, 0xe0, 0x3b, 0x23, 0x31, 0x81, 0x55, 0x80, 0x31, 0x83, +=090x0d, 0xe6, 0x04, 0x00, 0x88, 0x00, 0x4e, 0x08, 0x00, 0x00, 0x10, 0x80, +=090x05, 0x00, 0x10, 0x9c, 0x08, 0x40, 0x00, 0x98, 0x25, 0x0b, 0x8e, 0x40, +=090xf0, 0xff, 0x3b, 0xa1, 0x45, 0x8a, 0x2b, 0x23, 0x06, 0x4c, 0x00, 0xe0, +=090x45, 0x90, 0x2b, 0x25, 0x6e, 0x40, 0xf0, 0xff, 0x25, 0x87, 0x3b, 0xa1, +=090x25, 0x8a, 0x2b, 0x23, 0x06, 0x0c, 0x08, 0xe0, 0x05, 0x8e, 0x2b, 0x25, +=090x5e, 0x40, 0xf0, 0xff, 0x85, 0x0c, 0x06, 0x0c, 0x04, 0xe0, 0x95, 0x87, +=090x3b, 0xa1, 0xc5, 0x88, 0x2b, 0x23, 0x61, 0x91, 0x85, 0x8a, 0x2b, 0x25, +=090x7e, 0x40, 0xf0, 0xff, 0x25, 0x83, 0x2b, 0xa3, 0xc5, 0x08, 0x06, 0x0c, +=090x08, 0x80, 0x2b, 0x25, 0x4e, 0x40, 0xf0, 0xff, 0x15, 0x8a, 0xf5, 0x03, +=090x06, 0x0c, 0x04, 0xe0, 0x2b, 0x23, 0x61, 0x91, 0x45, 0x86, 0x2b, 0x25, +=090x6e, 0x40, 0xf0, 0xff, 0xc5, 0x04, 0x61, 0x89, 0xc5, 0x83, 0x2b, 0x23, +=090x06, 0x4c, 0x00, 0xe0, 0x05, 0x84, 0x2b, 0x25, 0x5e, 0x40, 0xf0, 0xff, +=090x85, 0x02, 0x61, 0xa1, 0x25, 0x83, 0x2b, 0x23, 0x61, 0x85, 0xe5, 0x80, +=090x2b, 0x25, 0x7e, 0x40, 0xf0, 0xff, 0x65, 0x00, 0x61, 0x83, 0x95, 0x81, +=090x0b, 0x02, 0x1b, 0x8c, 0x48, 0x78, 0xfc, 0xef, 0x0b, 0xa1, 0x00, 0x4c, +=090x00, 0xdc, 0x0b, 0x8c, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, +=090x0c, 0x04, 0x04, 0xfa, 0x6b, 0x00, 0xc6, 0x40, 0xdc, 0xe0, 0x04, 0x00, +=090xf0, 0x1e, 0x30, 0xec, 0x48, 0x55, 0xfc, 0x6e, 0x0e, 0x02, 0x24, 0x74, +=090x03, 0xc0, 0xb8, 0x68, 0xfc, 0xee, 0x58, 0x71, 0x08, 0xef, 0x78, 0x68, +=090xfc, 0x6e, 0x0b, 0x8c, 0x71, 0x01, 0x5b, 0x80, 0x7e, 0x3c, 0x0e, 0x00, +=090x05, 0x60, 0x10, 0xc0, 0x11, 0x03, 0x21, 0x81, 0x31, 0x05, 0x41, 0x81, +=090xa8, 0x77, 0x08, 0xef, 0x0e, 0x3e, 0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0, +=090x48, 0x4b, 0x0c, 0xef, 0x0e, 0x7c, 0x11, 0x81, 0x04, 0x3e, 0x21, 0x83, +=090x68, 0x76, 0xfc, 0x6f, 0x0e, 0x06, 0x04, 0x60, 0x10, 0xc0, 0xce, 0x0d, +=090x01, 0x60, 0x10, 0xc0, 0x76, 0x98, 0x04, 0xfc, 0xc8, 0x59, 0x0c, 0xef, +=090x13, 0xc3, 0x08, 0x98, 0x0b, 0xa1, 0xa5, 0xfe, 0x04, 0xfc, 0x18, 0x5c, +=090x0c, 0xef, 0x14, 0x3e, 0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0, 0x38, 0x46, +=090x0c, 0xef, 0x01, 0x01, 0xf1, 0x98, 0x0c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, +=090x65, 0x5e, 0x04, 0xfa, 0xf0, 0x0c, 0x10, 0xec, 0x60, 0x5e, 0x1c, 0x74, +=090x61, 0x88, 0x6e, 0xbc, 0xfc, 0x03, 0x80, 0xfe, 0x26, 0x00, 0x4c, 0x61, +=090x11, 0x83, 0x16, 0x00, 0xce, 0x01, 0x01, 0x60, 0x10, 0xc0, 0x16, 0x00, +=090x46, 0x00, 0x2c, 0xe1, 0x04, 0x00, 0xf0, 0x1e, 0x30, 0xec, 0x14, 0xc0, +=090x14, 0x02, 0x20, 0xfc, 0x1e, 0xc0, 0x98, 0x40, 0x00, 0xe8, 0xf1, 0x98, +=090xfc, 0x0b, 0x80, 0xf6, 0xf4, 0xbc, 0x64, 0xfd, 0x53, 0xc1, 0xc3, 0xc1, +=090x06, 0x00, 0x01, 0x60, 0x00, 0xe0, 0x06, 0x00, 0x62, 0xf4, 0x93, 0xdd, +=090x4c, 0x04, 0x7c, 0xfa, 0xc6, 0x54, 0x84, 0x60, 0x06, 0x0f, 0xdc, 0xe0, +=090x04, 0x2a, 0xae, 0x4d, 0x01, 0x60, 0x10, 0xc0, 0x29, 0x14, 0x70, 0x60, +=090x8e, 0x51, 0x00, 0x60, 0x10, 0xc0, 0x3b, 0x0e, 0x9c, 0x65, 0x06, 0x52, +=090x94, 0xe0, 0x1b, 0x00, 0x20, 0x60, 0x0e, 0x57, 0x08, 0x60, 0x10, 0xc0, +=090x0b, 0x00, 0x1c, 0xe0, 0x13, 0x20, 0x01, 0x81, 0x13, 0x84, 0x13, 0x86, +=090x11, 0x9e, 0x1c, 0x98, 0x0c, 0xa0, 0x04, 0xa4, 0x0b, 0x00, 0xa0, 0xe5, +=090x0c, 0xac, 0x0a, 0x98, 0x1a, 0xac, 0x0d, 0xc3, 0xf5, 0x82, 0x04, 0xa4, +=090x0b, 0x00, 0xa0, 0xe5, 0x0c, 0x2c, 0x01, 0x8b, 0x08, 0x56, 0x2c, 0xef, +=090x0a, 0xa0, 0x01, 0x82, 0x0c, 0xa0, 0x0a, 0xa0, 0x8a, 0x00, 0x24, 0xe7, +=090xf5, 0xfa, 0x05, 0x0e, 0xbc, 0x61, 0x06, 0x04, 0x00, 0x60, 0x00, 0xf0, +=090x13, 0x0e, 0xb8, 0x79, 0x06, 0x06, 0x00, 0x60, 0x00, 0xe0, 0x2f, 0x80, +=090x2b, 0x07, 0x0e, 0x45, 0x01, 0x60, 0x10, 0xc0, 0x1c, 0x88, 0x95, 0x86, +=090x07, 0xe1, 0x09, 0xbe, 0x0b, 0xa1, 0x05, 0x86, 0x21, 0xff, 0x1d, 0x84, +=090x85, 0x02, 0x00, 0x00, 0x08, 0x8c, 0x10, 0x04, 0x18, 0xec, 0x8a, 0x04, +=090x14, 0xed, 0xb5, 0x80, 0x8a, 0x02, 0x40, 0xe1, 0x75, 0x82, 0x01, 0x84, +=090x14, 0x24, 0x09, 0xbe, 0x29, 0x02, 0x00, 0xe3, 0x20, 0x44, 0x80, 0xf3, +=090x2f, 0xa0, 0x21, 0x42, 0x00, 0xe3, 0x8e, 0x41, 0x09, 0x60, 0x10, 0x40, +=090xc6, 0x0d, 0x30, 0xe1, 0x04, 0x80, 0x0b, 0xa3, 0x75, 0xa0, 0x19, 0x0c, +=090xcc, 0xe5, 0x4a, 0x02, 0xfc, 0xfb, 0xc5, 0x9e, 0xa8, 0x54, 0x00, 0x68, +=090x01, 0x81, 0x04, 0x24, 0x11, 0x85, 0x11, 0x40, 0x20, 0x60, 0x4e, 0x43, +=090x00, 0x60, 0x10, 0xc0, 0x04, 0xa4, 0x29, 0x00, 0x50, 0xeb, 0x2e, 0x84, +=090x24, 0x84, 0x29, 0x86, 0x2e, 0x84, 0x24, 0x84, 0x2b, 0xa1, 0x15, 0xfe, +=090xa8, 0x52, 0x44, 0xef, 0x04, 0xaa, 0x08, 0x80, 0x0b, 0xa5, 0xe5, 0x80, +=090x04, 0xa8, 0x09, 0x00, 0x20, 0xe1, 0x0b, 0xa1, 0x48, 0x4a, 0x44, 0x8f, +=090x46, 0x10, 0x74, 0xe1, 0x04, 0xa0, 0x14, 0xc0, 0x14, 0x02, 0x2c, 0xfc, +=090x1e, 0xc0, 0x14, 0xc0, 0x14, 0x02, 0x08, 0xfc, 0x1e, 0x40, 0x11, 0x83, +=090x04, 0xa4, 0x11, 0x40, 0xb0, 0x67, 0x11, 0x81, 0x04, 0xa6, 0x11, 0x40, +=090x10, 0xe0, 0xb8, 0x73, 0x74, 0xef, 0x84, 0x20, 0x70, 0x06, 0x00, 0xe7, +=090x8e, 0x17, 0x01, 0x60, 0x10, 0x40, 0xce, 0x54, 0x01, 0x60, 0x10, 0xc0, +=090x04, 0xe0, 0x04, 0x00, 0x04, 0xfc, 0x0e, 0xe0, 0x04, 0xe0, 0x04, 0x00, +=090x0c, 0xfc, 0x0e, 0xe0, 0x04, 0xe0, 0x04, 0x00, 0x10, 0xfc, 0x0e, 0xe0, +=090x45, 0x10, 0x2c, 0xe0, 0x44, 0x00, 0x00, 0xfc, 0x05, 0x50, 0x2c, 0x60, +=090x4e, 0x41, 0x08, 0x60, 0x10, 0xc0, 0x1b, 0x0e, 0xa0, 0xe1, 0x04, 0x80, +=090x2b, 0x0e, 0x9c, 0xe1, 0x1b, 0xc2, 0x03, 0x02, 0xce, 0x42, 0x01, 0x60, +=090x10, 0xc0, 0x3e, 0x04, 0x03, 0x84, 0x00, 0x00, 0xf4, 0xec, 0x0e, 0xac, +=090x09, 0x0e, 0x00, 0xe3, 0x4e, 0x8f, 0x0b, 0xa5, 0x0b, 0x0e, 0x10, 0xd8, +=090x95, 0x96, 0x0b, 0x0e, 0x84, 0xe1, 0x15, 0x0e, 0x10, 0xe0, 0x03, 0x4e, +=090x10, 0xf8, 0x1d, 0xc1, 0x13, 0x4e, 0x10, 0x58, 0x10, 0x40, 0x00, 0xdc, +=090x1a, 0x5e, 0x04, 0x04, 0x80, 0xfb, 0x2d, 0xc3, 0x13, 0x4e, 0x10, 0x58, +=090x10, 0x40, 0x00, 0xdc, 0x85, 0x89, 0x0b, 0xa1, 0x98, 0x0c, 0x00, 0xc0, +=090x68, 0x7b, 0x68, 0x6f, 0x01, 0x85, 0x60, 0x00, 0x10, 0x64, 0x11, 0x81, +=090xc8, 0x71, 0x54, 0xef, 0x28, 0x45, 0x70, 0xef, 0x09, 0x0e, 0xe8, 0xea, +=090x4a, 0x40, 0x90, 0xe0, 0x06, 0x00, 0x00, 0xc0, 0xa8, 0x4b, 0x00, 0xc8, +=090x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x80, 0xe0, 0x25, 0xac, 0x19, 0x0c, +=090xcc, 0xe5, 0x4a, 0x02, 0xfc, 0xfb, 0x85, 0xaa, 0x0a, 0x40, 0x90, 0xe0, +=090x45, 0x82, 0x46, 0x00, 0x74, 0xe1, 0x04, 0x80, 0x14, 0xc0, 0x14, 0x02, +=090x2c, 0xfc, 0x1e, 0xc0, 0x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x84, 0xe0, +=090x25, 0x82, 0xb8, 0x68, 0x30, 0x6f, 0x01, 0x81, 0xc8, 0x58, 0x2c, 0x6f, +=090x0b, 0x8c, 0x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x94, 0xe0, 0x45, 0x82, +=090x46, 0x00, 0x74, 0xe1, 0x04, 0x80, 0x14, 0xc0, 0x14, 0x02, 0x08, 0xfc, +=090x1e, 0xc0, 0x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x98, 0xe0, 0x18, 0x49, +=090x00, 0xc8, 0x45, 0x91, 0x14, 0x2c, 0x04, 0x00, 0x80, 0xfb, 0x13, 0x20, +=090x06, 0x41, 0x2c, 0xe0, 0x16, 0x40, 0x02, 0x60, 0x46, 0x42, 0x04, 0xe0, +=090xc8, 0x7a, 0xf8, 0xee, 0x0e, 0x2c, 0x0e, 0x4c, 0x01, 0x60, 0x10, 0xc0, +=090x04, 0xac, 0x00, 0x00, 0xd1, 0x6f, 0x0f, 0xc0, 0x0e, 0xac, 0x05, 0x10, +=090x40, 0xe0, 0x04, 0x00, 0x38, 0xfc, 0x0e, 0x98, 0x05, 0x50, 0x40, 0xe0, +=090x04, 0xac, 0xd8, 0x63, 0xfc, 0xef, 0x46, 0x10, 0x74, 0xe1, 0x04, 0xa0, +=090x15, 0x00, 0x40, 0xe0, 0x14, 0x02, 0xb8, 0xfc, 0x1e, 0x98, 0x15, 0x40, +=090x40, 0xe0, 0x98, 0x52, 0x30, 0xef, 0x0b, 0xa1, 0xa5, 0xfe, 0x34, 0x28, +=090xc6, 0x0d, 0x30, 0xe1, 0x08, 0x8c, 0x0b, 0xa5, 0x0b, 0x0e, 0x04, 0xd8, +=090x1b, 0x0e, 0x00, 0xc0, 0x2b, 0x0e, 0x04, 0xc0, 0x3b, 0x0e, 0x08, 0xc0, +=090x75, 0x84, 0x08, 0x8e, 0x19, 0x0e, 0x10, 0xeb, 0x12, 0x40, 0x80, 0xfb, +=090x01, 0x4e, 0x10, 0xf8, 0x0a, 0xcc, 0x03, 0x4e, 0x04, 0xf8, 0x1a, 0xce, +=090x1c, 0x9c, 0x2b, 0x06, 0x10, 0xe0, 0x2c, 0x9e, 0x3b, 0x06, 0x14, 0xe0, +=090x3c, 0xdc, 0xa4, 0x8f, 0x03, 0x4e, 0x80, 0xf9, 0x13, 0x4e, 0x7c, 0xf9, +=090x23, 0x4e, 0x78, 0xf9, 0x33, 0x4e, 0x74, 0xf9, 0xc8, 0x6d, 0x38, 0xef, +=090xe8, 0x66, 0x3c, 0xef, 0x04, 0x20, 0xa9, 0xc2, 0xa5, 0x40, 0x2c, 0xe0, +=090x19, 0x0c, 0x40, 0xe6, 0x1b, 0xa1, 0x55, 0x88, 0x14, 0xc0, 0x19, 0xd0, +=090x1e, 0xc0, 0x14, 0xc0, 0x19, 0xe0, 0x1e, 0xc0, 0x14, 0xc0, 0x19, 0xc4, +=090x1e, 0x40, 0x01, 0x83, 0xa8, 0x41, 0x00, 0xe8, 0x04, 0xa0, 0x14, 0xc0, +=090x14, 0x02, 0xac, 0xfc, 0x1e, 0xc0, 0x14, 0xc0, 0x19, 0xc8, 0x1e, 0xc0, +=090x48, 0x51, 0x74, 0xef, 0x04, 0x26, 0x11, 0x83, 0x11, 0x40, 0x10, 0xe0, +=090x04, 0xa4, 0x11, 0x40, 0x20, 0x60, 0x11, 0x81, 0x04, 0xa4, 0x11, 0x40, +=090xb0, 0xe7, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x1b, 0x00, 0x06, 0x01, +=090x38, 0xe1, 0x04, 0x80, 0xc8, 0x20, 0x04, 0x60, 0x01, 0xb8, 0xc3, 0xc1, +=090x83, 0xc1, 0x13, 0xc3, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, +=090xe6, 0x41, 0x84, 0x60, 0x8e, 0x42, 0x00, 0x60, 0x10, 0xc0, 0x08, 0x80, +=090x14, 0x84, 0x0b, 0x21, 0xa6, 0x41, 0x04, 0xe1, 0x1c, 0x80, 0x05, 0x82, +=090x28, 0x47, 0x64, 0xef, 0x88, 0x7b, 0x28, 0x6f, 0x46, 0x40, 0x04, 0xe0, +=090x35, 0x81, 0x38, 0x56, 0x40, 0xef, 0xd8, 0x67, 0x64, 0xef, 0x38, 0x63, +=090x64, 0xef, 0xd8, 0x44, 0x44, 0xef, 0x06, 0x40, 0x94, 0xe0, 0x04, 0x80, +=090x09, 0x00, 0x50, 0xeb, 0x0a, 0x40, 0x88, 0xe0, 0x76, 0x00, 0xa0, 0xc0, +=090x68, 0x4e, 0x50, 0xcf, 0xc6, 0x0d, 0x30, 0xe1, 0x09, 0x0c, 0x30, 0xe7, +=090x0b, 0xa1, 0x78, 0x6c, 0x70, 0xcf, 0x98, 0x7f, 0x6c, 0xef, 0x38, 0x4b, +=090x2c, 0x6f, 0x0b, 0x8c, 0xc8, 0x5a, 0x30, 0x6f, 0x01, 0x81, 0x58, 0x49, +=090x30, 0xef, 0xb8, 0x5f, 0x70, 0xef, 0x01, 0x83, 0x01, 0x4c, 0xc0, 0xe5, +=090x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x84, 0xfa, +=090x06, 0x4e, 0x88, 0x60, 0x06, 0x0c, 0x0c, 0xe1, 0x05, 0x0e, 0x38, 0x78, +=090x06, 0x04, 0x00, 0x70, 0x40, 0xc0, 0x19, 0x0c, 0x94, 0x78, 0x06, 0x06, +=090x10, 0x60, 0x40, 0xc0, 0x08, 0xc0, 0x4a, 0x02, 0x00, 0xe0, 0x09, 0x86, +=090x07, 0xc6, 0x2f, 0x61, 0x3f, 0xe1, 0x21, 0x4e, 0x10, 0xf8, 0x0c, 0x00, +=090x00, 0xe2, 0x31, 0x4e, 0x0c, 0xf8, 0x18, 0x62, 0x30, 0xef, 0x05, 0x0e, +=090x38, 0xf8, 0x14, 0x98, 0x09, 0x00, 0x24, 0xe0, 0x4a, 0x40, 0x88, 0xe0, +=090x65, 0x82, 0x0b, 0x0c, 0x28, 0x78, 0x1b, 0xa1, 0x0c, 0xde, 0x05, 0x84, +=090x0a, 0x01, 0x20, 0xec, 0xf5, 0x84, 0x55, 0x03, 0x01, 0x93, 0x0b, 0x0c, +=090x24, 0x78, 0x1b, 0xa1, 0x0c, 0xde, 0x65, 0x82, 0x0a, 0x01, 0x24, 0xec, +=090xb5, 0x82, 0xb5, 0x01, 0x01, 0x95, 0x0a, 0x01, 0x48, 0xec, 0x15, 0x82, +=090x65, 0x01, 0x01, 0xa7, 0x0a, 0x01, 0x50, 0xec, 0x75, 0x80, 0x01, 0xab, +=090x0c, 0xde, 0x15, 0x0c, 0x20, 0x79, 0x06, 0x04, 0x00, 0x60, 0x00, 0xf0, +=090x49, 0x0c, 0x64, 0x78, 0x06, 0x06, 0x00, 0x60, 0x00, 0xe0, 0x2f, 0x82, +=090x3b, 0x0c, 0x8c, 0x78, 0x2b, 0x87, 0x30, 0x42, 0x00, 0x5c, 0x4a, 0x08, +=090x14, 0xfc, 0x14, 0x04, 0x80, 0x7a, 0xce, 0x43, 0x00, 0x60, 0x10, 0xc0, +=090x2c, 0x04, 0x8e, 0x48, 0x01, 0x60, 0x10, 0xc0, 0x3e, 0x90, 0x85, 0x88, +=090x45, 0x0e, 0x30, 0xf8, 0x3b, 0x08, 0x18, 0xe0, 0x5b, 0x08, 0x20, 0xe0, +=090x4b, 0x08, 0x1c, 0xe0, 0x32, 0x4a, 0x94, 0xf1, 0x53, 0x88, 0x8a, 0x0a, +=090x89, 0x63, 0x05, 0xc0, 0xb5, 0x84, 0x54, 0x1a, 0x8e, 0x59, 0x09, 0x60, +=090x10, 0xc0, 0x71, 0x83, 0x7e, 0x30, 0x2e, 0x59, 0x09, 0x60, 0x10, 0xc0, +=090x5c, 0x30, 0x54, 0x08, 0x80, 0xfb, 0x4d, 0x44, 0x4e, 0x45, 0x09, 0x60, +=090x10, 0xc0, 0x3e, 0x88, 0x43, 0x42, 0x00, 0xc0, 0x65, 0x81, 0x8e, 0x43, +=090x09, 0x60, 0x10, 0x40, 0x21, 0x81, 0x2e, 0x84, 0x03, 0x4c, 0xd5, 0x79, +=090x02, 0x40, 0xd6, 0x41, 0x00, 0xe0, 0x0c, 0x0c, 0x84, 0xf2, 0x18, 0x34, +=090x48, 0xff, 0xc3, 0xc1, 0x0c, 0x04, 0xfc, 0xfa, 0x6b, 0x00, 0x06, 0x41, +=090x08, 0xe0, 0x98, 0x73, 0x48, 0xef, 0x0b, 0xa1, 0x78, 0x14, 0x00, 0xc0, +=090x86, 0x52, 0x84, 0xe0, 0x74, 0xe4, 0x08, 0x9c, 0x09, 0x86, 0x0b, 0xa3, +=090x36, 0x40, 0x98, 0x40, 0x06, 0x02, 0x00, 0xc0, 0x11, 0x40, 0x00, 0xc0, +=090xf5, 0x80, 0x21, 0x01, 0x36, 0x40, 0x98, 0xe0, 0x2e, 0x18, 0x11, 0x83, +=090x16, 0x80, 0x84, 0x26, 0x16, 0x44, 0x98, 0xe0, 0x18, 0x9c, 0x09, 0x10, +=090xb4, 0xe0, 0x0a, 0x02, 0x0c, 0xfc, 0x0c, 0x02, 0x00, 0xe2, 0x01, 0x4c, +=090x10, 0xe1, 0x0b, 0x10, 0x80, 0xe0, 0x16, 0x88, 0xe8, 0x75, 0xf8, 0xee, +=090x05, 0x4c, 0x48, 0xe0, 0x08, 0x9c, 0x00, 0x42, 0x08, 0xfc, 0x19, 0x86, +=090x1b, 0xa5, 0xd5, 0x80, 0x4a, 0x00, 0x0c, 0xf8, 0x0c, 0x00, 0x00, 0xe2, +=090x0e, 0x98, 0x09, 0x10, 0xb0, 0xe0, 0x98, 0x51, 0x00, 0x68, 0x09, 0x82, +=090x01, 0x4c, 0x18, 0x60, 0x11, 0x9f, 0x0b, 0x10, 0x88, 0xe0, 0x78, 0x51, +=090x00, 0xe8, 0x14, 0xa6, 0x05, 0x4c, 0x4c, 0xe0, 0x0b, 0x02, 0x84, 0x60, +=090x11, 0x91, 0xf8, 0x50, 0x00, 0xe8, 0xb4, 0xa6, 0x05, 0x4c, 0x50, 0xe0, +=090x09, 0x16, 0xd0, 0xe0, 0x0a, 0x40, 0x84, 0x60, 0x06, 0x00, 0x00, 0x60, +=090x48, 0xd0, 0x56, 0x01, 0x55, 0x15, 0x41, 0xd0, 0x05, 0x4c, 0x34, 0xe0, +=090x09, 0x16, 0xd0, 0xe0, 0x68, 0x4f, 0x00, 0x68, 0x09, 0x82, 0x14, 0x64, +=090x06, 0x54, 0xdc, 0xe0, 0x01, 0x4c, 0x10, 0x60, 0xce, 0x41, 0x00, 0x60, +=090x10, 0xc0, 0x0a, 0x80, 0x2b, 0x02, 0x18, 0xe0, 0x23, 0xa0, 0x23, 0x4c, +=090x60, 0xe0, 0x09, 0x14, 0x70, 0xea, 0x22, 0x40, 0x80, 0xf1, 0x03, 0x4c, +=090x60, 0xe0, 0x25, 0x14, 0xe0, 0xe2, 0x2b, 0xa3, 0x35, 0x88, 0x24, 0xa4, +=090x3b, 0x02, 0x18, 0xe0, 0x4b, 0x02, 0x20, 0xe0, 0x1b, 0x02, 0x1c, 0xe0, +=090x59, 0x04, 0x24, 0xe0, 0x33, 0xa8, 0x32, 0x44, 0x84, 0x70, 0x2e, 0x47, +=090x08, 0x60, 0x10, 0xc0, 0x20, 0x02, 0xfc, 0x6c, 0x0a, 0x4a, 0x88, 0xe0, +=090x1c, 0x0c, 0x20, 0x02, 0x14, 0xcc, 0x10, 0x02, 0xf0, 0xcc, 0x13, 0x46, +=090x00, 0x40, 0x0a, 0x41, 0x04, 0xec, 0x13, 0x4c, 0x60, 0x40, 0x10, 0x40, +=090x00, 0xdc, 0x15, 0x14, 0xdc, 0x62, 0x04, 0x00, 0x80, 0xfb, 0x86, 0x05, +=090x74, 0xe1, 0x1d, 0xc1, 0x13, 0x4c, 0x60, 0x40, 0x14, 0x00, 0x80, 0xdb, +=090x14, 0xa4, 0x0e, 0xa8, 0x04, 0x88, 0x7a, 0x84, 0x73, 0x4c, 0x64, 0xe0, +=090xe8, 0x6d, 0xf8, 0xee, 0x1b, 0x00, 0x8e, 0x40, 0xb1, 0x66, 0x9b, 0xd3, +=090x08, 0x6d, 0xf8, 0xee, 0x8b, 0x00, 0x0b, 0x8e, 0x85, 0x4c, 0x3c, 0xe0, +=090x28, 0x6d, 0xf8, 0xee, 0x1b, 0x00, 0x0b, 0x90, 0x28, 0x6d, 0xf8, 0xee, +=090x48, 0x6c, 0xf8, 0x6e, 0x0e, 0x02, 0x00, 0x60, 0x1e, 0xd1, 0x05, 0x4c, +=090x40, 0x60, 0x11, 0x91, 0x0b, 0x16, 0x64, 0xe0, 0x7b, 0x16, 0x5c, 0xe0, +=090x89, 0x16, 0xc0, 0xe0, 0x08, 0x49, 0x00, 0xe8, 0x3b, 0x00, 0x80, 0x44, +=090x7c, 0xf0, 0x81, 0x01, 0x11, 0x81, 0xb8, 0x40, 0x40, 0x6f, 0x0b, 0x8e, +=090x4b, 0x0c, 0x60, 0x60, 0x06, 0x0e, 0x00, 0x60, 0xe0, 0xcf, 0x0e, 0x5a, +=090x11, 0x81, 0x21, 0x01, 0x06, 0x06, 0x01, 0x60, 0xe0, 0xcf, 0xd8, 0x7f, +=090x3c, 0x6f, 0x0b, 0x88, 0x14, 0x64, 0x86, 0x57, 0x94, 0xe1, 0x05, 0x4c, +=090x2c, 0xe0, 0x0a, 0x86, 0x83, 0x4c, 0xe4, 0xe0, 0x03, 0x4c, 0xe0, 0xe0, +=090x08, 0x86, 0x09, 0xbe, 0x03, 0x4c, 0xe8, 0xe0, 0x08, 0x86, 0x09, 0xbe, +=090x07, 0xc4, 0x05, 0x00, 0x2c, 0xfc, 0x05, 0x4c, 0x54, 0xe0, 0x0a, 0xc4, +=090x03, 0x4c, 0xec, 0xe0, 0x0a, 0x44, 0x11, 0x91, 0xe8, 0x45, 0x00, 0xe8, +=090x14, 0xe4, 0x05, 0x4c, 0x58, 0xe0, 0x0a, 0x46, 0x11, 0x91, 0x78, 0x45, +=090x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x5c, 0xe0, 0x0b, 0x02, 0x10, 0x60, +=090x11, 0x91, 0xf8, 0x44, 0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x60, 0xe0, +=090x0b, 0x02, 0x14, 0x60, 0x11, 0x91, 0x78, 0x44, 0x00, 0xe8, 0x14, 0xa6, +=090x05, 0x4c, 0x64, 0xe0, 0x85, 0x4c, 0x14, 0xe0, 0x85, 0x4c, 0x18, 0xe0, +=090x0b, 0x02, 0x7c, 0x60, 0x11, 0x91, 0xb8, 0x43, 0x00, 0xe8, 0x05, 0x4c, +=090x10, 0x60, 0x11, 0x91, 0x81, 0x4c, 0x14, 0xe0, 0x75, 0x4c, 0x1c, 0xe0, +=090x09, 0x14, 0xd0, 0xea, 0x07, 0xc4, 0x05, 0x00, 0x2c, 0xfc, 0x05, 0x4c, +=090x20, 0xe0, 0x0b, 0x14, 0x94, 0xe5, 0x98, 0x42, 0x00, 0xe8, 0x05, 0x4c, +=090x38, 0x60, 0x11, 0x91, 0x0b, 0x14, 0x64, 0xe5, 0x28, 0x42, 0x00, 0xe8, +=090x05, 0x4c, 0x28, 0x60, 0x11, 0x81, 0x09, 0x14, 0x8c, 0x6a, 0x21, 0x81, +=090x0b, 0x12, 0x7c, 0x60, 0x0a, 0x40, 0x88, 0xe0, 0xd6, 0x0e, 0xcd, 0x0c, +=090x73, 0xcf, 0x75, 0x4c, 0x24, 0x60, 0x3b, 0x8e, 0x28, 0x79, 0x3c, 0xef, +=090x0e, 0xd8, 0x16, 0x41, 0x08, 0xe0, 0x0c, 0x0c, 0xfc, 0xf2, 0xb8, 0x1e, +=090x48, 0xff, 0xc3, 0xc1, 0x4a, 0x00, 0x00, 0xe0, 0x0c, 0x00, 0x00, 0xe2, +=090x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x00, 0x00, 0xfa, 0x88, 0x61, 0x28, 0xef, +=090x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, +=090x88, 0x5d, 0x48, 0x6f, 0xf6, 0x40, 0x04, 0xe0, 0x0b, 0xa1, 0x85, 0x80, +=090x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0xb8, 0x6b, 0x54, 0xef, 0xc6, 0x4c, +=090x84, 0xe0, 0x04, 0x98, 0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, +=090x85, 0x88, 0xc6, 0x40, 0xb4, 0x60, 0x46, 0x45, 0x00, 0xe0, 0x19, 0x00, +=090xb4, 0xe4, 0x16, 0x42, 0x0a, 0xe0, 0x03, 0x82, 0x09, 0x00, 0x40, 0xe2, +=090x0b, 0xa5, 0xf5, 0x84, 0x48, 0x56, 0x40, 0x6f, 0x01, 0x85, 0x58, 0x4c, +=090x40, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0xd8, 0x7d, 0x44, 0x6f, 0x06, 0x00, +=090x80, 0xe1, 0x58, 0x50, 0x40, 0xef, 0x18, 0x70, 0xf4, 0xef, 0x4e, 0x40, +=090x01, 0x60, 0x10, 0xc0, 0x08, 0x80, 0x0b, 0xa1, 0x08, 0x70, 0xf4, 0xcf, +=090x09, 0x0c, 0x48, 0xe0, 0x0b, 0xa1, 0x95, 0x84, 0xe8, 0x70, 0x38, 0xef, +=090x06, 0x40, 0x94, 0x60, 0x16, 0x07, 0x04, 0xe1, 0x04, 0x80, 0x1b, 0x00, +=090x18, 0xe1, 0x2b, 0x00, 0x50, 0xe1, 0x48, 0x8c, 0x39, 0x06, 0xac, 0xe0, +=090x13, 0xa4, 0x13, 0xa8, 0x13, 0xa6, 0x15, 0x40, 0x2c, 0xe0, 0xc6, 0x00, +=090x2c, 0x61, 0x11, 0xa1, 0x04, 0x80, 0x13, 0x40, 0xd0, 0x65, 0xe6, 0x40, +=090xe0, 0xe0, 0x0a, 0x00, 0x06, 0x42, 0x94, 0xe0, 0x14, 0x84, 0x03, 0x42, +=090x10, 0x62, 0x06, 0x41, 0x04, 0xe0, 0x0c, 0x0c, 0x00, 0xf2, 0x98, 0x17, +=090x48, 0xff, 0xc3, 0xc1, 0x66, 0x01, 0xcc, 0xe0, 0x18, 0x80, 0x0a, 0x42, +=090x84, 0xe0, 0x10, 0x42, 0xf8, 0xd3, 0x11, 0x40, 0x00, 0xc0, 0x93, 0xdd, +=090x4a, 0x40, 0x80, 0xe0, 0x55, 0x84, 0x14, 0x04, 0xa0, 0x60, 0x0e, 0x06, +=090x00, 0x70, 0x3f, 0xc0, 0x2f, 0x06, 0x14, 0x06, 0xa0, 0xe1, 0x14, 0x00, +=090xe0, 0x61, 0x30, 0x46, 0x00, 0x70, 0xff, 0xc0, 0x17, 0x70, 0x3f, 0xa0, +=090x1f, 0xa4, 0x1f, 0xa6, 0x93, 0x5d, 0x0b, 0x82, 0x4c, 0x04, 0x04, 0xfa, +=090x86, 0x0d, 0xcc, 0x60, 0x71, 0x81, 0x7c, 0x98, 0x88, 0x55, 0x68, 0xef, +=090x0a, 0x98, 0x00, 0x42, 0xf1, 0x73, 0xff, 0xc0, 0x19, 0xc2, 0x1c, 0x18, +=090x60, 0x02, 0xe1, 0x65, 0x02, 0xc0, 0x65, 0x81, 0x24, 0x84, 0x2b, 0xa1, +=090xf5, 0x80, 0x71, 0x02, 0x11, 0x88, 0x0a, 0x0e, 0x00, 0xe1, 0x35, 0xfe, +=090x75, 0x81, 0x77, 0x50, 0x00, 0x40, 0xf0, 0xf3, 0x0f, 0xae, 0x09, 0xc4, +=090x0c, 0x98, 0x4c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x4c, 0x04, 0x7c, 0xfa, +=090xbb, 0x06, 0x6b, 0x82, 0x14, 0x2c, 0x9b, 0x80, 0x74, 0x24, 0xab, 0x84, +=090xa4, 0x00, 0xa0, 0x61, 0x8b, 0x88, 0x1b, 0x81, 0x65, 0x82, 0x0e, 0x2c, +=090x0b, 0x8e, 0x78, 0x56, 0x30, 0x6f, 0x1b, 0x8c, 0x24, 0x2c, 0x0b, 0x8e, +=090x28, 0x59, 0x30, 0x6f, 0x1b, 0x8c, 0x04, 0x18, 0xb1, 0x83, 0x11, 0x01, +=090x21, 0x83, 0x38, 0x44, 0x00, 0x68, 0x31, 0x85, 0xa4, 0x02, 0x80, 0x7a, +=090x21, 0x8b, 0xd8, 0x43, 0x00, 0x68, 0x06, 0x46, 0xfc, 0xe1, 0xab, 0x00, +=090x0b, 0x8e, 0x78, 0x40, 0xf8, 0x6f, 0x1b, 0x94, 0x09, 0x12, 0x10, 0x60, +=090x1b, 0x90, 0x98, 0x79, 0xfc, 0x6f, 0x70, 0x12, 0x10, 0xe4, 0x1b, 0x00, +=090x0b, 0x92, 0xb8, 0x7f, 0xf4, 0xef, 0x11, 0x03, 0x21, 0x85, 0x31, 0x09, +=090x0b, 0x94, 0x58, 0x42, 0x00, 0xe8, 0x8b, 0x00, 0x0b, 0x8e, 0x18, 0x7f, +=090xf4, 0x6f, 0x1b, 0x90, 0x70, 0x12, 0x50, 0x64, 0x36, 0x54, 0x48, 0xe1, +=090x08, 0x42, 0x00, 0x68, 0x0b, 0x92, 0x0a, 0x00, 0x00, 0xfb, 0xb1, 0x54, +=090x00, 0x40, 0x0a, 0x40, 0xa0, 0xe0, 0xe5, 0xfc, 0x11, 0x01, 0x21, 0x85, +=090x31, 0x09, 0x0b, 0x90, 0xc8, 0x40, 0x00, 0xe8, 0x8b, 0x00, 0x0b, 0x8e, +=090x88, 0x7d, 0xf4, 0x6f, 0x1b, 0x90, 0x8e, 0x98, 0x4c, 0x0c, 0x7c, 0xf2, +=090x93, 0xdd, 0xc3, 0xc1, 0x1f, 0x25, 0x32, 0x40, 0x80, 0xf8, 0x1f, 0x86, +=090x93, 0x5d, 0x0f, 0xa2, 0x04, 0x80, 0x93, 0xdd, 0x0c, 0x00, 0x80, 0xfa, +=090xa8, 0x4c, 0x48, 0x6f, 0xe6, 0x40, 0x08, 0xe0, 0x0b, 0xa1, 0x95, 0x84, +=090xc8, 0x46, 0x40, 0xef, 0x86, 0x02, 0x84, 0x60, 0xc6, 0x04, 0x84, 0xe0, +=090x14, 0x04, 0x5a, 0x00, 0x08, 0xe0, 0x24, 0x88, 0x4a, 0x42, 0x08, 0x60, +=090x46, 0x02, 0x84, 0xe0, 0x0a, 0x42, 0x80, 0xe1, 0x0c, 0x00, 0x00, 0xe2, +=090x06, 0x84, 0xf6, 0x40, 0x08, 0xe0, 0x0c, 0x08, 0x80, 0xf2, 0xd8, 0x0a, +=090x48, 0xff, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0xf0, 0x1e, 0x60, 0x6c, +=090xa6, 0x01, 0x04, 0xe0, 0x48, 0x4a, 0x48, 0xef, 0x0b, 0xa1, 0x15, 0x90, +=090xc8, 0x5d, 0x2c, 0xef, 0xe8, 0x7a, 0xf4, 0x6e, 0x0e, 0x02, 0x24, 0x74, +=090x03, 0xc0, 0x86, 0x50, 0x84, 0xe0, 0x69, 0x10, 0x44, 0xe0, 0x58, 0x7a, +=090xf4, 0x6e, 0x1b, 0x8c, 0x04, 0x60, 0x7b, 0x80, 0x1b, 0x00, 0x28, 0xe0, +=090x0b, 0x00, 0x24, 0xe0, 0x13, 0xa0, 0x10, 0x00, 0x04, 0x64, 0x1b, 0x8c, +=090x88, 0x79, 0xf4, 0xee, 0x14, 0xa0, 0x19, 0x02, 0x28, 0xe0, 0x19, 0xbe, +=090x06, 0x44, 0x06, 0x60, 0x06, 0x41, 0xdc, 0xe0, 0x04, 0x00, 0x16, 0x42, +=090x1e, 0xe0, 0x21, 0xbe, 0x1e, 0x7c, 0x27, 0xcb, 0x2c, 0x7c, 0x0e, 0x02, +=090x25, 0x74, 0x03, 0xc0, 0x48, 0x78, 0xf4, 0xee, 0x0e, 0x7e, 0x11, 0x81, +=090x1e, 0x09, 0xf0, 0x00, 0x10, 0xe4, 0x1c, 0x95, 0x88, 0x7e, 0x1c, 0xef, +=090x0a, 0x95, 0x18, 0x41, 0x00, 0x68, 0x01, 0xa0, 0x06, 0x00, 0x38, 0x61, +=090x11, 0x83, 0x78, 0x7c, 0x1c, 0xef, 0x18, 0x46, 0x48, 0x6f, 0xb6, 0x01, +=090x04, 0xe0, 0xf1, 0xb0, 0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, +=090x1b, 0x00, 0x06, 0x00, 0x38, 0xe1, 0x04, 0x80, 0x08, 0x35, 0xf4, 0x7f, +=090x01, 0xc8, 0xc3, 0xc1, 0x0c, 0x04, 0x3c, 0xfa, 0x86, 0x4e, 0x84, 0x60, +=090xf0, 0x1e, 0x20, 0xee, 0x84, 0x9c, 0x19, 0x0e, 0x48, 0xe0, 0x0a, 0xe2, +=090x2a, 0xe0, 0x03, 0xa4, 0x01, 0x82, 0x38, 0x75, 0xf4, 0x6e, 0x04, 0x00, +=090x80, 0xfb, 0x0b, 0x10, 0x64, 0x60, 0x6b, 0x80, 0x0b, 0xa1, 0x05, 0x0e, +=090x04, 0xc0, 0x99, 0x00, 0xa0, 0xc0, 0xd5, 0x84, 0x09, 0x10, 0x24, 0x60, +=090x06, 0x03, 0xd0, 0xe0, 0x1a, 0x84, 0x07, 0xc5, 0x09, 0x82, 0x1f, 0x21, +=090x06, 0x00, 0x04, 0xe0, 0x10, 0x42, 0x01, 0x70, 0xff, 0xc0, 0x17, 0xd1, +=090x1b, 0xa1, 0x78, 0x73, 0xf4, 0x6e, 0x16, 0x02, 0x00, 0x80, 0x00, 0x12, +=090x04, 0xec, 0x18, 0x42, 0x48, 0x6f, 0x36, 0x01, 0x04, 0xe0, 0x0b, 0xa1, +=090xb5, 0xb0, 0x04, 0x1c, 0x06, 0x11, 0xd0, 0xe0, 0x19, 0x10, 0x24, 0x6e, +=090x46, 0x05, 0xb8, 0xe0, 0xa4, 0x9e, 0x09, 0x00, 0xb0, 0xe0, 0x18, 0x08, +=090x5a, 0x02, 0x00, 0xe0, 0x1c, 0x06, 0x00, 0xe2, 0x36, 0x3e, 0x09, 0x86, +=090x0b, 0x21, 0x19, 0x82, 0x0c, 0x04, 0x00, 0x62, 0x0b, 0xa5, 0x16, 0x7c, +=090x64, 0x02, 0x80, 0xfb, 0x26, 0x3c, 0x6b, 0x9e, 0x1e, 0xbe, 0x19, 0x0e, +=090x60, 0xe0, 0x2b, 0x10, 0x30, 0xf8, 0x0c, 0x00, 0x00, 0xe2, 0x16, 0x1b, +=090x11, 0x81, 0x06, 0x7e, 0x2b, 0xa3, 0x19, 0x14, 0x5c, 0xc0, 0x09, 0x0e, +=090x80, 0xe0, 0x25, 0x10, 0xa4, 0xe3, 0x35, 0x10, 0xa8, 0x63, 0x10, 0x42, +=090x3c, 0xd0, 0x0c, 0x0b, 0x01, 0x81, 0x16, 0x1d, 0x11, 0x81, 0x26, 0x1f, +=090x46, 0x05, 0x04, 0xe0, 0x0c, 0x89, 0x06, 0x99, 0x06, 0xa5, 0x0c, 0x91, +=090x3e, 0x8b, 0x0e, 0x91, 0x0e, 0x8f, 0x0e, 0x0d, 0x60, 0x00, 0xa0, 0xe4, +=090x91, 0x5e, 0x90, 0xe0, 0xc8, 0x7a, 0xf4, 0xee, 0x09, 0x14, 0x58, 0xe0, +=090x19, 0x10, 0xf0, 0xf8, 0x0e, 0x3f, 0xfe, 0x41, 0x3d, 0x70, 0xff, 0xc0, +=090x1b, 0x25, 0xf6, 0x43, 0x3c, 0xe0, 0x05, 0x5e, 0x80, 0x60, 0x16, 0x00, +=090x00, 0x80, 0x15, 0x5e, 0x84, 0xe0, 0x01, 0x5e, 0x34, 0x80, 0x05, 0x14, +=090x18, 0xe0, 0x38, 0x47, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, +=090x2a, 0x20, 0x11, 0x91, 0x0e, 0x97, 0x78, 0x5d, 0xfc, 0x6f, 0x0b, 0x84, +=090x19, 0x10, 0xc0, 0xe9, 0x0e, 0xb7, 0x4a, 0x42, 0x80, 0xe0, 0xc5, 0x82, +=090x60, 0x00, 0xc0, 0x65, 0x11, 0xfb, 0x75, 0x81, 0x24, 0x37, 0x11, 0x82, +=090x2e, 0xc1, 0x24, 0x97, 0x25, 0x40, 0x44, 0xf8, 0x1b, 0xa1, 0x35, 0xfe, +=090xe5, 0x85, 0x04, 0x9e, 0x05, 0x00, 0x1c, 0xe0, 0x28, 0x45, 0x00, 0x68, +=090x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, 0x14, 0x9e, 0x0e, 0x99, 0x05, 0x02, +=090x20, 0xe0, 0x98, 0x44, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, +=090x14, 0x9e, 0x0e, 0x9b, 0x05, 0x02, 0x24, 0xe0, 0x08, 0x44, 0x00, 0x68, +=090x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, 0x2a, 0x22, 0x11, 0x91, 0x0e, 0x9d, +=090x48, 0x5a, 0xfc, 0x6f, 0x0b, 0x84, 0x2a, 0x60, 0x11, 0x91, 0x0e, 0xb9, +=090xe8, 0x59, 0xfc, 0x6f, 0x0b, 0x84, 0x2a, 0x62, 0x11, 0x91, 0x0e, 0xbb, +=090x88, 0x59, 0xfc, 0x6f, 0x0b, 0x84, 0x0e, 0xbd, 0x04, 0x9c, 0x09, 0x00, +=090x24, 0xe0, 0x0a, 0x40, 0x88, 0xe0, 0xa5, 0x84, 0x04, 0xb7, 0xf8, 0x7a, +=090xf4, 0x6e, 0x1b, 0x80, 0x14, 0xb9, 0x0e, 0xb7, 0xa8, 0x7a, 0xf4, 0x6e, +=090x0b, 0x82, 0x14, 0xbb, 0x0e, 0xb9, 0x58, 0x7a, 0xf4, 0x6e, 0x0b, 0x82, +=090x14, 0xbd, 0x0e, 0xbb, 0x08, 0x7a, 0xf4, 0x6e, 0x0b, 0x82, 0x0e, 0xbd, +=090x86, 0x41, 0x30, 0x61, 0x1b, 0x9e, 0xd8, 0x4c, 0x08, 0xef, 0x78, 0x75, +=090x44, 0x6f, 0x46, 0x01, 0x04, 0xe0, 0xf0, 0x1e, 0x20, 0xe6, 0x0c, 0x0c, +=090x3c, 0xf2, 0x93, 0xdd, 0x4c, 0x00, 0x00, 0xfa, 0x08, 0x74, 0x24, 0x6f, +=090x11, 0x8f, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0x0c, 0x04, 0x7c, 0xfe, +=090x6b, 0x04, 0xf0, 0x1e, 0x60, 0xec, 0xb5, 0x0c, 0x10, 0xe0, 0x85, 0x0c, +=090x18, 0xe0, 0x79, 0x0c, 0x24, 0xe0, 0xa4, 0xda, 0x1e, 0x0b, 0x11, 0x81, +=090x0e, 0x7e, 0x0b, 0x96, 0x68, 0x79, 0xf4, 0xee, 0x0b, 0xa1, 0x15, 0x82, +=090x14, 0x18, 0x0b, 0x96, 0x88, 0x79, 0xf4, 0xee, 0x0b, 0xa1, 0xb5, 0x4c, +=090x00, 0xc0, 0x11, 0x01, 0x0b, 0x94, 0x98, 0x78, 0xf4, 0xee, 0x94, 0x18, +=090x0b, 0xa1, 0x05, 0x1e, 0x14, 0xc0, 0xbe, 0xbe, 0x75, 0x82, 0x0b, 0x14, +=090x1b, 0x92, 0xf8, 0x78, 0xf4, 0xee, 0x04, 0x0b, 0x0b, 0xa1, 0xa5, 0x4c, +=090x00, 0x40, 0xa0, 0x52, 0x00, 0xdc, 0xae, 0x7c, 0xab, 0x80, 0x77, 0x42, +=090x0b, 0x92, 0x15, 0x14, 0x1c, 0xfe, 0x58, 0x75, 0xf4, 0xee, 0x0b, 0x14, +=090x44, 0x60, 0x9b, 0x80, 0x88, 0x75, 0xf4, 0xee, 0xbb, 0x00, 0x0b, 0x92, +=090x08, 0x77, 0xf4, 0x6e, 0x1b, 0x96, 0x0b, 0xa1, 0x90, 0x56, 0x00, 0x1c, +=090xa0, 0x12, 0x88, 0xe4, 0xc8, 0x75, 0xf4, 0x6e, 0x0b, 0x96, 0xab, 0x00, +=090x01, 0x81, 0x01, 0x4c, 0x20, 0x60, 0x8b, 0xa1, 0x04, 0x7e, 0x76, 0x03, +=090x71, 0x7b, 0x34, 0xce, 0xac, 0xd8, 0x03, 0x8e, 0x00, 0x00, 0x70, 0xe7, +=090x0e, 0x89, 0x65, 0x88, 0x8b, 0xa3, 0x35, 0x08, 0x06, 0x02, 0x01, 0x00, +=090xc0, 0xcf, 0x58, 0x74, 0xf4, 0x6e, 0x0b, 0x96, 0x28, 0x73, 0xf4, 0x6e, +=090x8b, 0x80, 0x1b, 0x00, 0x0b, 0x96, 0x58, 0x73, 0xf4, 0xee, 0xd8, 0x49, +=090x00, 0xe8, 0x18, 0x74, 0xf4, 0x6e, 0x76, 0x03, 0x70, 0x7b, 0x34, 0xce, +=090x0b, 0xa1, 0x25, 0x84, 0x11, 0x01, 0x0b, 0x96, 0x48, 0x74, 0xf4, 0xee, +=090x0b, 0xa1, 0x80, 0x14, 0x04, 0x04, 0x80, 0x54, 0x00, 0xdc, 0x75, 0x81, +=090xc8, 0x70, 0xf4, 0x6e, 0x0b, 0x96, 0x58, 0x72, 0xf4, 0xee, 0xab, 0x80, +=090xac, 0xd8, 0x0a, 0xa4, 0x08, 0x71, 0xf4, 0xee, 0x04, 0x0b, 0x9b, 0x80, +=090x73, 0x80, 0x0b, 0x0e, 0x40, 0xe0, 0x98, 0x70, 0xf4, 0xee, 0xbb, 0x00, +=090xa4, 0x00, 0x80, 0xfb, 0x48, 0x70, 0xf4, 0xee, 0x1b, 0x00, 0x0b, 0x96, +=090x68, 0x49, 0x00, 0xe8, 0x1b, 0x00, 0x0b, 0x92, 0xc8, 0x47, 0x00, 0xe8, +=090xa8, 0x70, 0xf4, 0xee, 0x04, 0x09, 0xab, 0x80, 0xac, 0xd8, 0x9a, 0x80, +=090x9c, 0xda, 0x0b, 0x0e, 0x4c, 0xe0, 0x18, 0x6f, 0xf4, 0xee, 0x0b, 0x0e, +=090x48, 0x60, 0xbb, 0x80, 0xc8, 0x6e, 0xf4, 0xee, 0x8b, 0x00, 0x0b, 0x92, +=090x88, 0x6e, 0xf4, 0xee, 0x1b, 0x00, 0x0b, 0x90, 0xa8, 0x47, 0x00, 0xe8, +=090x1b, 0x00, 0x0b, 0x96, 0x08, 0x46, 0x00, 0xe8, 0xe8, 0x6e, 0xf4, 0xee, +=090xb4, 0x3e, 0x9b, 0x80, 0x84, 0xfc, 0x9c, 0xda, 0x1b, 0x96, 0xf8, 0x6d, +=090xf4, 0x6e, 0x0b, 0x90, 0x68, 0x44, 0x00, 0xe8, 0xe8, 0x6e, 0xf4, 0x6e, +=090x11, 0x81, 0x0b, 0xa1, 0x85, 0x8e, 0x11, 0x01, 0x0b, 0x96, 0xf8, 0x6d, +=090xf4, 0xee, 0x2a, 0x00, 0x00, 0x60, 0x0b, 0x94, 0x24, 0x7e, 0x1b, 0x92, +=090x34, 0x8b, 0xf8, 0x74, 0x18, 0xef, 0x58, 0x01, 0x01, 0x40, 0x00, 0x40, +=090x9b, 0x80, 0x0b, 0x16, 0x1b, 0x92, 0x78, 0x6d, 0xf4, 0xee, 0x0b, 0xa1, +=090x85, 0x82, 0x1a, 0xd8, 0x09, 0x0c, 0x20, 0xe0, 0x11, 0x82, 0x04, 0x09, +=090x0b, 0xa1, 0x1c, 0x58, 0x70, 0x00, 0x90, 0xc4, 0x0a, 0x80, 0x0c, 0xda, +=090x11, 0x01, 0x0b, 0x90, 0xe8, 0x6b, 0xf4, 0xee, 0x0b, 0xa1, 0xb5, 0x84, +=090x0b, 0x10, 0x1b, 0x92, 0x88, 0x6c, 0xf4, 0xee, 0x0b, 0xa1, 0xe5, 0x82, +=090x09, 0x0c, 0x20, 0xe0, 0x1a, 0xd8, 0x0b, 0xa1, 0x70, 0x0e, 0x98, 0x44, +=090x10, 0x00, 0x04, 0xec, 0x75, 0x5e, 0x10, 0xc0, 0x0c, 0xd8, 0x04, 0x89, +=090x0a, 0x80, 0x0c, 0xda, 0xf1, 0xb0, 0x0c, 0x0c, 0x7c, 0xf6, 0x93, 0xdd, +=090x0c, 0x04, 0x00, 0xfa, 0x6b, 0x00, 0x11, 0x81, 0xe8, 0x6a, 0xf4, 0xee, +=090x0b, 0xa1, 0x64, 0x0c, 0x7c, 0xdd, 0x0b, 0x8c, 0x0c, 0x0c, 0x00, 0xf2, +=090x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0x6b, 0x02, 0x7b, 0x80, +=090x08, 0x6a, 0xf4, 0xee, 0x8b, 0x00, 0x0b, 0x8e, 0x48, 0x69, 0xf4, 0x6e, +=090x1b, 0x8c, 0x0b, 0xa1, 0x70, 0x4c, 0x00, 0x1c, 0x8b, 0xa1, 0x70, 0x4c, +=090x00, 0xdc, 0x0b, 0x8c, 0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, +=090x4c, 0x04, 0x04, 0xfa, 0x6b, 0x02, 0x7b, 0x80, 0xa8, 0x68, 0xf4, 0xee, +=090x0b, 0xa1, 0x70, 0x4c, 0x00, 0x9c, 0x0b, 0x8c, 0x4c, 0x0c, 0x04, 0xf2, +=090x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x6b, 0x00, 0x21, 0x81, +=090x04, 0x18, 0x31, 0x83, 0x68, 0x53, 0xfc, 0xef, 0x0e, 0x98, 0x0c, 0x0c, +=090x00, 0xf2, 0x93, 0xdd, 0x18, 0xa9, 0x00, 0x00, 0x38, 0x90, 0x40, 0x00, +=090x08, 0x14, 0xb8, 0xe0, 0x80, 0x2c, 0x40, 0x00, 0xa8, 0x3a, 0xe8, 0xe0, +=090x08, 0x9f, 0x40, 0x00, 0x28, 0x28, 0xb0, 0xe0, 0x18, 0x72, 0x40, 0x00, +=090x88, 0x19, 0xc8, 0xe0, 0xe0, 0xbb, 0x40, 0x00, 0x08, 0x0c, 0xa4, 0xe0, +=090xa8, 0xe3, 0x40, 0x00, 0x28, 0x13, 0x90, 0xe0, 0xf0, 0xec, 0x40, 0x00, +=090x68, 0x0d, 0x8c, 0xe0, 0x48, 0xa8, 0x40, 0x00, 0xa8, 0x3c, 0xac, 0xe0, +=090x28, 0xe4, 0x40, 0x00, 0x08, 0x0e, 0x94, 0xe0, 0xb8, 0xe2, 0x40, 0x00, +=090x28, 0x3d, 0x90, 0xe0, 0x90, 0xa7, 0x40, 0x00, 0xc8, 0x13, 0xb0, 0xe0, +=090x18, 0xc1, 0x40, 0x00, 0xa8, 0x2a, 0xa4, 0xe0, 0xa8, 0x91, 0x40, 0x00, +=090x68, 0x2f, 0xbc, 0xe0, 0x88, 0xf1, 0x40, 0x00, 0x08, 0x1c, 0x88, 0xe0, +=090xd0, 0x8e, 0x40, 0x00, 0xa8, 0x19, 0xb8, 0xe0, 0x38, 0x82, 0x40, 0x00, +=090x28, 0x38, 0xbc, 0xe0, 0x88, 0xe0, 0x40, 0x00, 0xa8, 0x0e, 0x98, 0xe0, +=090xd8, 0xe4, 0x40, 0x00, 0x68, 0x32, 0x94, 0xe0, 0x18, 0xd7, 0x40, 0x00, +=090x28, 0x2d, 0x9c, 0xe0, 0x40, 0xe8, 0x40, 0x00, 0x28, 0x19, 0x94, 0xe0, +=090xa8, 0x78, 0x40, 0x00, 0x28, 0x18, 0xcc, 0xe0, 0xf0, 0x95, 0x40, 0x00, +=090x48, 0x34, 0xbc, 0xe0, 0xa8, 0xd2, 0x40, 0x00, 0x48, 0x16, 0xa0, 0xe0, +=090x18, 0x52, 0x40, 0x00, 0x68, 0x2b, 0xe0, 0xe0, 0x00, 0xb9, 0x00, 0x00, +=090x23, 0xdb, 0x00, 0x00, +}; + +static const u8 cut2_patch[] =3D { +=090x37, 0x00, 0x05, 0x00, 0x0c, 0x04, 0x3c, 0xfa, 0x86, 0x0e, 0x84, 0x60, +=090x06, 0x11, 0x84, 0xe0, 0x04, 0x1c, 0x06, 0x13, 0x88, 0xe1, 0x14, 0xa0, +=090x0d, 0xc2, 0x95, 0x80, 0x04, 0xa4, 0x0b, 0xa3, 0xb5, 0x88, 0x78, 0x6c, +=090x40, 0xef, 0x6b, 0x00, 0x46, 0x01, 0x84, 0xe0, 0x88, 0x53, 0x48, 0x6f, +=090x46, 0x15, 0x84, 0xe0, 0x6b, 0x25, 0xc6, 0x0d, 0x84, 0xe0, 0x95, 0x84, +=090x08, 0xa8, 0x4a, 0x00, 0xfc, 0xfb, 0x05, 0x84, 0x09, 0x12, 0x1c, 0xe0, +=090xa8, 0x46, 0x48, 0xef, 0x04, 0x1c, 0x11, 0x83, 0x16, 0x18, 0xc6, 0x04, +=090x84, 0xe0, 0x0e, 0x08, 0x01, 0x87, 0xf8, 0x6a, 0x40, 0xef, 0x46, 0x0c, +=090x84, 0xe0, 0x04, 0x1c, 0x11, 0x81, 0x16, 0x98, 0x0e, 0xa0, 0x06, 0x41, +=090x84, 0x60, 0xc6, 0x02, 0xd8, 0xe0, 0x04, 0x80, 0x08, 0x80, 0x06, 0x84, +=090x0c, 0x0c, 0x3c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x00, 0x80, 0xfa, +=090xc6, 0x40, 0x84, 0x60, 0x86, 0x43, 0xd8, 0xe0, 0x04, 0x80, 0x09, 0x00, +=090x18, 0xe1, 0x06, 0x84, 0x88, 0x41, 0x68, 0xef, 0x0c, 0x08, 0x80, 0xf2, +=090x48, 0x20, 0x68, 0xff, 0x1e, 0xc0, 0xb5, 0x00, 0x2c, 0xe0, 0xb4, 0x02, +=090x00, 0xfc, 0x15, 0x40, 0x2c, 0xe0, 0x19, 0x10, 0x31, 0x78, 0x01, 0x40, +=090x86, 0x04, 0x0c, 0xe0, 0x4a, 0x04, 0x00, 0x64, 0x31, 0x81, 0x30, 0x0a, +=090x04, 0x64, 0x4b, 0x82, 0x1b, 0x06, 0x3b, 0x8a, 0xc8, 0x44, 0xfc, 0x87, +=090x41, 0x50, 0x31, 0x78, 0x01, 0x40, 0xa1, 0xe1, 0xe6, 0x43, 0x99, 0x6c, +=090x10, 0xc0, 0x08, 0x42, 0x00, 0xf8, 0x00, 0x00, 0x03, 0xa9, 0x00, 0x00, +=090x30, 0x85, 0x40, 0x00, 0xa8, 0x16, 0xbc, 0xe0, 0xcc, 0xc1, 0x40, 0x00, +=090xa8, 0x35, 0x9c, 0xe0, 0xb0, 0xc9, 0x40, 0x00, 0x88, 0x37, 0x98, 0xe0, +=090x00, 0xb9, 0x00, 0x00, 0x49, 0xa7, 0x00, 0x00, +}; + +struct vd55g0_patch { +=09const u8 *bin; +=09unsigned int size; +=09/* As FWPATCH_REVISION reads it: major in the high byte */ +=09u16 version; +}; + +static const struct vd55g0_patch vd55g0_patch_cut1 =3D { +=09.bin =3D cut1_patch, +=09.size =3D ARRAY_SIZE(cut1_patch), +=09.version =3D 0x020b,=09/* 2.11 */ +}; + +static const struct vd55g0_patch vd55g0_patch_cut2 =3D { +=09.bin =3D cut2_patch, +=09.size =3D ARRAY_SIZE(cut2_patch), +=09.version =3D 0x0005,=09/* 0.5 */ +}; + +static const char * const vd55g0_test_pattern_menu[] =3D { +=09"Disabled", +=09"Solid", +=09"Colorbar", +=09"Gradbar", +=09"Hgrey", +=09"Vgrey", +=09"Dgrey", +=09"PN28", +}; + +static const s64 vd55g0_ev_bias_menu[] =3D { +=09-3000, -2500, -2000, -1500, -1000, -500, +=09 0, +=09 500, 1000, 1500, 2000, 2500, 3000, +}; + +static const char * const vd55g0_supply_name[] =3D { +=09"vcore", +=09"vddio", +=09"vana", +}; + +enum vd55g0_bin_mode { +=09VD55G0_BIN_MODE_NORMAL, +=09VD55G0_BIN_MODE_DIGITAL_X2, +}; + +enum vd55g0_gpio_modes { +=09VD55G0_GPIO_MODE_DISABLED, +=09VD55G0_GPIO_MODE_STROBE, +}; + +struct vd55g0_mode_info { +=09u32 width; +=09u32 height; +=09struct v4l2_rect crop; +}; + +struct vd55g0_fmt_desc { +=09u32 code; +=09u8 bpp; +=09u8 data_type; +}; + +static const struct vd55g0_fmt_desc vd55g0_supported_codes[] =3D { +=09{ +=09=09.code =3D MEDIA_BUS_FMT_Y8_1X8, +=09=09.bpp =3D 8, +=09=09.data_type =3D MIPI_CSI2_DT_RAW8, +=09}, +=09{ +=09=09.code =3D MEDIA_BUS_FMT_Y10_1X10, +=09=09.bpp =3D 10, +=09=09.data_type =3D MIPI_CSI2_DT_RAW10, +=09}, +}; + +static const struct vd55g0_mode_info vd55g0_mode_data[] =3D { +=09{ +=09=09.width =3D VD55G0_WIDTH, +=09=09.height =3D VD55G0_HEIGHT, +=09=09.crop =3D { +=09=09=09.left =3D 0, +=09=09=09.top =3D 0, +=09=09=09.width =3D VD55G0_WIDTH, +=09=09=09.height =3D VD55G0_HEIGHT, +=09=09}, +=09}, +=09{ +=09=09.width =3D 640, +=09=09.height =3D 600, +=09=09.crop =3D { +=09=09=09.left =3D 2, +=09=09=09.top =3D 2, +=09=09=09.width =3D 640, +=09=09=09.height =3D 600, +=09=09}, +=09}, +=09{ +=09=09.width =3D 640, +=09=09.height =3D 480, +=09=09.crop =3D { +=09=09=09.left =3D 2, +=09=09=09.top =3D 62, +=09=09=09.width =3D 640, +=09=09=09.height =3D 480, +=09=09}, +=09}, +=09{ +=09=09.width =3D 320, +=09=09.height =3D 240, +=09=09.crop =3D { +=09=09=09.left =3D 2, +=09=09=09.top =3D 62, +=09=09=09.width =3D 640, +=09=09=09.height =3D 480, +=09=09}, +=09}, +}; + +enum vd55g0_expo_state { +=09VD55G0_EXP_AUTO, +=09VD55G0_EXP_FREEZE, +=09VD55G0_EXP_MANUAL +}; + +struct vd55g0_dev { +=09struct i2c_client *i2c_client; +=09struct regmap *regmap; +=09struct v4l2_subdev sd; +=09struct media_pad pad; +=09struct regulator_bulk_data supplies[ARRAY_SIZE(vd55g0_supply_name)]; +=09struct gpio_desc *reset_gpio; +=09struct clk *xclk; +=09u32 clk_freq; +=09u16 oif_ctrl; +=09u64 link_freq; +=09u16 revision; +=09u32 leds[VD55G0_NB_GPIOS]; +=09unsigned int nb_leds; +=09/* Its lock is also the subdev state lock and protects all below */ +=09struct v4l2_ctrl_handler ctrl_handler; +=09struct v4l2_ctrl *vblank_ctrl; +=09struct v4l2_ctrl *hblank_ctrl; +=09/* The flip cluster */ +=09struct { +=09=09struct v4l2_ctrl *hflip_ctrl; +=09=09struct v4l2_ctrl *vflip_ctrl; +=09}; +=09struct v4l2_ctrl *pattern_ctrl; +=09/* The auto exposure cluster, the auto control first */ +=09struct { +=09=09struct v4l2_ctrl *ae_ctrl; +=09=09struct v4l2_ctrl *expo_ctrl; +=09=09struct v4l2_ctrl *again_ctrl; +=09=09struct v4l2_ctrl *dgain_ctrl; +=09}; +=09struct v4l2_ctrl *ae_lock_ctrl; +=09/* What the last stream applied, for the next one to start from */ +=09struct { +=09=09u16 expo; +=09=09u16 digital_gain; +=09=09u8 analog_gain; +=09} cold_start; +}; + +static inline struct vd55g0_dev *to_vd55g0_dev(struct v4l2_subdev *sd) +{ +=09return container_of(sd, struct vd55g0_dev, sd); +} + +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) +{ +=09return &container_of(ctrl->handler, struct vd55g0_dev, +=09=09ctrl_handler)->sd; +} + +static u8 get_bpp_by_code(__u32 code) +{ +=09for (unsigned int i =3D 0; i < ARRAY_SIZE(vd55g0_supported_codes); i++)= { +=09=09if (vd55g0_supported_codes[i].code =3D=3D code) +=09=09=09return vd55g0_supported_codes[i].bpp; +=09} +=09/* Should never happen */ +=09WARN(1, "Unsupported code %d. default to 8 bpp\n", code); +=09return 8; +} + +static u8 get_data_type_by_code(__u32 code) +{ +=09for (unsigned int i =3D 0; i < ARRAY_SIZE(vd55g0_supported_codes); i++)= { +=09=09if (vd55g0_supported_codes[i].code =3D=3D code) +=09=09=09return vd55g0_supported_codes[i].data_type; +=09} +=09/* Should never happen */ +=09WARN(1, "Unsupported code %d. default to MIPI_CSI2_DT_RAW8 data type\n"= , +=09 code); +=09return MIPI_CSI2_DT_RAW8; +} + +#define vd55g0_read(sensor, reg, val, err) \ +=09cci_read((sensor)->regmap, reg, val, err) + +#define vd55g0_write(sensor, reg, val, err) \ +=09cci_write((sensor)->regmap, reg, val, err) + +static unsigned int get_chunk_size(struct vd55g0_dev *sensor) +{ +=09const struct i2c_adapter_quirks *quirks =3D +=09=09sensor->i2c_client->adapter->quirks; +=09unsigned int max_write_len =3D VD55G0_WRITE_MULTIPLE_CHUNK_MAX; + +=09/* Each write also carries the two address bytes */ +=09if (quirks && quirks->max_write_len > 2) +=09=09max_write_len =3D min(max_write_len, quirks->max_write_len - 2U); + +=09return max_write_len; +} + +static int vd55g0_write_array(struct vd55g0_dev *sensor, u32 reg, +=09=09=09 unsigned int nb, const u8 *array) +{ +=09const unsigned int chunk_size =3D get_chunk_size(sensor); +=09unsigned int addr =3D CCI_REG_ADDR(reg); +=09unsigned int sz; +=09int ret; + +=09while (nb) { +=09=09sz =3D min(nb, chunk_size); +=09=09ret =3D regmap_bulk_write(sensor->regmap, addr, array, sz); +=09=09if (ret < 0) +=09=09=09return ret; +=09=09nb -=3D sz; +=09=09addr +=3D sz; +=09=09array +=3D sz; +=09} + +=09return 0; +} + +static int vd55g0_poll_reg(struct vd55g0_dev *sensor, u32 reg, u8 poll_val= , +=09=09=09 unsigned int timeout_ms) +{ +=09unsigned int val =3D 0; + +=09return regmap_read_poll_timeout(sensor->regmap, CCI_REG_ADDR(reg), val, +=09=09=09=09=09(val =3D=3D poll_val), 10 * USEC_PER_MSEC, +=09=09=09=09=09timeout_ms * USEC_PER_MSEC); +} + +static int vd55g0_wait_state(struct vd55g0_dev *sensor, int state, +=09=09=09 unsigned int timeout_ms) +{ +=09return vd55g0_poll_reg(sensor, VD55G0_REG_SYSTEM_FSM, state, +=09=09=09 timeout_ms); +} + +/* The MIPI bus is double data rate; 32 bits, as the range is checked */ +static u32 vd55g0_mipi_rate(struct vd55g0_dev *sensor) +{ +=09return sensor->link_freq * 2; +} + +static u32 vd55g0_pixel_rate(struct vd55g0_dev *sensor) +{ +=09u32 mipi_rate =3D vd55g0_mipi_rate(sensor); + +=09return mipi_rate / (mipi_rate <=3D VD55G0_MIPI_RATE_FAST ? 6 : 8); +} + +static unsigned int vd55g0_line_length(struct vd55g0_dev *sensor) +{ +=09return vd55g0_mipi_rate(sensor) <=3D VD55G0_MIPI_RATE_FAST ? +=09 VD55G0_LINE_LENGTH_SLOW : VD55G0_LINE_LENGTH_FAST; +} + +static int vd55g0_check_clock_tree(struct vd55g0_dev *sensor) +{ +=09struct device *dev =3D &sensor->i2c_client->dev; + +=09if (sensor->clk_freq < VD55G0_XCLK_FREQ_MIN || +=09 sensor->clk_freq > VD55G0_XCLK_FREQ_MAX) { +=09=09dev_err(dev, +=09=09=09"Only %lu Hz-%lu Hz clock range supported. Provided %u Hz\n", +=09=09=09VD55G0_XCLK_FREQ_MIN, VD55G0_XCLK_FREQ_MAX, +=09=09=09sensor->clk_freq); +=09=09return -EINVAL; +=09} + +=09/* +=09 * The MIPI rate is an integer multiple of the input clock. The sensor +=09 * would round any other rate down (UM2829 13.6), so it is refused +=09 * rather than used. +=09 */ +=09if (sensor->link_freq < VD55G0_MIPI_RATE_MIN / 2 || +=09 sensor->link_freq > VD55G0_MIPI_RATE_MAX / 2) { +=09=09dev_err(dev, +=09=09=09"Only %luMbps-%luMbps data rate range supported. Provided link fr= equency %llu Hz\n", +=09=09=09VD55G0_MIPI_RATE_MIN / MEGA, +=09=09=09VD55G0_MIPI_RATE_MAX / MEGA, sensor->link_freq); +=09=09return -EINVAL; +=09} +=09if (vd55g0_mipi_rate(sensor) % sensor->clk_freq) { +=09=09dev_err(dev, +=09=09=09"Link frequency %llu Hz is not a multiple of half the %u Hz input= clock\n", +=09=09=09sensor->link_freq, sensor->clk_freq); +=09=09return -EINVAL; +=09} + +=09return 0; +} + +static int vd55g0_update_gpio_mode(struct vd55g0_dev *sensor, u32 mode, +=09=09=09=09 unsigned int gpio) +{ +=09static const u8 index2val[] =3D { 0x01, 0x02 }; + +=09return vd55g0_write(sensor, VD55G0_REG_GPIO_0_CTRL + gpio, +=09=09=09 index2val[mode], NULL); +} + +static int vd55g0_set_gpios_array(struct vd55g0_dev *sensor, u32 *array, +=09=09=09=09 unsigned int size, +=09=09=09=09 enum vd55g0_gpio_modes mode) +{ +=09int ret; + +=09for (unsigned int i =3D 0; i < size; i++) { +=09=09if (array[i] =3D=3D ~0) +=09=09=09break; +=09=09ret =3D vd55g0_update_gpio_mode(sensor, mode, array[i]); +=09=09if (ret) +=09=09=09return ret; +=09} + +=09return 0; +} + +static int vd55g0_apply_exposure_mode(struct vd55g0_dev *sensor, bool is_a= uto, +=09=09=09=09 bool locked) +{ +=09enum vd55g0_expo_state exp =3D VD55G0_EXP_MANUAL; + +=09if (is_auto) +=09=09exp =3D locked ? VD55G0_EXP_FREEZE : VD55G0_EXP_AUTO; + +=09return vd55g0_write(sensor, VD55G0_REG_EXP_MODE, exp, NULL); +} + +static int vd55g0_get_regulators(struct vd55g0_dev *sensor) +{ +=09struct device *dev =3D &sensor->i2c_client->dev; + +=09for (unsigned int i =3D 0; i < ARRAY_SIZE(vd55g0_supply_name); i++) +=09=09sensor->supplies[i].supply =3D vd55g0_supply_name[i]; + +=09return devm_regulator_bulk_get(dev, ARRAY_SIZE(vd55g0_supply_name), +=09=09=09=09 sensor->supplies); +} + +static int vd55g0_apply_patgen(struct vd55g0_dev *sensor, u32 index) +{ +=09static const u8 index2val[] =3D { +=09=090x0, 0x0, 0x8, 0x10, 0x20, 0x21, 0x22, 0x28 +=09}; +=09u32 pattern =3D index2val[index]; +=09u32 reg =3D pattern << VD55G0_PATGEN_TYPE_SHIFT; +=09u8 darkcal =3D VD55G0_DARKCAL_AUTO; +=09u8 duster =3D VD55G0_DUSTER_RING_ENABLE | VD55G0_DUSTER_DYN_ENABLE | +=09=09 VD55G0_DUSTER_ENABLE; +=09int ret =3D 0; + +=09if (index) { +=09=09reg |=3D VD55G0_PATGEN_ENABLE; +=09=09/* +=09=09 * Take care of dark calibaration and duster to not mess up the +=09=09 * test pattern output. +=09=09 */ +=09=09darkcal =3D VD55G0_DARKCAL_BYPASS; +=09=09duster =3D VD55G0_DUSTER_DISABLE; +=09} + +=09vd55g0_write(sensor, VD55G0_REG_DARKCAL_CTRL, darkcal, &ret); +=09vd55g0_write(sensor, VD55G0_REG_DUSTER_CTRL, duster, &ret); +=09if (ret) +=09=09return ret; + +=09return vd55g0_write(sensor, VD55G0_REG_PATGEN_CTRL, reg, NULL); +} + +static int vd55g0_apply_flash(struct vd55g0_dev *sensor, u32 led_mode) +{ +=09enum vd55g0_gpio_modes mode =3D led_mode =3D=3D V4L2_FLASH_LED_MODE_NON= E ? +=09=09=09=09 VD55G0_GPIO_MODE_DISABLED : +=09=09=09=09 VD55G0_GPIO_MODE_STROBE; + +=09return vd55g0_set_gpios_array(sensor, sensor->leds, +=09=09=09=09 ARRAY_SIZE(sensor->leds), mode); +} + +static int vd55g0_apply_exposure_target(struct vd55g0_dev *sensor, u32 ind= ex) +{ +=09/* +=09 * Find auto exposure target with: default target exposure * 2^EV, +=09 * the default being the firmware's 27, at index 6. +=09 */ +=09static const unsigned int index2exposure_target[] =3D { +=09=093, 5, 7, 10, 14, 19, 27, 38, 54, 76, 108, 153, 216, +=09}; + +=09return vd55g0_write(sensor, VD55G0_REG_AE_TARGET_PERCENTAGE, +=09=09=09 index2exposure_target[index], NULL); +} + +static void vd55g0_apply_reset(struct vd55g0_dev *sensor) +{ +=09gpiod_set_value_cansleep(sensor->reset_gpio, 0); +=09usleep_range(5000, 10000); +=09gpiod_set_value_cansleep(sensor->reset_gpio, 1); +=09usleep_range(5000, 10000); +=09gpiod_set_value_cansleep(sensor->reset_gpio, 0); +=09usleep_range(5000, 10000); +} + +static void vd55g0_fill_framefmt(const struct vd55g0_mode_info *mode, +=09=09=09=09 struct v4l2_mbus_framefmt *fmt, u32 code) +{ +=09fmt->code =3D code; +=09fmt->width =3D mode->width; +=09fmt->height =3D mode->height; +=09fmt->colorspace =3D V4L2_COLORSPACE_RAW; +=09fmt->field =3D V4L2_FIELD_NONE; +=09fmt->ycbcr_enc =3D V4L2_YCBCR_ENC_DEFAULT; +=09fmt->quantization =3D V4L2_QUANTIZATION_DEFAULT; +=09fmt->xfer_func =3D V4L2_XFER_FUNC_DEFAULT; +} + +static const struct vd55g0_mode_info * +vd55g0_try_fmt(struct v4l2_mbus_framefmt *fmt) +{ +=09const struct vd55g0_mode_info *mode; +=09u32 code =3D vd55g0_supported_codes[0].code; + +=09for (unsigned int i =3D 0; i < ARRAY_SIZE(vd55g0_supported_codes); i++)= { +=09=09if (vd55g0_supported_codes[i].code =3D=3D fmt->code) +=09=09=09code =3D fmt->code; +=09} + +=09mode =3D v4l2_find_nearest_size(vd55g0_mode_data, +=09=09=09=09 ARRAY_SIZE(vd55g0_mode_data), width, +=09=09=09=09 height, fmt->width, fmt->height); +=09vd55g0_fill_framefmt(mode, fmt, code); + +=09return mode; +} + +static int vd55g0_apply_cold_start(struct vd55g0_dev *sensor) +{ +=09int ret =3D 0; + +=09vd55g0_write(sensor, VD55G0_REG_AE_COLDSTART_COARSE_EXPOSURE, +=09=09 sensor->cold_start.expo, &ret); +=09vd55g0_write(sensor, VD55G0_REG_AE_COLDSTART_ANALOG_GAIN, +=09=09 sensor->cold_start.analog_gain, &ret); +=09vd55g0_write(sensor, VD55G0_REG_AE_COLDSTART_DIGITAL_GAIN, +=09=09 sensor->cold_start.digital_gain, &ret); + +=09return ret; +} + +static int vd55g0_apply_frame_format(struct vd55g0_dev *sensor, +=09=09=09=09 const struct v4l2_mbus_framefmt *fmt, +=09=09=09=09 const struct v4l2_rect *crop) +{ +=09enum vd55g0_bin_mode bin_mode =3D fmt->width < crop->width ? +=09=09=09=09=09VD55G0_BIN_MODE_DIGITAL_X2 : +=09=09=09=09=09VD55G0_BIN_MODE_NORMAL; +=09int ret =3D 0; + +=09vd55g0_write(sensor, VD55G0_REG_FORMAT_CTRL, get_bpp_by_code(fmt->code)= , +=09=09 &ret); +=09vd55g0_write(sensor, VD55G0_REG_OIF_IMG_CTRL, +=09=09 get_data_type_by_code(fmt->code), &ret); +=09vd55g0_write(sensor, VD55G0_REG_READOUT_CTRL, bin_mode, &ret); +=09vd55g0_write(sensor, VD55G0_REG_ROI_X_START, crop->left, &ret); +=09vd55g0_write(sensor, VD55G0_REG_ROI_X_END, +=09=09 crop->left + crop->width - 1, &ret); +=09vd55g0_write(sensor, VD55G0_REG_ROI_Y_START, crop->top, &ret); +=09vd55g0_write(sensor, VD55G0_REG_ROI_Y_END, +=09=09 crop->top + crop->height - 1, &ret); + +=09/* +=09 * Use the same auto exposure crop as the image crop, performing auto +=09 * exposure computation only on image boundaries. +=09 */ +=09vd55g0_write(sensor, VD55G0_REG_AE_ROI_START_H, crop->left, &ret); +=09vd55g0_write(sensor, VD55G0_REG_AE_ROI_END_H, +=09=09 crop->left + crop->width - 1, &ret); +=09vd55g0_write(sensor, VD55G0_REG_AE_ROI_START_V, crop->top, &ret); +=09vd55g0_write(sensor, VD55G0_REG_AE_ROI_END_V, +=09=09 crop->top + crop->height - 1, &ret); + +=09return ret; +} + +/* GPIOs in input (disabled) by default; the LED control may strobe some *= / +static int vd55g0_disable_gpios(struct vd55g0_dev *sensor) +{ +=09int ret; + +=09for (unsigned int i =3D 0; i < VD55G0_NB_GPIOS; i++) { +=09=09ret =3D vd55g0_update_gpio_mode(sensor, +=09=09=09=09=09 VD55G0_GPIO_MODE_DISABLED, i); +=09=09if (ret) +=09=09=09return ret; +=09} + +=09return 0; +} + +static int vd55g0_stream_enable(struct vd55g0_dev *sensor, +=09=09=09=09struct v4l2_subdev_state *state) +{ +=09const struct v4l2_mbus_framefmt *fmt =3D +=09=09v4l2_subdev_state_get_format(state, 0); +=09const struct v4l2_rect *crop =3D v4l2_subdev_state_get_crop(state, 0); +=09struct device *dev =3D &sensor->i2c_client->dev; +=09int ret; + +=09ret =3D pm_runtime_resume_and_get(dev); +=09if (ret < 0) +=09=09return ret; + +=09ret =3D vd55g0_disable_gpios(sensor); +=09if (ret) +=09=09goto err_rpm_put; + +=09ret =3D vd55g0_apply_frame_format(sensor, fmt, crop); +=09if (ret) +=09=09goto err_rpm_put; + +=09ret =3D vd55g0_apply_cold_start(sensor); +=09if (ret) +=09=09goto err_rpm_put; + +=09ret =3D __v4l2_ctrl_handler_setup(&sensor->ctrl_handler); +=09if (ret) +=09=09goto err_rpm_put; + +=09/* HBLANK is read-only, so s_ctrl leaves the line length to us */ +=09ret =3D vd55g0_write(sensor, VD55G0_REG_LINE_LENGTH, +=09=09=09 crop->width + sensor->hblank_ctrl->cur.val, NULL); +=09if (ret) +=09=09goto err_rpm_put; + +=09ret =3D vd55g0_write(sensor, VD55G0_REG_SW_STBY, +=09=09=09 VD55G0_SW_STBY_START_STREAM, NULL); +=09if (ret) +=09=09goto err_rpm_put; + +=09ret =3D vd55g0_poll_reg(sensor, VD55G0_REG_SW_STBY, 0, VD55G0_TIMEOUT_M= S); +=09if (ret) +=09=09goto err_rpm_put; + +=09ret =3D vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_STREAMING, +=09=09=09=09VD55G0_TIMEOUT_MS); +=09if (ret) +=09=09goto err_rpm_put; + +=09return 0; + +err_rpm_put: +=09pm_runtime_put(dev); +=09return ret; +} + +static void vd55g0_save_exposure(struct vd55g0_dev *sensor) +{ +=09u64 val; + +=09/* On a read error, keep what the previous stream left */ +=09if (!vd55g0_read(sensor, VD55G0_REG_APPLIED_COARSE_EXPOSURE, &val, +=09=09=09 NULL)) +=09=09sensor->cold_start.expo =3D val; +=09if (!vd55g0_read(sensor, VD55G0_REG_APPLIED_DIGITAL_GAIN, &val, NULL)) +=09=09sensor->cold_start.digital_gain =3D val; +=09if (!vd55g0_read(sensor, VD55G0_REG_APPLIED_ANALOG_GAIN, &val, NULL)) +=09=09sensor->cold_start.analog_gain =3D val; +} + +static void vd55g0_stream_disable(struct vd55g0_dev *sensor) +{ +=09struct i2c_client *client =3D v4l2_get_subdevdata(&sensor->sd); +=09int ret; + +=09/* Keep exposure values for next cold start boot */ +=09vd55g0_save_exposure(sensor); + +=09ret =3D vd55g0_write(sensor, VD55G0_REG_STREAMING, +=09=09=09 VD55G0_STREAMING_STOP_STREAM, NULL); +=09if (ret) +=09=09goto err_str_dis; + +=09ret =3D vd55g0_poll_reg(sensor, VD55G0_REG_STREAMING, 0, 2000); +=09if (ret) +=09=09goto err_str_dis; + +=09ret =3D vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_SW_STBY, +=09=09=09=09VD55G0_TIMEOUT_MS); + +err_str_dis: +=09if (ret) +=09=09dev_err(&client->dev, "failed to stop streaming: %d\n", ret); +=09pm_runtime_put_autosuspend(&client->dev); +} + +static int vd55g0_tx_from_ep(struct vd55g0_dev *sensor, +=09=09=09 struct fwnode_handle *handle) +{ +=09struct i2c_client *client =3D sensor->i2c_client; +=09struct v4l2_fwnode_endpoint ep =3D { .bus_type =3D V4L2_MBUS_CSI2_DPHY = }; +=09int ret; + +=09ret =3D v4l2_fwnode_endpoint_alloc_parse(handle, &ep); +=09if (ret) +=09=09return ret; + +=09/* The sensor has a single data lane */ +=09if (ep.bus.mipi_csi2.num_data_lanes !=3D 1) { +=09=09dev_err(&client->dev, "only one data lane is supported, found %u\n", +=09=09=09ep.bus.mipi_csi2.num_data_lanes); +=09=09goto error_ep; +=09} + +=09if (ep.bus.mipi_csi2.clock_lane !=3D 0) { +=09=09dev_err(&client->dev, "clock lane must be lane 0\n"); +=09=09goto error_ep; +=09} + +=09/* Only the two polarity bits: the rest of OIF_CTRL is reserved */ +=09sensor->oif_ctrl =3D (ep.bus.mipi_csi2.lane_polarities[0] << 3) | +=09=09=09 (ep.bus.mipi_csi2.lane_polarities[1] << 6); + +=09if (ep.nr_of_link_frequencies !=3D 1) { +=09=09dev_err(&client->dev, "one link frequency is needed, found %u\n", +=09=09=09ep.nr_of_link_frequencies); +=09=09goto error_ep; +=09} +=09sensor->link_freq =3D ep.link_frequencies[0]; + +=09v4l2_fwnode_endpoint_free(&ep); + +=09return 0; + +error_ep: +=09v4l2_fwnode_endpoint_free(&ep); + +=09return -EINVAL; +} + +static int vd55g0_patch(struct vd55g0_dev *sensor) +{ +=09struct i2c_client *client =3D sensor->i2c_client; +=09const struct vd55g0_patch *patch; +=09u64 patch_version; +=09int ret; + +=09/* Choose appropriate patch for sensor revision */ +=09if (sensor->revision =3D=3D VD55G0_REVISION_CUT1) +=09=09patch =3D &vd55g0_patch_cut1; +=09else if (sensor->revision =3D=3D VD55G0_REVISION_CUT2) +=09=09patch =3D &vd55g0_patch_cut2; +=09else +=09=09return -EINVAL; + +=09/* Write patch */ +=09ret =3D vd55g0_write_array(sensor, VD55G0_REG_FWPATCH_START_ADDR, +=09=09=09=09 patch->size, patch->bin); +=09if (ret) +=09=09return ret; + +=09ret =3D vd55g0_write(sensor, VD55G0_REG_BOOT, +=09=09=09 VD55G0_BOOT_PATCH_SETUP, NULL); +=09if (ret) +=09=09return ret; + +=09ret =3D vd55g0_poll_reg(sensor, VD55G0_REG_BOOT, 0, VD55G0_TIMEOUT_MS); +=09if (ret) +=09=09return ret; + +=09/* Read back patch version */ +=09ret =3D vd55g0_read(sensor, VD55G0_REG_FWPATCH_REVISION, &patch_version= , +=09=09=09 NULL); +=09if (ret) +=09=09return ret; + +=09if (patch_version !=3D patch->version) { +=09=09dev_err(&client->dev, +=09=09=09"bad patch version expected %u.%u got %llu.%llu\n", +=09=09=09patch->version >> 8, patch->version & 0xff, +=09=09=09patch_version >> 8, patch_version & 0xff); +=09=09return -ENODEV; +=09} +=09dev_dbg(&client->dev, "patch %llu.%llu applied\n", +=09=09patch_version >> 8, patch_version & 0xff); + +=09return 0; +} + +static int vd55g0_boot(struct vd55g0_dev *sensor) +{ +=09int ret; + +=09ret =3D vd55g0_write(sensor, VD55G0_REG_BOOT, VD55G0_BOOT_BOOT, NULL); +=09if (ret) +=09=09return ret; + +=09ret =3D vd55g0_poll_reg(sensor, VD55G0_REG_BOOT, 0, VD55G0_TIMEOUT_MS); +=09if (ret) +=09=09return ret; + +=09ret =3D vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_SW_STBY, +=09=09=09=09VD55G0_TIMEOUT_MS); +=09if (ret) +=09=09return ret; + +=09return 0; +} + +static int vd55g0_configure(struct vd55g0_dev *sensor) +{ +=09int ret =3D 0; + +=09/* +=09 * PLL_PREDIV and PLL_MULT are not accessible. We rely on the firmware +=09 * to set the correct multiplier for the clock. Hence we don't do +=09 * anything more here. +=09 */ +=09vd55g0_write(sensor, VD55G0_REG_EXT_CLOCK, sensor->clk_freq, &ret); + +=09vd55g0_write(sensor, VD55G0_REG_OIF_CTRL, sensor->oif_ctrl, &ret); +=09/* The status lines are not exposed, so do not send them, as vd55g1 */ +=09vd55g0_write(sensor, VD55G0_REG_ISL_ENABLE, 0, &ret); +=09vd55g0_write(sensor, VD55G0_REG_CLK_PLL_MIPI, vd55g0_mipi_rate(sensor), +=09=09 &ret); + +=09return ret; +} + +/* Called with the control handler's lock held, which is the state lock */ +static void vd55g0_grab_stream_ctrls(struct vd55g0_dev *sensor, bool grab) +{ +=09__v4l2_ctrl_grab(sensor->vflip_ctrl, grab); +=09__v4l2_ctrl_grab(sensor->hflip_ctrl, grab); +=09__v4l2_ctrl_grab(sensor->pattern_ctrl, grab); +} + +static int vd55g0_enable_streams(struct v4l2_subdev *sd, +=09=09=09=09 struct v4l2_subdev_state *state, u32 pad, +=09=09=09=09 u64 streams_mask) +{ +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(sd); +=09int ret; + +=09ret =3D vd55g0_stream_enable(sensor, state); +=09if (ret) +=09=09return ret; + +=09vd55g0_grab_stream_ctrls(sensor, true); + +=09return 0; +} + +static int vd55g0_disable_streams(struct v4l2_subdev *sd, +=09=09=09=09 struct v4l2_subdev_state *state, u32 pad, +=09=09=09=09 u64 streams_mask) +{ +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(sd); + +=09/* Powered down either way, so report success as call_s_stream() does *= / +=09vd55g0_stream_disable(sensor); + +=09vd55g0_grab_stream_ctrls(sensor, false); + +=09return 0; +} + +static int vd55g0_get_selection(struct v4l2_subdev *sd, +=09=09=09=09const struct v4l2_subdev_client_info *ci, +=09=09=09=09struct v4l2_subdev_state *sd_state, +=09=09=09=09struct v4l2_subdev_selection *sel) +{ +=09switch (sel->target) { +=09case V4L2_SEL_TGT_CROP: +=09=09sel->r =3D *v4l2_subdev_state_get_crop(sd_state, 0); +=09=09return 0; +=09case V4L2_SEL_TGT_NATIVE_SIZE: +=09case V4L2_SEL_TGT_CROP_DEFAULT: +=09case V4L2_SEL_TGT_CROP_BOUNDS: +=09=09sel->r.top =3D 0; +=09=09sel->r.left =3D 0; +=09=09sel->r.width =3D VD55G0_WIDTH; +=09=09sel->r.height =3D VD55G0_HEIGHT; +=09=09return 0; +=09} + +=09return -EINVAL; +} + +static int vd55g0_enum_mbus_code(struct v4l2_subdev *sd, +=09=09=09=09 struct v4l2_subdev_state *sd_state, +=09=09=09=09 struct v4l2_subdev_mbus_code_enum *code) +{ +=09if (code->index >=3D ARRAY_SIZE(vd55g0_supported_codes)) +=09=09return -EINVAL; + +=09code->code =3D vd55g0_supported_codes[code->index].code; + +=09return 0; +} + +/* Max exposure follows the frame length */ +static int vd55g0_update_expo_range(struct vd55g0_dev *sensor, +=09=09=09=09 unsigned int frame_length) +{ +=09return __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, +=09=09=09=09=09frame_length - VD55G0_EXPO_MAX_TERM, 1, +=09=09=09=09=09VD55G0_EXPO_DEF); +} + +/* Blanking counts from the analogue crop, as in vd55g1 */ +static int vd55g0_update_blanking(struct vd55g0_dev *sensor, +=09=09=09=09 const struct v4l2_rect *crop) +{ +=09unsigned int vblank_def =3D VD55G0_FRAME_LENGTH_DEF - crop->height; +=09unsigned int hblank =3D vd55g0_line_length(sensor) - crop->width; +=09int ret; + +=09ret =3D __v4l2_ctrl_modify_range(sensor->vblank_ctrl, +=09=09=09=09 VD55G0_MIN_FRAME_LENGTH - crop->height, +=09=09=09=09 0xffff - crop->height, 1, vblank_def); +=09if (ret) +=09=09return ret; + +=09/* The range change may keep the old vblank; set the default */ +=09ret =3D __v4l2_ctrl_s_ctrl(sensor->vblank_ctrl, vblank_def); +=09if (ret) +=09=09return ret; + +=09/* Also when vblank kept its value and s_ctrl was not called */ +=09ret =3D vd55g0_update_expo_range(sensor, crop->height + vblank_def); +=09if (ret) +=09=09return ret; + +=09return __v4l2_ctrl_modify_range(sensor->hblank_ctrl, hblank, hblank, 1, +=09=09=09=09=09hblank); +} + +static int vd55g0_set_fmt(struct v4l2_subdev *sd, +=09=09=09 const struct v4l2_subdev_client_info *ci, +=09=09=09 struct v4l2_subdev_state *sd_state, +=09=09=09 struct v4l2_subdev_format *format) +{ +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(sd); +=09const struct vd55g0_mode_info *mode; +=09struct v4l2_rect *crop; +=09bool crop_changed; + +=09/* The mode cannot change under a running stream */ +=09if (format->which =3D=3D V4L2_SUBDEV_FORMAT_ACTIVE && +=09 media_entity_is_streaming(&sd->entity)) +=09=09return -EBUSY; + +=09mode =3D vd55g0_try_fmt(&format->format); +=09*v4l2_subdev_state_get_format(sd_state, 0) =3D format->format; + +=09crop =3D v4l2_subdev_state_get_crop(sd_state, 0); +=09crop_changed =3D !v4l2_rect_equal(crop, &mode->crop); +=09*crop =3D mode->crop; + +=09/* The code alone leaves the blanking as the user set it */ +=09if (format->which !=3D V4L2_SUBDEV_FORMAT_ACTIVE || !crop_changed) +=09=09return 0; + +=09return vd55g0_update_blanking(sensor, crop); +} + +static int vd55g0_init_state(struct v4l2_subdev *sd, +=09=09=09 struct v4l2_subdev_state *sd_state) +{ +=09struct v4l2_subdev_format fmt =3D { 0 }; + +=09vd55g0_fill_framefmt(&vd55g0_mode_data[VD55G0_DEFAULT_MODE], +=09=09=09 &fmt.format, VD55G0_MEDIA_BUS_FMT_DEF); + +=09return vd55g0_set_fmt(sd, NULL, sd_state, &fmt); +} + +static int vd55g0_enum_frame_size(struct v4l2_subdev *sd, +=09=09=09=09 struct v4l2_subdev_state *sd_state, +=09=09=09=09 struct v4l2_subdev_frame_size_enum *fse) +{ +=09unsigned int i; + +=09if (fse->index >=3D ARRAY_SIZE(vd55g0_mode_data)) +=09=09return -EINVAL; + +=09for (i =3D 0; i < ARRAY_SIZE(vd55g0_supported_codes); i++) +=09=09if (vd55g0_supported_codes[i].code =3D=3D fse->code) +=09=09=09break; +=09if (i =3D=3D ARRAY_SIZE(vd55g0_supported_codes)) +=09=09return -EINVAL; + +=09fse->min_width =3D vd55g0_mode_data[fse->index].width; +=09fse->max_width =3D fse->min_width; +=09fse->min_height =3D vd55g0_mode_data[fse->index].height; +=09fse->max_height =3D fse->min_height; + +=09return 0; +} + +static const struct v4l2_subdev_video_ops vd55g0_video_ops =3D { +=09.s_stream =3D v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops vd55g0_pad_ops =3D { +=09.enum_mbus_code =3D vd55g0_enum_mbus_code, +=09.get_fmt =3D v4l2_subdev_get_fmt, +=09.set_fmt =3D vd55g0_set_fmt, +=09.enable_streams =3D vd55g0_enable_streams, +=09.disable_streams =3D vd55g0_disable_streams, +=09.get_selection =3D vd55g0_get_selection, +=09.enum_frame_size =3D vd55g0_enum_frame_size, +}; + +static const struct v4l2_subdev_ops vd55g0_subdev_ops =3D { +=09.video =3D &vd55g0_video_ops, +=09.pad =3D &vd55g0_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops vd55g0_internal_ops =3D { +=09.init_state =3D vd55g0_init_state, +}; + +/* + * The manual values only in manual mode, written before the mode so that = a + * switch to manual starts from them. On that switch all three are written= : + * under auto exposure the sensor never had them. + */ +static int vd55g0_update_expo_cluster(struct vd55g0_dev *sensor) +{ +=09bool is_auto =3D sensor->ae_ctrl->val =3D=3D V4L2_EXPOSURE_AUTO; +=09bool all =3D sensor->ae_ctrl->is_new; +=09int ret =3D 0; + +=09if (!is_auto) { +=09=09/* A range change under auto exposure did not clamp it */ +=09=09sensor->expo_ctrl->val =3D min(sensor->expo_ctrl->val, +=09=09=09=09=09 sensor->expo_ctrl->maximum); +=09=09if (all || sensor->expo_ctrl->is_new) +=09=09=09vd55g0_write(sensor, VD55G0_REG_MANUAL_COARSE_EXPOSURE, +=09=09=09=09 sensor->expo_ctrl->val, &ret); +=09=09if (all || sensor->again_ctrl->is_new) +=09=09=09vd55g0_write(sensor, VD55G0_REG_MANUAL_ANALOG_GAIN, +=09=09=09=09 sensor->again_ctrl->val, &ret); +=09=09if (all || sensor->dgain_ctrl->is_new) +=09=09=09vd55g0_write(sensor, VD55G0_REG_MANUAL_DIGITAL_GAIN, +=09=09=09=09 sensor->dgain_ctrl->val, &ret); +=09=09if (ret) +=09=09=09return ret; +=09} + +=09if (sensor->ae_ctrl->is_new) +=09=09ret =3D vd55g0_apply_exposure_mode(sensor, is_auto, +=09=09=09=09=09=09 sensor->ae_lock_ctrl->cur.val & +=09=09=09=09=09=09 V4L2_LOCK_EXPOSURE); + +=09return ret; +} + +/* Under auto exposure, the manual controls read what the sensor applies *= / +static int vd55g0_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(ctrl_to_sd(ctrl)); +=09struct device *dev =3D &sensor->i2c_client->dev; +=09u64 expo, again, dgain; +=09int ret =3D 0; + +=09/* Unpowered: the last stream's values, the next one's start */ +=09if (!pm_runtime_get_if_in_use(dev)) { +=09=09sensor->expo_ctrl->val =3D min_t(u32, sensor->cold_start.expo, +=09=09=09=09=09 sensor->expo_ctrl->maximum); +=09=09sensor->again_ctrl->val =3D sensor->cold_start.analog_gain; +=09=09sensor->dgain_ctrl->val =3D sensor->cold_start.digital_gain; +=09=09return 0; +=09} + +=09vd55g0_read(sensor, VD55G0_REG_APPLIED_COARSE_EXPOSURE, &expo, &ret); +=09vd55g0_read(sensor, VD55G0_REG_APPLIED_ANALOG_GAIN, &again, &ret); +=09vd55g0_read(sensor, VD55G0_REG_APPLIED_DIGITAL_GAIN, &dgain, &ret); +=09if (!ret) { +=09=09sensor->expo_ctrl->val =3D min_t(u64, expo, +=09=09=09=09=09 sensor->expo_ctrl->maximum); +=09=09sensor->again_ctrl->val =3D again; +=09=09sensor->dgain_ctrl->val =3D dgain; +=09} + +=09pm_runtime_put_autosuspend(dev); + +=09return ret; +} + +static int vd55g0_s_ctrl(struct v4l2_ctrl *ctrl) +{ +=09struct v4l2_subdev *sd =3D ctrl_to_sd(ctrl); +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(sd); +=09struct device *dev =3D &sensor->i2c_client->dev; +=09struct v4l2_subdev_state *state =3D +=09=09v4l2_subdev_get_locked_active_state(sd); +=09const struct v4l2_rect *crop =3D v4l2_subdev_state_get_crop(state, 0); +=09bool is_auto, locked; +=09int ret; + +=09/* Read-only controls are set by the driver: nothing to apply */ +=09if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) +=09=09return 0; + +=09/* The exposure range follows vblank whether the sensor is on or not */ +=09if (ctrl->id =3D=3D V4L2_CID_VBLANK) { +=09=09ret =3D vd55g0_update_expo_range(sensor, +=09=09=09=09=09 crop->height + ctrl->val); +=09=09if (ret) { +=09=09=09vd55g0_update_expo_range(sensor, +=09=09=09=09=09=09 crop->height + ctrl->cur.val); +=09=09=09return ret; +=09=09} +=09} + +=09/* The sensor gets the values at the next stream start */ +=09if (!pm_runtime_get_if_in_use(dev)) +=09=09return 0; + +=09switch (ctrl->id) { +=09case V4L2_CID_HFLIP: +=09=09ret =3D vd55g0_write(sensor, VD55G0_REG_ORIENTATION, +=09=09=09=09 sensor->hflip_ctrl->val | +=09=09=09=09 (sensor->vflip_ctrl->val << 1), NULL); +=09=09break; +=09case V4L2_CID_TEST_PATTERN: +=09=09ret =3D vd55g0_apply_patgen(sensor, ctrl->val); +=09=09break; +=09case V4L2_CID_EXPOSURE_AUTO: +=09=09ret =3D vd55g0_update_expo_cluster(sensor); +=09=09break; +=09case V4L2_CID_3A_LOCK: +=09=09is_auto =3D sensor->ae_ctrl->cur.val =3D=3D V4L2_EXPOSURE_AUTO; +=09=09locked =3D ctrl->val & V4L2_LOCK_EXPOSURE; +=09=09ret =3D vd55g0_apply_exposure_mode(sensor, is_auto, locked); +=09=09break; +=09case V4L2_CID_VBLANK: +=09=09ret =3D vd55g0_write(sensor, VD55G0_REG_FRAME_LENGTH, +=09=09=09=09 crop->height + ctrl->val, NULL); +=09=09/* Not applied: put the exposure range back */ +=09=09if (ret) +=09=09=09vd55g0_update_expo_range(sensor, +=09=09=09=09=09=09 crop->height + ctrl->cur.val); +=09=09break; +=09case V4L2_CID_AUTO_EXPOSURE_BIAS: +=09=09/* +=09=09 * We use auto exposure target percentage register to control +=09=09 * exposure bias for more precision. +=09=09 */ +=09=09ret =3D vd55g0_apply_exposure_target(sensor, ctrl->val); +=09=09break; +=09case V4L2_CID_FLASH_LED_MODE: +=09=09ret =3D vd55g0_apply_flash(sensor, ctrl->val); +=09=09break; +=09default: +=09=09ret =3D -EINVAL; +=09=09break; +=09} + +=09pm_runtime_put_autosuspend(dev); + +=09return ret; +} + +static const struct v4l2_ctrl_ops vd55g0_ctrl_ops =3D { +=09.g_volatile_ctrl =3D vd55g0_g_volatile_ctrl, +=09.s_ctrl =3D vd55g0_s_ctrl, +}; + +static int vd55g0_init_controls(struct vd55g0_dev *sensor) +{ +=09const struct v4l2_ctrl_ops *ops =3D &vd55g0_ctrl_ops; +=09struct v4l2_ctrl_handler *hdl =3D &sensor->ctrl_handler; +=09/* What vd55g0_init_state() puts in the active state */ +=09const struct v4l2_rect *crop =3D +=09=09&vd55g0_mode_data[VD55G0_DEFAULT_MODE].crop; +=09struct v4l2_fwnode_device_properties fwnode_props; +=09struct v4l2_ctrl *ctrl; +=09unsigned int patgen_size =3D ARRAY_SIZE(vd55g0_test_pattern_menu) - 1; +=09unsigned int hblank =3D vd55g0_line_length(sensor) - crop->width; +=09u32 pixel_rate =3D vd55g0_pixel_rate(sensor); +=09int ret; + +=09ret =3D v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &fwnode_prop= s); +=09if (ret) +=09=09return ret; + +=09v4l2_ctrl_handler_init(hdl, 16); +=09v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_AUTO_EXPOSURE_BIAS, +=09=09=09 ARRAY_SIZE(vd55g0_ev_bias_menu) - 1, +=09=09=09 ARRAY_SIZE(vd55g0_ev_bias_menu) / 2, +=09=09=09 vd55g0_ev_bias_menu); +=09ctrl =3D v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, +=09=09=09=09 0, 0, &sensor->link_freq); +=09if (ctrl) +=09=09ctrl->flags |=3D V4L2_CTRL_FLAG_READ_ONLY; +=09v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, pixel_rate, +=09=09=09 pixel_rate, 1, pixel_rate); +=09sensor->ae_ctrl =3D v4l2_ctrl_new_std_menu(hdl, ops, +=09=09=09=09=09=09 V4L2_CID_EXPOSURE_AUTO, 1, +=09=09=09=09=09=09 ~0x3, V4L2_EXPOSURE_AUTO); +=09sensor->again_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GA= IN, +=09=09=09=09=09 0, 24, 1, 0); +=09sensor->dgain_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAI= N, +=09=09=09=09=09 256, 2048, 1, 256); +=09sensor->ae_lock_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_3A_LOCK, +=09=09=09=09=09=09 0, 1, 0, 0); +=09/* Only when the firmware describes the LED GPIOs */ +=09if (sensor->nb_leds) +=09=09v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE, +=09=09=09=09 V4L2_FLASH_LED_MODE_FLASH, ~0x7, +=09=09=09=09 V4L2_FLASH_LED_MODE_NONE); + +=09/* +=09 * Keep a pointer to these controls as we need to update them when +=09 * setting the format +=09 */ +=09sensor->vblank_ctrl =3D +=09=09v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, +=09=09=09=09 VD55G0_MIN_FRAME_LENGTH - crop->height, +=09=09=09=09 0xffff - crop->height, 1, +=09=09=09=09 VD55G0_FRAME_LENGTH_DEF - crop->height); +=09sensor->hblank_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, +=09=09=09=09=09=09hblank, hblank, 1, hblank); +=09if (sensor->hblank_ctrl) +=09=09sensor->hblank_ctrl->flags |=3D V4L2_CTRL_FLAG_READ_ONLY; +=09sensor->hflip_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, +=09=09=09=09=09 0, 1, 1, 0); +=09sensor->vflip_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, +=09=09=09=09=09 0, 1, 1, 0); +=09sensor->pattern_ctrl =3D +=09=09v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, +=09=09=09=09=09 patgen_size, 0, 0, +=09=09=09=09=09 vd55g0_test_pattern_menu); +=09sensor->expo_ctrl =3D +=09=09v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 0, +=09=09=09=09 VD55G0_FRAME_LENGTH_DEF - +=09=09=09=09 VD55G0_EXPO_MAX_TERM, 1, VD55G0_EXPO_DEF); + +=09ret =3D v4l2_ctrl_new_fwnode_properties(hdl, ops, &fwnode_props); +=09if (ret) +=09=09goto free_ctrls; + +=09v4l2_ctrl_cluster(2, &sensor->hflip_ctrl); +=09v4l2_ctrl_auto_cluster(4, &sensor->ae_ctrl, V4L2_EXPOSURE_MANUAL, true)= ; + +=09sensor->sd.ctrl_handler =3D hdl; + +=09return 0; + +free_ctrls: +=09return v4l2_ctrl_handler_free(hdl); +} + +static int vd55g0_detect(struct vd55g0_dev *sensor) +{ +=09struct i2c_client *client =3D sensor->i2c_client; +=09u64 revision, id =3D 0; +=09int ret; + +=09ret =3D vd55g0_read(sensor, VD55G0_REG_MODEL_ID, &id, NULL); +=09if (ret) +=09=09return ret; + +=09if (id !=3D VD55G0_MODEL_ID) { +=09=09dev_warn(&client->dev, "Unsupported sensor id %llx\n", id); +=09=09return -ENODEV; +=09} + +=09ret =3D vd55g0_read(sensor, VD55G0_REG_REVISION, &revision, NULL); +=09if (ret) +=09=09return ret; +=09dev_dbg(&client->dev, "Sensor revision 0x%llx\n", revision); + +=09if (revision !=3D VD55G0_REVISION_CUT1 && +=09 revision !=3D VD55G0_REVISION_CUT2) { +=09=09dev_err(&client->dev, "Unsupported device revision 0x%llx\n", +=09=09=09revision); +=09=09return -ENODEV; +=09} + +=09sensor->revision =3D revision; + +=09return 0; +} + +/* Power/clock management functions */ +static int vd55g0_power_on(struct device *dev) +{ +=09struct i2c_client *client =3D to_i2c_client(dev); +=09struct v4l2_subdev *sd =3D i2c_get_clientdata(client); +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(sd); +=09int ret; + +=09ret =3D regulator_bulk_enable(ARRAY_SIZE(vd55g0_supply_name), +=09=09=09=09 sensor->supplies); +=09if (ret) { +=09=09dev_err(&client->dev, "failed to enable regulators %d\n", ret); +=09=09return ret; +=09} + +=09ret =3D clk_prepare_enable(sensor->xclk); +=09if (ret) { +=09=09dev_err(&client->dev, "failed to enable clock %d\n", ret); +=09=09goto disable_bulk; +=09} + +=09if (sensor->reset_gpio) +=09=09vd55g0_apply_reset(sensor); + +=09ret =3D vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_READY_TO_BOOT, +=09=09=09=09VD55G0_TIMEOUT_MS); +=09if (ret) { +=09=09dev_err(&client->dev, "sensor reset failed %d\n", ret); +=09=09goto disable_clock; +=09} + +=09ret =3D vd55g0_detect(sensor); +=09if (ret) { +=09=09dev_err(&client->dev, "sensor detect failed %d\n", ret); +=09=09goto disable_clock; +=09} + +=09ret =3D vd55g0_patch(sensor); +=09if (ret) { +=09=09dev_err(&client->dev, "sensor patch failed %d\n", ret); +=09=09goto disable_clock; +=09} + +=09ret =3D vd55g0_boot(sensor); +=09if (ret) { +=09=09dev_err(&client->dev, "sensor boot failed %d\n", ret); +=09=09goto disable_clock; +=09} + +=09ret =3D vd55g0_configure(sensor); +=09if (ret) { +=09=09dev_err(&client->dev, "sensor configuration failed %d\n", ret); +=09=09goto disable_clock; +=09} + +=09return 0; + +disable_clock: +=09gpiod_set_value_cansleep(sensor->reset_gpio, 1); +=09clk_disable_unprepare(sensor->xclk); +disable_bulk: +=09regulator_bulk_disable(ARRAY_SIZE(vd55g0_supply_name), +=09=09=09 sensor->supplies); + +=09return ret; +} + +static int vd55g0_power_off(struct device *dev) +{ +=09struct i2c_client *client =3D to_i2c_client(dev); +=09struct v4l2_subdev *sd =3D i2c_get_clientdata(client); +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(sd); + +=09/* Hold the sensor in reset while its rails are off, as vd55g1 does */ +=09gpiod_set_value_cansleep(sensor->reset_gpio, 1); +=09clk_disable_unprepare(sensor->xclk); +=09regulator_bulk_disable(ARRAY_SIZE(vd55g0_supply_name), +=09=09=09 sensor->supplies); +=09return 0; +} + +static int vd55g0_parse_dt_gpios_array(struct vd55g0_dev *sensor, +=09=09=09=09 char *prop_name, u32 *array, int *nb) +{ +=09struct i2c_client *client =3D sensor->i2c_client; +=09int ret; + +=09*nb =3D device_property_count_u32(&client->dev, prop_name); +=09if (*nb =3D=3D -EINVAL) { +=09=09/* Property not found */ +=09=09*nb =3D 0; +=09=09return 0; +=09} +=09if (*nb < 0) +=09=09return *nb; +=09if (*nb > VD55G0_NB_GPIOS) { +=09=09dev_err(&client->dev, "%s lists %d GPIOs, the sensor has %d\n", +=09=09=09prop_name, *nb, VD55G0_NB_GPIOS); +=09=09return -EINVAL; +=09} + +=09ret =3D device_property_read_u32_array(&client->dev, prop_name, array, +=09=09=09=09=09 *nb); +=09if (ret) { +=09=09dev_err(&client->dev, "Failed to read %s prop\n", prop_name); +=09=09return ret; +=09} + +=09for (unsigned int i =3D 0; i < *nb; i++) { +=09=09if (array[i] >=3D VD55G0_NB_GPIOS) { +=09=09=09dev_err(&client->dev, "invalid GPIO %d for leds\n", +=09=09=09=09array[i]); +=09=09=09return -EINVAL; +=09=09} +=09} + +=09return 0; +} + +static int vd55g0_parse_dt_gpios(struct vd55g0_dev *sensor) +{ +=09int nb_gpios_leds; +=09int ret; + +=09memset(sensor->leds, ~0, sizeof(sensor->leds)); + +=09ret =3D vd55g0_parse_dt_gpios_array(sensor, "st,leds", sensor->leds, +=09=09=09=09=09 &nb_gpios_leds); +=09if (ret) +=09=09return ret; + +=09sensor->nb_leds =3D nb_gpios_leds; + +=09return 0; +} + +static int vd55g0_probe(struct i2c_client *client) +{ +=09struct device *dev =3D &client->dev; +=09struct fwnode_handle *handle; +=09struct vd55g0_dev *sensor; +=09int ret; + +=09sensor =3D devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); +=09if (!sensor) +=09=09return -ENOMEM; + +=09sensor->i2c_client =3D client; +=09sensor->regmap =3D devm_cci_regmap_init_i2c(client, 16); +=09if (IS_ERR(sensor->regmap)) +=09=09return dev_err_probe(&client->dev, PTR_ERR(sensor->regmap), +=09=09=09=09 "failed to init CCI\n"); +=09sensor->cold_start.expo =3D 0x32; +=09sensor->cold_start.digital_gain =3D 256; +=09sensor->cold_start.analog_gain =3D 0; + +=09handle =3D fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); + +=09sensor->reset_gpio =3D devm_gpiod_get_optional(dev, "reset", +=09=09=09=09=09=09 GPIOD_OUT_HIGH); +=09if (IS_ERR(sensor->reset_gpio)) { +=09=09ret =3D dev_err_probe(dev, PTR_ERR(sensor->reset_gpio), +=09=09=09=09 "Failed to get reset gpio\n"); +=09=09goto error_put_handle; +=09} + +=09ret =3D vd55g0_parse_dt_gpios(sensor); +=09if (ret) { +=09=09dev_err(dev, "Failed to get gpios\n"); +=09=09goto error_put_handle; +=09} + +=09ret =3D vd55g0_tx_from_ep(sensor, handle); +=09if (ret) { +=09=09dev_err_probe(dev, ret, "Failed to parse endpoint\n"); +=09=09goto error_put_handle; +=09} +=09fwnode_handle_put(handle); + +=09sensor->xclk =3D devm_v4l2_sensor_clk_get(dev, NULL); +=09if (IS_ERR(sensor->xclk)) +=09=09return dev_err_probe(dev, PTR_ERR(sensor->xclk), +=09=09=09=09 "failed to get xclk\n"); + +=09sensor->clk_freq =3D clk_get_rate(sensor->xclk); +=09ret =3D vd55g0_check_clock_tree(sensor); +=09if (ret) +=09=09return ret; + +=09v4l2_i2c_subdev_init(&sensor->sd, client, &vd55g0_subdev_ops); +=09sensor->sd.internal_ops =3D &vd55g0_internal_ops; +=09sensor->sd.flags |=3D V4L2_SUBDEV_FL_HAS_DEVNODE; +=09sensor->pad.flags =3D MEDIA_PAD_FL_SOURCE; +=09sensor->sd.entity.function =3D MEDIA_ENT_F_CAM_SENSOR; + +=09ret =3D vd55g0_get_regulators(sensor); +=09if (ret) +=09=09return dev_err_probe(&client->dev, ret, +=09=09=09=09 "failed to get regulators\n"); + +=09/* Power on once to check that the sensor answers */ +=09ret =3D vd55g0_power_on(dev); +=09if (ret) +=09=09return ret; + +=09ret =3D vd55g0_init_controls(sensor); +=09if (ret) { +=09=09dev_err(&client->dev, "controls initialization failed %d\n", +=09=09=09ret); +=09=09goto error_power_off; +=09} + +=09sensor->sd.state_lock =3D sensor->ctrl_handler.lock; + +=09ret =3D media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); +=09if (ret) { +=09=09dev_err(&client->dev, "pads init failed %d\n", ret); +=09=09goto error_handler_free; +=09} + +=09ret =3D v4l2_subdev_init_finalize(&sensor->sd); +=09if (ret) { +=09=09dev_err(&client->dev, "subdev init error %d\n", ret); +=09=09goto error_media_entity; +=09} + +=09/* Held until registered, so that runtime PM cannot power it down */ +=09pm_runtime_set_active(dev); +=09pm_runtime_get_noresume(dev); +=09pm_runtime_enable(dev); +=09pm_runtime_set_autosuspend_delay(dev, 1000); +=09pm_runtime_use_autosuspend(dev); + +=09ret =3D v4l2_async_register_subdev_sensor(&sensor->sd); +=09if (ret) { +=09=09dev_err_probe(dev, ret, "async subdev register failed\n"); +=09=09goto error_pm_runtime; +=09} + +=09pm_runtime_put_autosuspend(dev); + +=09dev_dbg(&client->dev, "vd55g0 probe successfully\n"); + +=09return 0; + +error_put_handle: +=09fwnode_handle_put(handle); + +=09return ret; + +error_pm_runtime: +=09pm_runtime_disable(dev); +=09pm_runtime_set_suspended(dev); +=09pm_runtime_put_noidle(dev); +=09v4l2_subdev_cleanup(&sensor->sd); +error_media_entity: +=09media_entity_cleanup(&sensor->sd.entity); +error_handler_free: +=09v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); +error_power_off: +=09vd55g0_power_off(dev); + +=09return ret; +} + +static void vd55g0_remove(struct i2c_client *client) +{ +=09struct v4l2_subdev *sd =3D i2c_get_clientdata(client); +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(sd); + +=09v4l2_async_unregister_subdev(&sensor->sd); +=09v4l2_subdev_cleanup(&sensor->sd); +=09media_entity_cleanup(&sensor->sd.entity); +=09v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); + +=09pm_runtime_disable(&client->dev); +=09if (!pm_runtime_status_suspended(&client->dev)) +=09=09vd55g0_power_off(&client->dev); +=09pm_runtime_set_suspended(&client->dev); +} + +static const struct of_device_id vd55g0_dt_ids[] =3D { +=09{ .compatible =3D "st,vd55g0" }, +=09{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, vd55g0_dt_ids); + +static const struct acpi_device_id vd55g0_acpi_ids[] =3D { +=09{ "SMO55F0" }, +=09{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, vd55g0_acpi_ids); + +static const struct dev_pm_ops vd55g0_pm_ops =3D { +=09RUNTIME_PM_OPS(vd55g0_power_off, vd55g0_power_on, NULL) +}; + +static struct i2c_driver vd55g0_i2c_driver =3D { +=09.driver =3D { +=09=09.name =3D "vd55g0", +=09=09.of_match_table =3D vd55g0_dt_ids, +=09=09.acpi_match_table =3D vd55g0_acpi_ids, +=09=09.pm =3D pm_ptr(&vd55g0_pm_ops), +=09}, +=09.probe =3D vd55g0_probe, +=09.remove =3D vd55g0_remove, +}; + +module_i2c_driver(vd55g0_i2c_driver); + +MODULE_AUTHOR("Benjamin Mugnier "); +MODULE_AUTHOR("Mickael Guene "); +MODULE_AUTHOR("Sylvain Petinot "); +MODULE_AUTHOR("Sergey Lebedev "); +MODULE_DESCRIPTION("VD55G0 camera subdev driver"); +MODULE_LICENSE("GPL"); --=20 2.54.0