From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=79.135.106.29 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1792427283; b=pk33DpNxl9csRwNdRBFvD7UXmh3ff5l/aH3ckZZYtVKbMGioPWBJl/OYgsAN2S20eJFs //EamVwwFBckRihfywSpTXf3ukHMeew2J0+0haQlvVz+KS1TxDzXxXy/JCGu/9ow3DFjq wfjkKvcxwlU8iJvIVtQZFmjAgIrzqPAbjd1am1tIknRakcK5rNL74tUruCIqnpS+4ZGOI OfuGeFM6efTSInjUhqMsE/H1xlnYIxUjw8XZuvMhGeqh+F3KLpq8Igznadk2XH5oAuGF9 IWwXZM1OxMUY6HFzZdJwRgmEloAfRAiOf5d54OfxvB025a3jsqJ93iaGZjOP8kYR1+g== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1792427283; 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=tw/BspER6s3TAvGB76PfA/Qld5hKjw++rgE/xXlVX5M=; b=fMr/P/lYeHmc1yRDYm2ofSbKVVsq4NTAgnRKJMd+bnsnnxQW66XMO5sKaivhOlphPhsA dFfuh4BOigB0XkpTdlfcK8hSjBivjaGDvW8bbcroL0Zf/AIJ5cr5U38AAQyTsr/wdGUVt OOLcnDUOBR1VX8UYGtnadqenQz3zLqLy4VfXVBkhyZz6qS4I6gmj3dv9eN7yg1DRsWEWn vtt8P1eJiHmjq9hjdCu8BYb8+dh9oLV3w4Ao9ZMoc4Atn+ECvFHaQ4KEZshBv0smGoi2F MjMJdw8Ft8ILBKxTf/AOQRypY0F/IYXFLoDfMzn7ZWp/LdYpCQ29Th2B5iahTbhxkTg== 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="bP/ynfYt"; arc=none smtp.remote-ip=79.135.106.29 Received: from mail-10629.protonmail.ch (mail-10629.protonmail.ch [79.135.106.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AFF9F606A320; Mon, 19 Oct 2026 16:28:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org AFF9F606A320 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, unprotected) header.d=pm.me header.i=@pm.me header.a=rsa-sha256 header.s=protonmail3 header.b=bP/ynfYt DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1792427278; x=1792686478; bh=tw/BspER6s3TAvGB76PfA/Qld5hKjw++rgE/xXlVX5M=; 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=bP/ynfYtzBRCqJAugESdpnbnkya1czkZIpm3lLXWo5xnML7xF/fvAh8TBh3lmQGv3 8T+730owA8QpifHRpNPFpO7oj9aYFeCaT+w7R/p68BS7uHGWMwMuSdze5YTzOc+bOc CkWYC/MfC9lVFPKx3kZ7xt1zYnEZuXdJ2TQcsaqdpPXHF6RsF++QaY04/wjz5ErOeA U2uE+WtmWljdFwvyQ/KXA7aO3D5rplZU1RxpFkuX/B/re4bvurMOfOufHTMX5NFTLm nxTAE+j3c9rFUNUPBDViVKwTmtmOTxqQzVktM4+YHISCijeXY+v9Ge3zhyGb3R248R SwdlQl9kUNDYQ== Date: Mon, 19 Oct 2026 16:27:50 +0000 To: Sakari Ailus , Benjamin Mugnier , Sylvain Petinot , Mauro Carvalho Chehab From: Sergey Lebedev Cc: Dan Scally , Hans de Goede , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Peter Marshall , George Neacsu , Hao Yao , linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/4] media: i2c: Add ST VD55G0 global shutter sensor driver Message-ID: <20261019162722.25587-3-lsa.uz@pm.me> In-Reply-To: <20261019162722.25587-1-lsa.uz@pm.me> References: <20261019162722.25587-1-lsa.uz@pm.me> Feedback-ID: 113843758:user:proton X-Pm-Message-ID: d1fc06b38b268aab19804605dc53ea90093f7fdd 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. With the ACPI ID the supplies take the names INT3472 registers, avdd and dovdd; a PRP0001 device keeps the DT names. 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 Assisted-by: Claude:claude-opus-5-5 sparse Signed-off-by: Sergey Lebedev --- On ACPI the supplies take the names INT3472 registers, avdd and dovdd, through acpi_match_device(); vd55g1 is served by an entry in int3472's map instead. I did not add one, as it would have to say which rail each pin feeds, and that is not known here: INT3472 calls pin type 0x10 DOVDD, while Windows' camera driver calls it Avdd. If a map entry is preferred, I can move the names there. MAINTAINERS | 10 + drivers/media/i2c/Kconfig | 11 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/vd55g0.c | 2434 ++++++++++++++++++++++++++++++++++++ 4 files changed, 2456 insertions(+) create mode 100644 drivers/media/i2c/vd55g0.c diff --git a/MAINTAINERS b/MAINTAINERS index 760791e3635..7745ad9ef81 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26036,6 +26036,15 @@ 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:=09Documentation/devicetree/bindings/media/i2c/st,vd55g0.yaml +F:=09drivers/media/i2c/vd55g0.c + ST VD55G1 DRIVER M:=09Benjamin Mugnier M:=09Sylvain Petinot @@ -28683,6 +28692,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 7de2d095c96..05343f82ec6 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..3b51a87e740 --- /dev/null +++ b/drivers/media/i2c/vd55g0.c @@ -0,0 +1,2434 @@ +// 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_REG8(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=0916 +#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_EXPO_TARGET_DEF=09=09=09=0927 +#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 { +0x81, 0x06, 0x0b, 0x02, 0x00, 0x09, 0x42, 0x00, 0xd2, 0x08, 0x42, 0x00, 0x= e6, +0x08, 0x42, 0x00, 0x12, 0x09, 0x42, 0x00, 0xe0, 0x3f, 0x80, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40, 0x01, 0x60, 0x10, 0x40, 0x= 11, +0x81, 0x16, 0x80, 0x93, 0xdd, 0x4c, 0x04, 0x04, 0xfa, 0x06, 0x4c, 0x94, 0x= 60, +0xe6, 0x0e, 0xdc, 0xe0, 0x04, 0x18, 0x70, 0x02, 0x08, 0xe7, 0xce, 0x44, 0x= 01, +0x60, 0x10, 0x40, 0x31, 0x85, 0x1e, 0x08, 0x4e, 0x43, 0x01, 0x60, 0x10, 0x= c0, +0x31, 0x40, 0x20, 0xe0, 0x04, 0x98, 0x29, 0x00, 0x50, 0xeb, 0x2e, 0x84, 0x= 24, +0x84, 0x29, 0x86, 0x2e, 0x84, 0x24, 0x84, 0x2b, 0xa1, 0x15, 0xfe, 0xd8, 0x= 41, +0x00, 0xe8, 0xf8, 0x47, 0x00, 0xe8, 0x78, 0x44, 0x40, 0xef, 0x0a, 0x9c, 0x= 1a, +0x9e, 0x2a, 0xdc, 0x3a, 0xde, 0x03, 0x4e, 0x7c, 0xf9, 0x13, 0x4e, 0x78, 0x= f9, +0x23, 0x4e, 0x74, 0xf9, 0x33, 0x4e, 0x70, 0xf9, 0x18, 0x50, 0x40, 0xef, 0x= 38, +0x49, 0x44, 0xef, 0x04, 0x18, 0x11, 0x83, 0x11, 0x40, 0x20, 0xe0, 0x4c, 0x= 0c, +0x04, 0xf2, 0x93, 0xdd, 0x86, 0x44, 0x88, 0xe0, 0x05, 0x04, 0x40, 0xf8, 0x= 09, +0x00, 0x24, 0xe0, 0x4a, 0x40, 0x88, 0x60, 0x06, 0x40, 0x94, 0xe0, 0x04, 0x= 80, +0x65, 0x86, 0x31, 0x01, 0x06, 0x02, 0x0c, 0xe1, 0x33, 0x40, 0xc8, 0xe2, 0x= 33, +0x40, 0x70, 0xe2, 0x14, 0x84, 0x18, 0x48, 0x1b, 0xa3, 0x55, 0x8a, 0x0a, 0x= 02, +0x08, 0x70, 0x16, 0x43, 0x58, 0xe0, 0x26, 0x08, 0x00, 0x40, 0x16, 0x0a, 0x= 00, +0xc0, 0x41, 0x44, 0x08, 0x40, 0x06, 0x46, 0x08, 0xe0, 0x51, 0x44, 0x04, 0x= c0, +0x45, 0x85, 0x66, 0x02, 0x04, 0xe0, 0x13, 0x40, 0x70, 0x62, 0x06, 0x02, 0x= 0c, +0xe1, 0x14, 0x84, 0x18, 0x48, 0x1b, 0xa3, 0xb5, 0x86, 0x0a, 0x02, 0x08, 0x= 70, +0xa6, 0x02, 0x68, 0xe0, 0x26, 0x0a, 0x00, 0x40, 0x16, 0x18, 0x00, 0xc0, 0x= 31, +0x01, 0xc6, 0x09, 0x0c, 0xe0, 0x51, 0x44, 0x08, 0xc0, 0xc1, 0x44, 0x04, 0x= c0, +0x95, 0x83, 0x0a, 0x02, 0x04, 0xf0, 0x16, 0x02, 0x00, 0xc0, 0x11, 0x44, 0x= 08, +0xc0, 0x11, 0x44, 0x04, 0x40, 0x11, 0x81, 0x33, 0x40, 0x18, 0xe3, 0x15, 0x= 83, +0x0a, 0x02, 0x04, 0x70, 0x11, 0x81, 0x16, 0x0a, 0x00, 0x40, 0x31, 0x9d, 0x= 51, +0x44, 0x08, 0x40, 0x06, 0x09, 0x04, 0xe0, 0x51, 0x44, 0x04, 0xc0, 0x43, 0x= 40, +0x18, 0xe3, 0x33, 0x40, 0xc8, 0xe2, 0x13, 0x40, 0xc0, 0x62, 0xa6, 0x05, 0x= 78, +0xe0, 0x23, 0x40, 0xd0, 0xe3, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x7c, 0x= fa, +0x86, 0x42, 0x84, 0x60, 0x06, 0x00, 0x0c, 0xe1, 0x14, 0x04, 0xf6, 0x50, 0x= 78, +0xe3, 0x04, 0x00, 0x26, 0x0f, 0x28, 0xe2, 0x16, 0x15, 0x2c, 0x64, 0xb1, 0x= bb, +0x6a, 0x84, 0x0b, 0xa3, 0x36, 0x10, 0x10, 0x41, 0x2e, 0x54, 0x08, 0xd8, 0x= 16, +0x4f, 0x44, 0x43, 0x06, 0x16, 0x00, 0xc0, 0x0b, 0x10, 0x1b, 0x8c, 0xb8, 0x= 4f, +0x00, 0x6f, 0xa4, 0x12, 0x80, 0xfb, 0x06, 0x42, 0x1a, 0x60, 0x00, 0x40, 0x= fc, +0x73, 0x03, 0xc0, 0x83, 0x22, 0x0e, 0x02, 0xc1, 0x7f, 0x1f, 0xc0, 0x87, 0x= d4, +0x8f, 0x02, 0x1b, 0x8c, 0x8f, 0x20, 0x0b, 0x8e, 0x98, 0x4e, 0x00, 0xef, 0x= 06, +0x42, 0x1a, 0x60, 0x00, 0x40, 0xfc, 0xf0, 0x73, 0xa2, 0x77, 0xcc, 0x70, 0x= 42, +0x01, 0x73, 0xff, 0xc7, 0x12, 0x4e, 0x80, 0x79, 0x0b, 0x92, 0xb8, 0x4d, 0x= 00, +0x6f, 0x1b, 0x8c, 0x06, 0x42, 0x94, 0x60, 0x06, 0x46, 0x1a, 0xe0, 0x24, 0x= 04, +0x00, 0x40, 0xfd, 0x73, 0x03, 0xc0, 0xa3, 0xa6, 0xa7, 0xd4, 0xb3, 0x44, 0x= 60, +0xe3, 0x85, 0x44, 0x9c, 0xe0, 0x24, 0x84, 0x75, 0x44, 0xa0, 0x60, 0x0e, 0x= 04, +0xc0, 0x7f, 0x1f, 0xc0, 0x14, 0x04, 0xaf, 0x84, 0xaf, 0xa0, 0xa5, 0x42, 0x= a4, +0xe0, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x0c, 0x04, 0x0c, 0xfa, 0x46, 0x= 0d, +0xcc, 0xe0, 0x09, 0x0c, 0xbc, 0xee, 0x0a, 0x40, 0x80, 0xe0, 0x45, 0x82, 0x= a6, +0x40, 0x08, 0xe0, 0x06, 0x98, 0x08, 0x7f, 0x74, 0xef, 0x0b, 0xa1, 0xb5, 0x= fe, +0x01, 0x87, 0x06, 0x98, 0x06, 0x4c, 0x94, 0x60, 0x06, 0x42, 0x0c, 0xe0, 0x= 05, +0x0c, 0x14, 0xe0, 0x11, 0x40, 0x30, 0x62, 0x26, 0x42, 0x00, 0xe0, 0x05, 0x= 0c, +0x14, 0xe0, 0x11, 0x40, 0xa0, 0x62, 0x56, 0x43, 0x04, 0xe0, 0x05, 0x0c, 0x= 14, +0xe0, 0x11, 0x40, 0x40, 0x62, 0x76, 0x43, 0x04, 0xe0, 0x05, 0x0c, 0x14, 0x= e0, +0x11, 0x40, 0x50, 0xe2, 0x04, 0x98, 0x19, 0x00, 0x50, 0xeb, 0x4a, 0x42, 0x= 88, +0xe0, 0xc5, 0x80, 0x28, 0x67, 0x54, 0x6f, 0x66, 0x00, 0xa0, 0xe0, 0x04, 0x= 98, +0x19, 0x00, 0x30, 0xe0, 0x19, 0xc4, 0x11, 0x40, 0x30, 0x60, 0x11, 0x83, 0x= 04, +0x9a, 0x11, 0x40, 0x10, 0xe0, 0x04, 0x98, 0x11, 0x40, 0x20, 0x60, 0x11, 0x= 81, +0x04, 0x98, 0x11, 0x40, 0xb0, 0xe7, 0x19, 0x00, 0x50, 0xeb, 0x4a, 0x02, 0x= 0c, +0xfc, 0x85, 0xfe, 0xc6, 0x4c, 0xb4, 0xe0, 0x60, 0x10, 0xb1, 0x64, 0x01, 0x= c0, +0x0a, 0xe0, 0x0b, 0xa1, 0x95, 0x8c, 0x04, 0xe0, 0x0b, 0xa1, 0x25, 0x8c, 0x= d8, +0x43, 0x5c, 0xef, 0x0a, 0xe0, 0x0b, 0xa1, 0x95, 0x8a, 0x04, 0xe0, 0x0b, 0x= a1, +0x25, 0x8a, 0xc6, 0x4e, 0x84, 0xe0, 0x04, 0x9c, 0x09, 0x00, 0x20, 0xe1, 0x= 4a, +0x40, 0x80, 0xe0, 0x25, 0x86, 0x08, 0x22, 0x46, 0x43, 0x00, 0xe0, 0x06, 0x= 40, +0x06, 0xe0, 0x63, 0x80, 0x09, 0x0c, 0x40, 0xe2, 0x09, 0x86, 0x0b, 0xa5, 0x= d5, +0x82, 0x68, 0x4e, 0x48, 0x6f, 0x01, 0x85, 0x78, 0x44, 0x48, 0x6f, 0x06, 0x= 00, +0x80, 0xe1, 0xf8, 0x75, 0x4c, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0x78, 0x48, 0x= 48, +0xef, 0x09, 0x0e, 0x48, 0xe0, 0x0b, 0xa1, 0xb5, 0x80, 0x58, 0x7b, 0x3c, 0x= ef, +0x78, 0x74, 0x40, 0xef, 0xa6, 0x40, 0x08, 0xe0, 0x0c, 0x0c, 0x0c, 0xf2, 0x= 18, +0x12, 0x50, 0xff, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0x7b, 0x00, 0x06, 0x= 01, +0x08, 0xe1, 0x08, 0x00, 0x6b, 0x82, 0x0b, 0xa1, 0x15, 0x82, 0xa6, 0x41, 0x= 84, +0xe0, 0x18, 0x00, 0x01, 0x89, 0x18, 0x42, 0x00, 0xef, 0x63, 0x80, 0x04, 0x= 1c, +0x64, 0x02, 0x84, 0xe0, 0x78, 0x40, 0x00, 0x68, 0x00, 0x00, 0x40, 0xe6, 0x= 4c, +0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x1e, 0x80, 0x93, 0xdd, 0x0c, 0x04, 0x3c, 0x= fa, +0xf0, 0x1e, 0x40, 0x6c, 0x86, 0x0f, 0xe0, 0xe0, 0x01, 0x05, 0x91, 0x81, 0x= 06, +0x02, 0x00, 0x62, 0x81, 0xb1, 0x01, 0x4e, 0xd8, 0x69, 0x0e, 0x00, 0x00, 0x= 60, +0x01, 0xc0, 0x0e, 0x7c, 0x6b, 0x9e, 0x93, 0x4e, 0x14, 0x65, 0x86, 0x00, 0x= 30, +0xe1, 0x93, 0x4e, 0x18, 0x65, 0x2b, 0x8c, 0x91, 0x4e, 0x50, 0xe1, 0x81, 0x= 4e, +0xc8, 0xe9, 0x1e, 0xbe, 0x1e, 0x7e, 0x11, 0x8f, 0x9e, 0xbc, 0xd8, 0x55, 0x= 30, +0xef, 0x06, 0x00, 0x00, 0x64, 0x46, 0x02, 0x54, 0xe1, 0x0e, 0x3e, 0x06, 0x= 00, +0x20, 0xe0, 0x0e, 0x7e, 0x86, 0x00, 0x30, 0xe1, 0x1e, 0x7c, 0x11, 0x91, 0x= 9e, +0x3c, 0x2b, 0x8c, 0xd8, 0x54, 0x30, 0xef, 0x06, 0x00, 0x00, 0x66, 0xa1, 0x= 83, +0x0e, 0x3e, 0xf6, 0x41, 0xfc, 0xe9, 0x0e, 0x7e, 0x06, 0x00, 0x01, 0x60, 0x= 20, +0xc0, 0x0e, 0x7c, 0x86, 0x00, 0x30, 0xe1, 0xae, 0x3c, 0x11, 0x93, 0xc8, 0x= 53, +0x30, 0x6f, 0x2b, 0x8c, 0x06, 0x40, 0x88, 0x60, 0xf6, 0x45, 0xfc, 0x63, 0x= ff, +0xc3, 0x14, 0x00, 0xf1, 0xa0, 0x95, 0x4e, 0xa8, 0xe2, 0xa1, 0x4e, 0x44, 0x= ea, +0x81, 0x4e, 0xf0, 0x69, 0x10, 0x42, 0x00, 0x7c, 0x00, 0xcc, 0x1f, 0x04, 0x= 21, +0x8b, 0x1e, 0x00, 0x86, 0x40, 0xfc, 0xe7, 0x05, 0x4e, 0xa4, 0x62, 0xc6, 0x= 01, +0x5c, 0xe0, 0x05, 0x4e, 0xac, 0x62, 0x9e, 0x00, 0x00, 0x60, 0x02, 0xc0, 0x= 05, +0x4e, 0x94, 0x62, 0x86, 0x40, 0x3c, 0x60, 0x10, 0xe7, 0x0e, 0x9c, 0x09, 0x= 0e, +0x0c, 0xe1, 0x15, 0x4e, 0x3c, 0x79, 0x06, 0x02, 0x80, 0xe0, 0x13, 0x4e, 0x= f4, +0x64, 0x86, 0x02, 0x00, 0x60, 0x02, 0xc0, 0x21, 0x4e, 0x5c, 0x69, 0x00, 0x= 40, +0xc0, 0xf3, 0x1e, 0x9e, 0x01, 0x4e, 0x0c, 0xe1, 0x0c, 0x0c, 0x3c, 0xf2, 0x= 93, +0xdd, 0xc6, 0x01, 0xcc, 0x60, 0x06, 0x42, 0x88, 0xe0, 0x29, 0x00, 0x98, 0x= ee, +0x34, 0x84, 0x4a, 0x44, 0x80, 0x60, 0x86, 0x04, 0x30, 0xe1, 0x24, 0x08, 0x= 30, +0x46, 0xfd, 0x73, 0xff, 0xc3, 0x3e, 0x04, 0xa6, 0x08, 0xa0, 0x80, 0x34, 0x= 06, +0xc8, 0x9c, 0x45, 0x44, 0xa0, 0x80, 0x35, 0x42, 0x00, 0x00, 0x06, 0x06, 0x= 00, +0xc0, 0x35, 0x44, 0xa0, 0xc0, 0x35, 0x02, 0x00, 0xc0, 0x3e, 0x80, 0x93, 0x= dd, +0x4c, 0x00, 0x00, 0xfa, 0x88, 0x40, 0x00, 0xe8, 0x86, 0x02, 0x0c, 0xe1, 0x= 0e, +0x84, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x= 04, +0x00, 0xf8, 0xc6, 0x40, 0xb4, 0xe0, 0x00, 0x02, 0xb1, 0x64, 0x01, 0xc0, 0x= 2a, +0xc4, 0x2b, 0xa1, 0x35, 0x92, 0x24, 0xc4, 0x2b, 0xa1, 0xc5, 0x90, 0x38, 0x= 06, +0x46, 0x45, 0x00, 0xe0, 0x36, 0x46, 0x0a, 0xe0, 0x33, 0x80, 0x49, 0x06, 0x= f0, +0xe2, 0x4d, 0xe6, 0xc6, 0x40, 0x48, 0x41, 0x16, 0x02, 0x00, 0xc0, 0x11, 0x= 40, +0x00, 0xc0, 0xd5, 0x8c, 0xc9, 0x06, 0x44, 0x62, 0x06, 0x4b, 0x00, 0xe0, 0x= 46, +0x48, 0x16, 0x60, 0x86, 0x4a, 0xc8, 0xe0, 0x53, 0x08, 0xc0, 0x58, 0x80, 0x= f3, +0x49, 0x0a, 0xa4, 0xe7, 0x6b, 0x0a, 0xd8, 0xe3, 0x49, 0xbe, 0xcf, 0xa8, 0x= c1, +0x46, 0x44, 0xe2, 0x48, 0x86, 0xc9, 0x0a, 0xa0, 0xe7, 0x46, 0x48, 0x0a, 0x= e0, +0xc1, 0x46, 0x40, 0xe2, 0xcb, 0x0a, 0xe0, 0x63, 0x43, 0x80, 0x63, 0x48, 0x= 28, +0xe1, 0x38, 0x86, 0x36, 0x46, 0x0a, 0xe0, 0x33, 0x80, 0xc3, 0x46, 0x30, 0x= e1, +0x18, 0x86, 0xcb, 0x0a, 0xd4, 0xe3, 0x2b, 0x0a, 0xdc, 0x63, 0x16, 0x42, 0x= 0a, +0xe0, 0x5b, 0x0a, 0xe4, 0xe3, 0xc3, 0x48, 0x24, 0x61, 0x03, 0x82, 0x23, 0x= 46, +0x2c, 0xe1, 0x53, 0x40, 0x34, 0xe1, 0x4c, 0x0c, 0x00, 0xf0, 0x93, 0xdd, 0x= c3, +0xc1, 0x0c, 0x00, 0x80, 0xfa, 0x86, 0x43, 0xcc, 0x60, 0x0b, 0xa3, 0x29, 0x= 02, +0xc4, 0xee, 0xb5, 0x84, 0x4a, 0x04, 0xfc, 0xfb, 0x45, 0x84, 0xc6, 0x40, 0x= 84, +0xe0, 0x14, 0x82, 0x18, 0x84, 0x19, 0x86, 0x1b, 0xa5, 0x85, 0x8c, 0x04, 0x= 80, +0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, 0xc5, 0x8a, 0x0c, 0x08, 0x= 80, +0xf2, 0x08, 0x34, 0x44, 0xff, 0x0b, 0xa5, 0x15, 0x8a, 0x0a, 0x04, 0x04, 0x= f0, +0xb5, 0x88, 0xc6, 0x40, 0x84, 0xe0, 0x24, 0x82, 0x28, 0x88, 0x29, 0x86, 0x= 2b, +0xa5, 0xc5, 0x86, 0x04, 0x80, 0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0x= e0, +0x05, 0x86, 0x09, 0x02, 0x24, 0xee, 0x0b, 0xa3, 0xd5, 0x80, 0x08, 0x84, 0x= 0a, +0x40, 0x80, 0xe0, 0x75, 0xf8, 0xf5, 0x81, 0x38, 0x72, 0x44, 0xef, 0xf8, 0x= 51, +0xfc, 0xef, 0x4e, 0x40, 0x01, 0x60, 0x10, 0xc0, 0x08, 0x80, 0x0b, 0xa1, 0x= a5, +0x80, 0x0c, 0x08, 0x80, 0xf2, 0xb8, 0x11, 0xfc, 0xff, 0x0c, 0x08, 0x80, 0x= f2, +0x93, 0xdd, 0xcc, 0x04, 0x0c, 0xfa, 0x06, 0x4f, 0x84, 0x60, 0x86, 0x50, 0x= 4c, +0xe1, 0x04, 0x1c, 0x80, 0x0c, 0x21, 0x6f, 0x01, 0xc0, 0xf0, 0x04, 0x50, 0x= 64, +0x11, 0x81, 0x09, 0x00, 0x6c, 0xe0, 0x06, 0x29, 0x0b, 0x8c, 0x58, 0x4c, 0x= 58, +0xef, 0x04, 0x9c, 0x19, 0x00, 0x6c, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, 0x= a3, +0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, 0x= 2f, +0xa2, 0x21, 0x40, 0x6c, 0xe0, 0x86, 0x43, 0xcc, 0xe0, 0x29, 0x02, 0x24, 0x= ee, +0x2b, 0xa3, 0xd5, 0x80, 0x18, 0x84, 0x4a, 0x42, 0x80, 0x60, 0x11, 0x8b, 0x= 65, +0x80, 0x19, 0x00, 0x70, 0xe0, 0x16, 0x29, 0xf0, 0x04, 0x50, 0xe4, 0x11, 0x= 03, +0x0b, 0x8c, 0x28, 0x4a, 0x58, 0xef, 0x04, 0x9c, 0x19, 0x00, 0x70, 0xe0, 0x= 10, +0x44, 0x3c, 0xf0, 0x2b, 0xa3, 0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0x= f3, +0x27, 0xc8, 0x29, 0xa0, 0x2f, 0xa2, 0x21, 0x40, 0x70, 0xe0, 0x09, 0x00, 0x= 74, +0x60, 0xf0, 0x04, 0x50, 0xe4, 0x11, 0x85, 0x06, 0x29, 0x0b, 0x8c, 0xa8, 0x= 48, +0x58, 0xef, 0x04, 0x9c, 0x19, 0x00, 0x74, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x= 2b, +0xa3, 0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0x= a0, +0x2f, 0xa2, 0x21, 0x40, 0x74, 0xe0, 0x09, 0x00, 0x78, 0x60, 0xf0, 0x04, 0x= 50, +0xe4, 0x11, 0x87, 0x06, 0x29, 0x0b, 0x8c, 0x28, 0x47, 0x58, 0xef, 0x04, 0x= 9c, +0x19, 0x00, 0x78, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, 0xa3, 0x35, 0x82, 0x= 28, +0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, 0x2f, 0xa2, 0x21, 0x= 40, +0x78, 0xe0, 0x19, 0x0e, 0xd0, 0xe0, 0x1b, 0xa1, 0x85, 0x86, 0x05, 0x00, 0x= 24, +0xe0, 0x1a, 0xa2, 0x04, 0x04, 0xc0, 0xe1, 0x2b, 0x83, 0xd5, 0x80, 0x19, 0x= 10, +0x10, 0x60, 0x09, 0x9e, 0x0b, 0x83, 0x85, 0x84, 0x08, 0xa0, 0x0b, 0xa1, 0x= 38, +0x61, 0x74, 0xcf, 0x58, 0x49, 0x34, 0xef, 0x14, 0x9c, 0x25, 0x02, 0x24, 0x= e0, +0x24, 0x02, 0xc0, 0x61, 0x29, 0x9e, 0x18, 0x58, 0x74, 0xef, 0x55, 0x81, 0x= 08, +0xa0, 0x0b, 0xa1, 0x48, 0x60, 0x74, 0xcf, 0x28, 0x72, 0x4c, 0x6f, 0x46, 0x= 01, +0x08, 0xe0, 0xcc, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x65, 0x5e, 0x= 04, +0xfa, 0xf0, 0x0c, 0x10, 0xec, 0x60, 0x5e, 0x1c, 0x74, 0x61, 0x88, 0x6e, 0x= bc, +0xfc, 0x07, 0x80, 0xfe, 0xf0, 0x1e, 0x20, 0x6c, 0xe6, 0x40, 0x00, 0xe0, 0x= c8, +0x70, 0x4c, 0xef, 0x0b, 0xa1, 0xb5, 0x88, 0xc6, 0x0d, 0xdc, 0xe0, 0x09, 0x= 0c, +0x94, 0xea, 0x0b, 0xa3, 0xf5, 0x80, 0x09, 0x0c, 0x91, 0x79, 0x01, 0xc0, 0x= 0a, +0x40, 0x80, 0xe0, 0xe5, 0x82, 0xc8, 0x71, 0x44, 0xef, 0x04, 0x18, 0x86, 0x= 02, +0x84, 0xe0, 0x24, 0x04, 0x31, 0x83, 0x01, 0x82, 0x0e, 0x18, 0xe6, 0x00, 0x= 48, +0xe1, 0x36, 0x00, 0x21, 0x82, 0x2e, 0x84, 0x46, 0x00, 0x2c, 0x61, 0x21, 0x= 83, +0x14, 0x00, 0x46, 0x40, 0x34, 0xe1, 0x25, 0x42, 0x44, 0xe0, 0x28, 0x51, 0x= 28, +0xef, 0x88, 0x40, 0x00, 0xe8, 0xf1, 0x90, 0xfc, 0x0f, 0x80, 0xf6, 0xf4, 0x= bc, +0x64, 0xfd, 0x53, 0xc1, 0x4c, 0x00, 0x00, 0xfa, 0x01, 0x03, 0x11, 0x81, 0x= 48, +0x79, 0x08, 0xef, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x= 00, +0x00, 0xfa, 0x0d, 0x62, 0x8e, 0x45, 0xf0, 0xff, 0x75, 0x82, 0x4e, 0x05, 0x= 01, +0x60, 0x10, 0x40, 0x07, 0xc8, 0x24, 0x88, 0x23, 0x80, 0x1e, 0x8a, 0x78, 0x= 40, +0x00, 0xe8, 0x21, 0x81, 0x0b, 0x84, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0x= 83, +0xc1, 0x93, 0xdd, 0x0c, 0x04, 0x00, 0xfa, 0x41, 0xb9, 0x06, 0x48, 0x12, 0x= e0, +0x33, 0x88, 0x45, 0x06, 0x14, 0xe0, 0x4b, 0xa3, 0xc5, 0x80, 0x35, 0x06, 0x= 18, +0xe0, 0x3b, 0x23, 0x31, 0x81, 0x55, 0x80, 0x31, 0x83, 0x0d, 0xe6, 0x04, 0x= 00, +0x88, 0x00, 0x4e, 0x08, 0x00, 0x00, 0x10, 0x80, 0x05, 0x00, 0x10, 0x9c, 0x= 08, +0x40, 0x00, 0x98, 0x25, 0x0b, 0x8e, 0x40, 0xf0, 0xff, 0x3b, 0xa1, 0x45, 0x= 8a, +0x2b, 0x23, 0x06, 0x4c, 0x00, 0xe0, 0x45, 0x90, 0x2b, 0x25, 0x6e, 0x40, 0x= f0, +0xff, 0x25, 0x87, 0x3b, 0xa1, 0x25, 0x8a, 0x2b, 0x23, 0x06, 0x0c, 0x08, 0x= e0, +0x05, 0x8e, 0x2b, 0x25, 0x5e, 0x40, 0xf0, 0xff, 0x85, 0x0c, 0x06, 0x0c, 0x= 04, +0xe0, 0x95, 0x87, 0x3b, 0xa1, 0xc5, 0x88, 0x2b, 0x23, 0x61, 0x91, 0x85, 0x= 8a, +0x2b, 0x25, 0x7e, 0x40, 0xf0, 0xff, 0x25, 0x83, 0x2b, 0xa3, 0xc5, 0x08, 0x= 06, +0x0c, 0x08, 0x80, 0x2b, 0x25, 0x4e, 0x40, 0xf0, 0xff, 0x15, 0x8a, 0xf5, 0x= 03, +0x06, 0x0c, 0x04, 0xe0, 0x2b, 0x23, 0x61, 0x91, 0x45, 0x86, 0x2b, 0x25, 0x= 6e, +0x40, 0xf0, 0xff, 0xc5, 0x04, 0x61, 0x89, 0xc5, 0x83, 0x2b, 0x23, 0x06, 0x= 4c, +0x00, 0xe0, 0x05, 0x84, 0x2b, 0x25, 0x5e, 0x40, 0xf0, 0xff, 0x85, 0x02, 0x= 61, +0xa1, 0x25, 0x83, 0x2b, 0x23, 0x61, 0x85, 0xe5, 0x80, 0x2b, 0x25, 0x7e, 0x= 40, +0xf0, 0xff, 0x65, 0x00, 0x61, 0x83, 0x95, 0x81, 0x0b, 0x02, 0x1b, 0x8c, 0x= 48, +0x78, 0xfc, 0xef, 0x0b, 0xa1, 0x00, 0x4c, 0x00, 0xdc, 0x0b, 0x8c, 0x0c, 0x= 0c, +0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x04, 0xfa, 0x6b, 0x00, 0x= c6, +0x40, 0xdc, 0xe0, 0x04, 0x00, 0xf0, 0x1e, 0x30, 0xec, 0x48, 0x55, 0xfc, 0x= 6e, +0x0e, 0x02, 0x24, 0x74, 0x03, 0xc0, 0xb8, 0x68, 0xfc, 0xee, 0x58, 0x71, 0x= 08, +0xef, 0x78, 0x68, 0xfc, 0x6e, 0x0b, 0x8c, 0x71, 0x01, 0x5b, 0x80, 0x7e, 0x= 3c, +0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0, 0x11, 0x03, 0x21, 0x81, 0x31, 0x05, 0x= 41, +0x81, 0xa8, 0x77, 0x08, 0xef, 0x0e, 0x3e, 0x0e, 0x00, 0x05, 0x60, 0x10, 0x= c0, +0x48, 0x4b, 0x0c, 0xef, 0x0e, 0x7c, 0x11, 0x81, 0x04, 0x3e, 0x21, 0x83, 0x= 68, +0x76, 0xfc, 0x6f, 0x0e, 0x06, 0x04, 0x60, 0x10, 0xc0, 0xce, 0x0d, 0x01, 0x= 60, +0x10, 0xc0, 0x76, 0x98, 0x04, 0xfc, 0xc8, 0x59, 0x0c, 0xef, 0x13, 0xc3, 0x= 08, +0x98, 0x0b, 0xa1, 0xa5, 0xfe, 0x04, 0xfc, 0x18, 0x5c, 0x0c, 0xef, 0x14, 0x= 3e, +0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0, 0x38, 0x46, 0x0c, 0xef, 0x01, 0x01, 0x= f1, +0x98, 0x0c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x65, 0x5e, 0x04, 0xfa, 0xf0, 0x= 0c, +0x10, 0xec, 0x60, 0x5e, 0x1c, 0x74, 0x61, 0x88, 0x6e, 0xbc, 0xfc, 0x03, 0x= 80, +0xfe, 0x26, 0x00, 0x4c, 0x61, 0x11, 0x83, 0x16, 0x00, 0xce, 0x01, 0x01, 0x= 60, +0x10, 0xc0, 0x16, 0x00, 0x46, 0x00, 0x2c, 0xe1, 0x04, 0x00, 0xf0, 0x1e, 0x= 30, +0xec, 0x14, 0xc0, 0x14, 0x02, 0x20, 0xfc, 0x1e, 0xc0, 0x98, 0x40, 0x00, 0x= e8, +0xf1, 0x98, 0xfc, 0x0b, 0x80, 0xf6, 0xf4, 0xbc, 0x64, 0xfd, 0x53, 0xc1, 0x= c3, +0xc1, 0x06, 0x00, 0x01, 0x60, 0x00, 0xe0, 0x06, 0x00, 0x62, 0xf4, 0x93, 0x= dd, +0x4c, 0x04, 0x7c, 0xfa, 0xc6, 0x54, 0x84, 0x60, 0x06, 0x0f, 0xdc, 0xe0, 0x= 04, +0x2a, 0xae, 0x4d, 0x01, 0x60, 0x10, 0xc0, 0x29, 0x14, 0x70, 0x60, 0x8e, 0x= 51, +0x00, 0x60, 0x10, 0xc0, 0x3b, 0x0e, 0x9c, 0x65, 0x06, 0x52, 0x94, 0xe0, 0x= 1b, +0x00, 0x20, 0x60, 0x0e, 0x57, 0x08, 0x60, 0x10, 0xc0, 0x0b, 0x00, 0x1c, 0x= e0, +0x13, 0x20, 0x01, 0x81, 0x13, 0x84, 0x13, 0x86, 0x11, 0x9e, 0x1c, 0x98, 0x= 0c, +0xa0, 0x04, 0xa4, 0x0b, 0x00, 0xa0, 0xe5, 0x0c, 0xac, 0x0a, 0x98, 0x1a, 0x= ac, +0x0d, 0xc3, 0xf5, 0x82, 0x04, 0xa4, 0x0b, 0x00, 0xa0, 0xe5, 0x0c, 0x2c, 0x= 01, +0x8b, 0x08, 0x56, 0x2c, 0xef, 0x0a, 0xa0, 0x01, 0x82, 0x0c, 0xa0, 0x0a, 0x= a0, +0x8a, 0x00, 0x24, 0xe7, 0xf5, 0xfa, 0x05, 0x0e, 0xbc, 0x61, 0x06, 0x04, 0x= 00, +0x60, 0x00, 0xf0, 0x13, 0x0e, 0xb8, 0x79, 0x06, 0x06, 0x00, 0x60, 0x00, 0x= e0, +0x2f, 0x80, 0x2b, 0x07, 0x0e, 0x45, 0x01, 0x60, 0x10, 0xc0, 0x1c, 0x88, 0x= 95, +0x86, 0x07, 0xe1, 0x09, 0xbe, 0x0b, 0xa1, 0x05, 0x86, 0x21, 0xff, 0x1d, 0x= 84, +0x85, 0x02, 0x00, 0x00, 0x08, 0x8c, 0x10, 0x04, 0x18, 0xec, 0x8a, 0x04, 0x= 14, +0xed, 0xb5, 0x80, 0x8a, 0x02, 0x40, 0xe1, 0x75, 0x82, 0x01, 0x84, 0x14, 0x= 24, +0x09, 0xbe, 0x29, 0x02, 0x00, 0xe3, 0x20, 0x44, 0x80, 0xf3, 0x2f, 0xa0, 0x= 21, +0x42, 0x00, 0xe3, 0x8e, 0x41, 0x09, 0x60, 0x10, 0x40, 0xc6, 0x0d, 0x30, 0x= e1, +0x04, 0x80, 0x0b, 0xa3, 0x75, 0xa0, 0x19, 0x0c, 0xcc, 0xe5, 0x4a, 0x02, 0x= fc, +0xfb, 0xc5, 0x9e, 0xa8, 0x54, 0x00, 0x68, 0x01, 0x81, 0x04, 0x24, 0x11, 0x= 85, +0x11, 0x40, 0x20, 0x60, 0x4e, 0x43, 0x00, 0x60, 0x10, 0xc0, 0x04, 0xa4, 0x= 29, +0x00, 0x50, 0xeb, 0x2e, 0x84, 0x24, 0x84, 0x29, 0x86, 0x2e, 0x84, 0x24, 0x= 84, +0x2b, 0xa1, 0x15, 0xfe, 0xa8, 0x52, 0x44, 0xef, 0x04, 0xaa, 0x08, 0x80, 0x= 0b, +0xa5, 0xe5, 0x80, 0x04, 0xa8, 0x09, 0x00, 0x20, 0xe1, 0x0b, 0xa1, 0x48, 0x= 4a, +0x44, 0x8f, 0x46, 0x10, 0x74, 0xe1, 0x04, 0xa0, 0x14, 0xc0, 0x14, 0x02, 0x= 2c, +0xfc, 0x1e, 0xc0, 0x14, 0xc0, 0x14, 0x02, 0x08, 0xfc, 0x1e, 0x40, 0x11, 0x= 83, +0x04, 0xa4, 0x11, 0x40, 0xb0, 0x67, 0x11, 0x81, 0x04, 0xa6, 0x11, 0x40, 0x= 10, +0xe0, 0xb8, 0x73, 0x74, 0xef, 0x84, 0x20, 0x70, 0x06, 0x00, 0xe7, 0x8e, 0x= 17, +0x01, 0x60, 0x10, 0x40, 0xce, 0x54, 0x01, 0x60, 0x10, 0xc0, 0x04, 0xe0, 0x= 04, +0x00, 0x04, 0xfc, 0x0e, 0xe0, 0x04, 0xe0, 0x04, 0x00, 0x0c, 0xfc, 0x0e, 0x= e0, +0x04, 0xe0, 0x04, 0x00, 0x10, 0xfc, 0x0e, 0xe0, 0x45, 0x10, 0x2c, 0xe0, 0x= 44, +0x00, 0x00, 0xfc, 0x05, 0x50, 0x2c, 0x60, 0x4e, 0x41, 0x08, 0x60, 0x10, 0x= c0, +0x1b, 0x0e, 0xa0, 0xe1, 0x04, 0x80, 0x2b, 0x0e, 0x9c, 0xe1, 0x1b, 0xc2, 0x= 03, +0x02, 0xce, 0x42, 0x01, 0x60, 0x10, 0xc0, 0x3e, 0x04, 0x03, 0x84, 0x00, 0x= 00, +0xf4, 0xec, 0x0e, 0xac, 0x09, 0x0e, 0x00, 0xe3, 0x4e, 0x8f, 0x0b, 0xa5, 0x= 0b, +0x0e, 0x10, 0xd8, 0x95, 0x96, 0x0b, 0x0e, 0x84, 0xe1, 0x15, 0x0e, 0x10, 0x= e0, +0x03, 0x4e, 0x10, 0xf8, 0x1d, 0xc1, 0x13, 0x4e, 0x10, 0x58, 0x10, 0x40, 0x= 00, +0xdc, 0x1a, 0x5e, 0x04, 0x04, 0x80, 0xfb, 0x2d, 0xc3, 0x13, 0x4e, 0x10, 0x= 58, +0x10, 0x40, 0x00, 0xdc, 0x85, 0x89, 0x0b, 0xa1, 0x98, 0x0c, 0x00, 0xc0, 0x= 68, +0x7b, 0x68, 0x6f, 0x01, 0x85, 0x60, 0x00, 0x10, 0x64, 0x11, 0x81, 0xc8, 0x= 71, +0x54, 0xef, 0x28, 0x45, 0x70, 0xef, 0x09, 0x0e, 0xe8, 0xea, 0x4a, 0x40, 0x= 90, +0xe0, 0x06, 0x00, 0x00, 0xc0, 0xa8, 0x4b, 0x00, 0xc8, 0x09, 0x0e, 0x5c, 0x= eb, +0x0a, 0x40, 0x80, 0xe0, 0x25, 0xac, 0x19, 0x0c, 0xcc, 0xe5, 0x4a, 0x02, 0x= fc, +0xfb, 0x85, 0xaa, 0x0a, 0x40, 0x90, 0xe0, 0x45, 0x82, 0x46, 0x00, 0x74, 0x= e1, +0x04, 0x80, 0x14, 0xc0, 0x14, 0x02, 0x2c, 0xfc, 0x1e, 0xc0, 0x09, 0x0e, 0x= 5c, +0xeb, 0x0a, 0x40, 0x84, 0xe0, 0x25, 0x82, 0xb8, 0x68, 0x30, 0x6f, 0x01, 0x= 81, +0xc8, 0x58, 0x2c, 0x6f, 0x0b, 0x8c, 0x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x= 94, +0xe0, 0x45, 0x82, 0x46, 0x00, 0x74, 0xe1, 0x04, 0x80, 0x14, 0xc0, 0x14, 0x= 02, +0x08, 0xfc, 0x1e, 0xc0, 0x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x98, 0xe0, 0x= 18, +0x49, 0x00, 0xc8, 0x45, 0x91, 0x14, 0x2c, 0x04, 0x00, 0x80, 0xfb, 0x13, 0x= 20, +0x06, 0x41, 0x2c, 0xe0, 0x16, 0x40, 0x02, 0x60, 0x46, 0x42, 0x04, 0xe0, 0x= c8, +0x7a, 0xf8, 0xee, 0x0e, 0x2c, 0x0e, 0x4c, 0x01, 0x60, 0x10, 0xc0, 0x04, 0x= ac, +0x00, 0x00, 0xd1, 0x6f, 0x0f, 0xc0, 0x0e, 0xac, 0x05, 0x10, 0x40, 0xe0, 0x= 04, +0x00, 0x38, 0xfc, 0x0e, 0x98, 0x05, 0x50, 0x40, 0xe0, 0x04, 0xac, 0xd8, 0x= 63, +0xfc, 0xef, 0x46, 0x10, 0x74, 0xe1, 0x04, 0xa0, 0x15, 0x00, 0x40, 0xe0, 0x= 14, +0x02, 0xb8, 0xfc, 0x1e, 0x98, 0x15, 0x40, 0x40, 0xe0, 0x98, 0x52, 0x30, 0x= ef, +0x0b, 0xa1, 0xa5, 0xfe, 0x34, 0x28, 0xc6, 0x0d, 0x30, 0xe1, 0x08, 0x8c, 0x= 0b, +0xa5, 0x0b, 0x0e, 0x04, 0xd8, 0x1b, 0x0e, 0x00, 0xc0, 0x2b, 0x0e, 0x04, 0x= c0, +0x3b, 0x0e, 0x08, 0xc0, 0x75, 0x84, 0x08, 0x8e, 0x19, 0x0e, 0x10, 0xeb, 0x= 12, +0x40, 0x80, 0xfb, 0x01, 0x4e, 0x10, 0xf8, 0x0a, 0xcc, 0x03, 0x4e, 0x04, 0x= f8, +0x1a, 0xce, 0x1c, 0x9c, 0x2b, 0x06, 0x10, 0xe0, 0x2c, 0x9e, 0x3b, 0x06, 0x= 14, +0xe0, 0x3c, 0xdc, 0xa4, 0x8f, 0x03, 0x4e, 0x80, 0xf9, 0x13, 0x4e, 0x7c, 0x= f9, +0x23, 0x4e, 0x78, 0xf9, 0x33, 0x4e, 0x74, 0xf9, 0xc8, 0x6d, 0x38, 0xef, 0x= e8, +0x66, 0x3c, 0xef, 0x04, 0x20, 0xa9, 0xc2, 0xa5, 0x40, 0x2c, 0xe0, 0x19, 0x= 0c, +0x40, 0xe6, 0x1b, 0xa1, 0x55, 0x88, 0x14, 0xc0, 0x19, 0xd0, 0x1e, 0xc0, 0x= 14, +0xc0, 0x19, 0xe0, 0x1e, 0xc0, 0x14, 0xc0, 0x19, 0xc4, 0x1e, 0x40, 0x01, 0x= 83, +0xa8, 0x41, 0x00, 0xe8, 0x04, 0xa0, 0x14, 0xc0, 0x14, 0x02, 0xac, 0xfc, 0x= 1e, +0xc0, 0x14, 0xc0, 0x19, 0xc8, 0x1e, 0xc0, 0x48, 0x51, 0x74, 0xef, 0x04, 0x= 26, +0x11, 0x83, 0x11, 0x40, 0x10, 0xe0, 0x04, 0xa4, 0x11, 0x40, 0x20, 0x60, 0x= 11, +0x81, 0x04, 0xa4, 0x11, 0x40, 0xb0, 0xe7, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0x= dd, +0x1b, 0x00, 0x06, 0x01, 0x38, 0xe1, 0x04, 0x80, 0xc8, 0x20, 0x04, 0x60, 0x= 01, +0xb8, 0xc3, 0xc1, 0x83, 0xc1, 0x13, 0xc3, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x= 04, +0x00, 0xfa, 0xe6, 0x41, 0x84, 0x60, 0x8e, 0x42, 0x00, 0x60, 0x10, 0xc0, 0x= 08, +0x80, 0x14, 0x84, 0x0b, 0x21, 0xa6, 0x41, 0x04, 0xe1, 0x1c, 0x80, 0x05, 0x= 82, +0x28, 0x47, 0x64, 0xef, 0x88, 0x7b, 0x28, 0x6f, 0x46, 0x40, 0x04, 0xe0, 0x= 35, +0x81, 0x38, 0x56, 0x40, 0xef, 0xd8, 0x67, 0x64, 0xef, 0x38, 0x63, 0x64, 0x= ef, +0xd8, 0x44, 0x44, 0xef, 0x06, 0x40, 0x94, 0xe0, 0x04, 0x80, 0x09, 0x00, 0x= 50, +0xeb, 0x0a, 0x40, 0x88, 0xe0, 0x76, 0x00, 0xa0, 0xc0, 0x68, 0x4e, 0x50, 0x= cf, +0xc6, 0x0d, 0x30, 0xe1, 0x09, 0x0c, 0x30, 0xe7, 0x0b, 0xa1, 0x78, 0x6c, 0x= 70, +0xcf, 0x98, 0x7f, 0x6c, 0xef, 0x38, 0x4b, 0x2c, 0x6f, 0x0b, 0x8c, 0xc8, 0x= 5a, +0x30, 0x6f, 0x01, 0x81, 0x58, 0x49, 0x30, 0xef, 0xb8, 0x5f, 0x70, 0xef, 0x= 01, +0x83, 0x01, 0x4c, 0xc0, 0xe5, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0x= c1, +0x0c, 0x04, 0x84, 0xfa, 0x06, 0x4e, 0x88, 0x60, 0x06, 0x0c, 0x0c, 0xe1, 0x= 05, +0x0e, 0x38, 0x78, 0x06, 0x04, 0x00, 0x70, 0x40, 0xc0, 0x19, 0x0c, 0x94, 0x= 78, +0x06, 0x06, 0x10, 0x60, 0x40, 0xc0, 0x08, 0xc0, 0x4a, 0x02, 0x00, 0xe0, 0x= 09, +0x86, 0x07, 0xc6, 0x2f, 0x61, 0x3f, 0xe1, 0x21, 0x4e, 0x10, 0xf8, 0x0c, 0x= 00, +0x00, 0xe2, 0x31, 0x4e, 0x0c, 0xf8, 0x18, 0x62, 0x30, 0xef, 0x05, 0x0e, 0x= 38, +0xf8, 0x14, 0x98, 0x09, 0x00, 0x24, 0xe0, 0x4a, 0x40, 0x88, 0xe0, 0x65, 0x= 82, +0x0b, 0x0c, 0x28, 0x78, 0x1b, 0xa1, 0x0c, 0xde, 0x05, 0x84, 0x0a, 0x01, 0x= 20, +0xec, 0xf5, 0x84, 0x55, 0x03, 0x01, 0x93, 0x0b, 0x0c, 0x24, 0x78, 0x1b, 0x= a1, +0x0c, 0xde, 0x65, 0x82, 0x0a, 0x01, 0x24, 0xec, 0xb5, 0x82, 0xb5, 0x01, 0x= 01, +0x95, 0x0a, 0x01, 0x48, 0xec, 0x15, 0x82, 0x65, 0x01, 0x01, 0xa7, 0x0a, 0x= 01, +0x50, 0xec, 0x75, 0x80, 0x01, 0xab, 0x0c, 0xde, 0x15, 0x0c, 0x20, 0x79, 0x= 06, +0x04, 0x00, 0x60, 0x00, 0xf0, 0x49, 0x0c, 0x64, 0x78, 0x06, 0x06, 0x00, 0x= 60, +0x00, 0xe0, 0x2f, 0x82, 0x3b, 0x0c, 0x8c, 0x78, 0x2b, 0x87, 0x30, 0x42, 0x= 00, +0x5c, 0x4a, 0x08, 0x14, 0xfc, 0x14, 0x04, 0x80, 0x7a, 0xce, 0x43, 0x00, 0x= 60, +0x10, 0xc0, 0x2c, 0x04, 0x8e, 0x48, 0x01, 0x60, 0x10, 0xc0, 0x3e, 0x90, 0x= 85, +0x88, 0x45, 0x0e, 0x30, 0xf8, 0x3b, 0x08, 0x18, 0xe0, 0x5b, 0x08, 0x20, 0x= e0, +0x4b, 0x08, 0x1c, 0xe0, 0x32, 0x4a, 0x94, 0xf1, 0x53, 0x88, 0x8a, 0x0a, 0x= 89, +0x63, 0x05, 0xc0, 0xb5, 0x84, 0x54, 0x1a, 0x8e, 0x59, 0x09, 0x60, 0x10, 0x= c0, +0x71, 0x83, 0x7e, 0x30, 0x2e, 0x59, 0x09, 0x60, 0x10, 0xc0, 0x5c, 0x30, 0x= 54, +0x08, 0x80, 0xfb, 0x4d, 0x44, 0x4e, 0x45, 0x09, 0x60, 0x10, 0xc0, 0x3e, 0x= 88, +0x43, 0x42, 0x00, 0xc0, 0x65, 0x81, 0x8e, 0x43, 0x09, 0x60, 0x10, 0x40, 0x= 21, +0x81, 0x2e, 0x84, 0x03, 0x4c, 0xd5, 0x79, 0x02, 0x40, 0xd6, 0x41, 0x00, 0x= e0, +0x0c, 0x0c, 0x84, 0xf2, 0x18, 0x34, 0x48, 0xff, 0xc3, 0xc1, 0x0c, 0x04, 0x= fc, +0xfa, 0x6b, 0x00, 0x06, 0x41, 0x08, 0xe0, 0x98, 0x73, 0x48, 0xef, 0x0b, 0x= a1, +0x78, 0x14, 0x00, 0xc0, 0x86, 0x52, 0x84, 0xe0, 0x74, 0xe4, 0x08, 0x9c, 0x= 09, +0x86, 0x0b, 0xa3, 0x36, 0x40, 0x98, 0x40, 0x06, 0x02, 0x00, 0xc0, 0x11, 0x= 40, +0x00, 0xc0, 0xf5, 0x80, 0x21, 0x01, 0x36, 0x40, 0x98, 0xe0, 0x2e, 0x18, 0x= 11, +0x83, 0x16, 0x80, 0x84, 0x26, 0x16, 0x44, 0x98, 0xe0, 0x18, 0x9c, 0x09, 0x= 10, +0xb4, 0xe0, 0x0a, 0x02, 0x0c, 0xfc, 0x0c, 0x02, 0x00, 0xe2, 0x01, 0x4c, 0x= 10, +0xe1, 0x0b, 0x10, 0x80, 0xe0, 0x16, 0x88, 0xe8, 0x75, 0xf8, 0xee, 0x05, 0x= 4c, +0x48, 0xe0, 0x08, 0x9c, 0x00, 0x42, 0x08, 0xfc, 0x19, 0x86, 0x1b, 0xa5, 0x= d5, +0x80, 0x4a, 0x00, 0x0c, 0xf8, 0x0c, 0x00, 0x00, 0xe2, 0x0e, 0x98, 0x09, 0x= 10, +0xb0, 0xe0, 0x98, 0x51, 0x00, 0x68, 0x09, 0x82, 0x01, 0x4c, 0x18, 0x60, 0x= 11, +0x9f, 0x0b, 0x10, 0x88, 0xe0, 0x78, 0x51, 0x00, 0xe8, 0x14, 0xa6, 0x05, 0x= 4c, +0x4c, 0xe0, 0x0b, 0x02, 0x84, 0x60, 0x11, 0x91, 0xf8, 0x50, 0x00, 0xe8, 0x= b4, +0xa6, 0x05, 0x4c, 0x50, 0xe0, 0x09, 0x16, 0xd0, 0xe0, 0x0a, 0x40, 0x84, 0x= 60, +0x06, 0x00, 0x00, 0x60, 0x48, 0xd0, 0x56, 0x01, 0x55, 0x15, 0x41, 0xd0, 0x= 05, +0x4c, 0x34, 0xe0, 0x09, 0x16, 0xd0, 0xe0, 0x68, 0x4f, 0x00, 0x68, 0x09, 0x= 82, +0x14, 0x64, 0x06, 0x54, 0xdc, 0xe0, 0x01, 0x4c, 0x10, 0x60, 0xce, 0x41, 0x= 00, +0x60, 0x10, 0xc0, 0x0a, 0x80, 0x2b, 0x02, 0x18, 0xe0, 0x23, 0xa0, 0x23, 0x= 4c, +0x60, 0xe0, 0x09, 0x14, 0x70, 0xea, 0x22, 0x40, 0x80, 0xf1, 0x03, 0x4c, 0x= 60, +0xe0, 0x25, 0x14, 0xe0, 0xe2, 0x2b, 0xa3, 0x35, 0x88, 0x24, 0xa4, 0x3b, 0x= 02, +0x18, 0xe0, 0x4b, 0x02, 0x20, 0xe0, 0x1b, 0x02, 0x1c, 0xe0, 0x59, 0x04, 0x= 24, +0xe0, 0x33, 0xa8, 0x32, 0x44, 0x84, 0x70, 0x2e, 0x47, 0x08, 0x60, 0x10, 0x= c0, +0x20, 0x02, 0xfc, 0x6c, 0x0a, 0x4a, 0x88, 0xe0, 0x1c, 0x0c, 0x20, 0x02, 0x= 14, +0xcc, 0x10, 0x02, 0xf0, 0xcc, 0x13, 0x46, 0x00, 0x40, 0x0a, 0x41, 0x04, 0x= ec, +0x13, 0x4c, 0x60, 0x40, 0x10, 0x40, 0x00, 0xdc, 0x15, 0x14, 0xdc, 0x62, 0x= 04, +0x00, 0x80, 0xfb, 0x86, 0x05, 0x74, 0xe1, 0x1d, 0xc1, 0x13, 0x4c, 0x60, 0x= 40, +0x14, 0x00, 0x80, 0xdb, 0x14, 0xa4, 0x0e, 0xa8, 0x04, 0x88, 0x7a, 0x84, 0x= 73, +0x4c, 0x64, 0xe0, 0xe8, 0x6d, 0xf8, 0xee, 0x1b, 0x00, 0x8e, 0x40, 0xb1, 0x= 66, +0x9b, 0xd3, 0x08, 0x6d, 0xf8, 0xee, 0x8b, 0x00, 0x0b, 0x8e, 0x85, 0x4c, 0x= 3c, +0xe0, 0x28, 0x6d, 0xf8, 0xee, 0x1b, 0x00, 0x0b, 0x90, 0x28, 0x6d, 0xf8, 0x= ee, +0x48, 0x6c, 0xf8, 0x6e, 0x0e, 0x02, 0x00, 0x60, 0x1e, 0xd1, 0x05, 0x4c, 0x= 40, +0x60, 0x11, 0x91, 0x0b, 0x16, 0x64, 0xe0, 0x7b, 0x16, 0x5c, 0xe0, 0x89, 0x= 16, +0xc0, 0xe0, 0x08, 0x49, 0x00, 0xe8, 0x3b, 0x00, 0x80, 0x44, 0x7c, 0xf0, 0x= 81, +0x01, 0x11, 0x81, 0xb8, 0x40, 0x40, 0x6f, 0x0b, 0x8e, 0x4b, 0x0c, 0x60, 0x= 60, +0x06, 0x0e, 0x00, 0x60, 0xe0, 0xcf, 0x0e, 0x5a, 0x11, 0x81, 0x21, 0x01, 0x= 06, +0x06, 0x01, 0x60, 0xe0, 0xcf, 0xd8, 0x7f, 0x3c, 0x6f, 0x0b, 0x88, 0x14, 0x= 64, +0x86, 0x57, 0x94, 0xe1, 0x05, 0x4c, 0x2c, 0xe0, 0x0a, 0x86, 0x83, 0x4c, 0x= e4, +0xe0, 0x03, 0x4c, 0xe0, 0xe0, 0x08, 0x86, 0x09, 0xbe, 0x03, 0x4c, 0xe8, 0x= e0, +0x08, 0x86, 0x09, 0xbe, 0x07, 0xc4, 0x05, 0x00, 0x2c, 0xfc, 0x05, 0x4c, 0x= 54, +0xe0, 0x0a, 0xc4, 0x03, 0x4c, 0xec, 0xe0, 0x0a, 0x44, 0x11, 0x91, 0xe8, 0x= 45, +0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x58, 0xe0, 0x0a, 0x46, 0x11, 0x91, 0x= 78, +0x45, 0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x5c, 0xe0, 0x0b, 0x02, 0x10, 0x= 60, +0x11, 0x91, 0xf8, 0x44, 0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x60, 0xe0, 0x= 0b, +0x02, 0x14, 0x60, 0x11, 0x91, 0x78, 0x44, 0x00, 0xe8, 0x14, 0xa6, 0x05, 0x= 4c, +0x64, 0xe0, 0x85, 0x4c, 0x14, 0xe0, 0x85, 0x4c, 0x18, 0xe0, 0x0b, 0x02, 0x= 7c, +0x60, 0x11, 0x91, 0xb8, 0x43, 0x00, 0xe8, 0x05, 0x4c, 0x10, 0x60, 0x11, 0x= 91, +0x81, 0x4c, 0x14, 0xe0, 0x75, 0x4c, 0x1c, 0xe0, 0x09, 0x14, 0xd0, 0xea, 0x= 07, +0xc4, 0x05, 0x00, 0x2c, 0xfc, 0x05, 0x4c, 0x20, 0xe0, 0x0b, 0x14, 0x94, 0x= e5, +0x98, 0x42, 0x00, 0xe8, 0x05, 0x4c, 0x38, 0x60, 0x11, 0x91, 0x0b, 0x14, 0x= 64, +0xe5, 0x28, 0x42, 0x00, 0xe8, 0x05, 0x4c, 0x28, 0x60, 0x11, 0x81, 0x09, 0x= 14, +0x8c, 0x6a, 0x21, 0x81, 0x0b, 0x12, 0x7c, 0x60, 0x0a, 0x40, 0x88, 0xe0, 0x= d6, +0x0e, 0xcd, 0x0c, 0x73, 0xcf, 0x75, 0x4c, 0x24, 0x60, 0x3b, 0x8e, 0x28, 0x= 79, +0x3c, 0xef, 0x0e, 0xd8, 0x16, 0x41, 0x08, 0xe0, 0x0c, 0x0c, 0xfc, 0xf2, 0x= b8, +0x1e, 0x48, 0xff, 0xc3, 0xc1, 0x4a, 0x00, 0x00, 0xe0, 0x0c, 0x00, 0x00, 0x= e2, +0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x00, 0x00, 0xfa, 0x88, 0x61, 0x28, 0xef, 0x= 4c, +0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x88, 0x= 5d, +0x48, 0x6f, 0xf6, 0x40, 0x04, 0xe0, 0x0b, 0xa1, 0x85, 0x80, 0x0c, 0x0c, 0x= 00, +0xf2, 0x93, 0xdd, 0xb8, 0x6b, 0x54, 0xef, 0xc6, 0x4c, 0x84, 0xe0, 0x04, 0x= 98, +0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, 0x85, 0x88, 0xc6, 0x40, 0x= b4, +0x60, 0x46, 0x45, 0x00, 0xe0, 0x19, 0x00, 0xb4, 0xe4, 0x16, 0x42, 0x0a, 0x= e0, +0x03, 0x82, 0x09, 0x00, 0x40, 0xe2, 0x0b, 0xa5, 0xf5, 0x84, 0x48, 0x56, 0x= 40, +0x6f, 0x01, 0x85, 0x58, 0x4c, 0x40, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0xd8, 0x= 7d, +0x44, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0x58, 0x50, 0x40, 0xef, 0x18, 0x70, 0x= f4, +0xef, 0x4e, 0x40, 0x01, 0x60, 0x10, 0xc0, 0x08, 0x80, 0x0b, 0xa1, 0x08, 0x= 70, +0xf4, 0xcf, 0x09, 0x0c, 0x48, 0xe0, 0x0b, 0xa1, 0x95, 0x84, 0xe8, 0x70, 0x= 38, +0xef, 0x06, 0x40, 0x94, 0x60, 0x16, 0x07, 0x04, 0xe1, 0x04, 0x80, 0x1b, 0x= 00, +0x18, 0xe1, 0x2b, 0x00, 0x50, 0xe1, 0x48, 0x8c, 0x39, 0x06, 0xac, 0xe0, 0x= 13, +0xa4, 0x13, 0xa8, 0x13, 0xa6, 0x15, 0x40, 0x2c, 0xe0, 0xc6, 0x00, 0x2c, 0x= 61, +0x11, 0xa1, 0x04, 0x80, 0x13, 0x40, 0xd0, 0x65, 0xe6, 0x40, 0xe0, 0xe0, 0x= 0a, +0x00, 0x06, 0x42, 0x94, 0xe0, 0x14, 0x84, 0x03, 0x42, 0x10, 0x62, 0x06, 0x= 41, +0x04, 0xe0, 0x0c, 0x0c, 0x00, 0xf2, 0x98, 0x17, 0x48, 0xff, 0xc3, 0xc1, 0x= 66, +0x01, 0xcc, 0xe0, 0x18, 0x80, 0x0a, 0x42, 0x84, 0xe0, 0x10, 0x42, 0xf8, 0x= d3, +0x11, 0x40, 0x00, 0xc0, 0x93, 0xdd, 0x4a, 0x40, 0x80, 0xe0, 0x55, 0x84, 0x= 14, +0x04, 0xa0, 0x60, 0x0e, 0x06, 0x00, 0x70, 0x3f, 0xc0, 0x2f, 0x06, 0x14, 0x= 06, +0xa0, 0xe1, 0x14, 0x00, 0xe0, 0x61, 0x30, 0x46, 0x00, 0x70, 0xff, 0xc0, 0x= 17, +0x70, 0x3f, 0xa0, 0x1f, 0xa4, 0x1f, 0xa6, 0x93, 0x5d, 0x0b, 0x82, 0x4c, 0x= 04, +0x04, 0xfa, 0x86, 0x0d, 0xcc, 0x60, 0x71, 0x81, 0x7c, 0x98, 0x88, 0x55, 0x= 68, +0xef, 0x0a, 0x98, 0x00, 0x42, 0xf1, 0x73, 0xff, 0xc0, 0x19, 0xc2, 0x1c, 0x= 18, +0x60, 0x02, 0xe1, 0x65, 0x02, 0xc0, 0x65, 0x81, 0x24, 0x84, 0x2b, 0xa1, 0x= f5, +0x80, 0x71, 0x02, 0x11, 0x88, 0x0a, 0x0e, 0x00, 0xe1, 0x35, 0xfe, 0x75, 0x= 81, +0x77, 0x50, 0x00, 0x40, 0xf0, 0xf3, 0x0f, 0xae, 0x09, 0xc4, 0x0c, 0x98, 0x= 4c, +0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x4c, 0x04, 0x7c, 0xfa, 0xbb, 0x06, 0x6b, 0x= 82, +0x14, 0x2c, 0x9b, 0x80, 0x74, 0x24, 0xab, 0x84, 0xa4, 0x00, 0xa0, 0x61, 0x= 8b, +0x88, 0x1b, 0x81, 0x65, 0x82, 0x0e, 0x2c, 0x0b, 0x8e, 0x78, 0x56, 0x30, 0x= 6f, +0x1b, 0x8c, 0x24, 0x2c, 0x0b, 0x8e, 0x28, 0x59, 0x30, 0x6f, 0x1b, 0x8c, 0x= 04, +0x18, 0xb1, 0x83, 0x11, 0x01, 0x21, 0x83, 0x38, 0x44, 0x00, 0x68, 0x31, 0x= 85, +0xa4, 0x02, 0x80, 0x7a, 0x21, 0x8b, 0xd8, 0x43, 0x00, 0x68, 0x06, 0x46, 0x= fc, +0xe1, 0xab, 0x00, 0x0b, 0x8e, 0x78, 0x40, 0xf8, 0x6f, 0x1b, 0x94, 0x09, 0x= 12, +0x10, 0x60, 0x1b, 0x90, 0x98, 0x79, 0xfc, 0x6f, 0x70, 0x12, 0x10, 0xe4, 0x= 1b, +0x00, 0x0b, 0x92, 0xb8, 0x7f, 0xf4, 0xef, 0x11, 0x03, 0x21, 0x85, 0x31, 0x= 09, +0x0b, 0x94, 0x58, 0x42, 0x00, 0xe8, 0x8b, 0x00, 0x0b, 0x8e, 0x18, 0x7f, 0x= f4, +0x6f, 0x1b, 0x90, 0x70, 0x12, 0x50, 0x64, 0x36, 0x54, 0x48, 0xe1, 0x08, 0x= 42, +0x00, 0x68, 0x0b, 0x92, 0x0a, 0x00, 0x00, 0xfb, 0xb1, 0x54, 0x00, 0x40, 0x= 0a, +0x40, 0xa0, 0xe0, 0xe5, 0xfc, 0x11, 0x01, 0x21, 0x85, 0x31, 0x09, 0x0b, 0x= 90, +0xc8, 0x40, 0x00, 0xe8, 0x8b, 0x00, 0x0b, 0x8e, 0x88, 0x7d, 0xf4, 0x6f, 0x= 1b, +0x90, 0x8e, 0x98, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x1f, 0x= 25, +0x32, 0x40, 0x80, 0xf8, 0x1f, 0x86, 0x93, 0x5d, 0x0f, 0xa2, 0x04, 0x80, 0x= 93, +0xdd, 0x0c, 0x00, 0x80, 0xfa, 0xa8, 0x4c, 0x48, 0x6f, 0xe6, 0x40, 0x08, 0x= e0, +0x0b, 0xa1, 0x95, 0x84, 0xc8, 0x46, 0x40, 0xef, 0x86, 0x02, 0x84, 0x60, 0x= c6, +0x04, 0x84, 0xe0, 0x14, 0x04, 0x5a, 0x00, 0x08, 0xe0, 0x24, 0x88, 0x4a, 0x= 42, +0x08, 0x60, 0x46, 0x02, 0x84, 0xe0, 0x0a, 0x42, 0x80, 0xe1, 0x0c, 0x00, 0x= 00, +0xe2, 0x06, 0x84, 0xf6, 0x40, 0x08, 0xe0, 0x0c, 0x08, 0x80, 0xf2, 0xd8, 0x= 0a, +0x48, 0xff, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0xf0, 0x1e, 0x60, 0x6c, 0x= a6, +0x01, 0x04, 0xe0, 0x48, 0x4a, 0x48, 0xef, 0x0b, 0xa1, 0x15, 0x90, 0xc8, 0x= 5d, +0x2c, 0xef, 0xe8, 0x7a, 0xf4, 0x6e, 0x0e, 0x02, 0x24, 0x74, 0x03, 0xc0, 0x= 86, +0x50, 0x84, 0xe0, 0x69, 0x10, 0x44, 0xe0, 0x58, 0x7a, 0xf4, 0x6e, 0x1b, 0x= 8c, +0x04, 0x60, 0x7b, 0x80, 0x1b, 0x00, 0x28, 0xe0, 0x0b, 0x00, 0x24, 0xe0, 0x= 13, +0xa0, 0x10, 0x00, 0x04, 0x64, 0x1b, 0x8c, 0x88, 0x79, 0xf4, 0xee, 0x14, 0x= a0, +0x19, 0x02, 0x28, 0xe0, 0x19, 0xbe, 0x06, 0x44, 0x06, 0x60, 0x06, 0x41, 0x= dc, +0xe0, 0x04, 0x00, 0x16, 0x42, 0x1e, 0xe0, 0x21, 0xbe, 0x1e, 0x7c, 0x27, 0x= cb, +0x2c, 0x7c, 0x0e, 0x02, 0x25, 0x74, 0x03, 0xc0, 0x48, 0x78, 0xf4, 0xee, 0x= 0e, +0x7e, 0x11, 0x81, 0x1e, 0x09, 0xf0, 0x00, 0x10, 0xe4, 0x1c, 0x95, 0x88, 0x= 7e, +0x1c, 0xef, 0x0a, 0x95, 0x18, 0x41, 0x00, 0x68, 0x01, 0xa0, 0x06, 0x00, 0x= 38, +0x61, 0x11, 0x83, 0x78, 0x7c, 0x1c, 0xef, 0x18, 0x46, 0x48, 0x6f, 0xb6, 0x= 01, +0x04, 0xe0, 0xf1, 0xb0, 0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x= 1b, +0x00, 0x06, 0x00, 0x38, 0xe1, 0x04, 0x80, 0x08, 0x35, 0xf4, 0x7f, 0x01, 0x= c8, +0xc3, 0xc1, 0x0c, 0x04, 0x3c, 0xfa, 0x86, 0x4e, 0x84, 0x60, 0xf0, 0x1e, 0x= 20, +0xee, 0x84, 0x9c, 0x19, 0x0e, 0x48, 0xe0, 0x0a, 0xe2, 0x2a, 0xe0, 0x03, 0x= a4, +0x01, 0x82, 0x38, 0x75, 0xf4, 0x6e, 0x04, 0x00, 0x80, 0xfb, 0x0b, 0x10, 0x= 64, +0x60, 0x6b, 0x80, 0x0b, 0xa1, 0x05, 0x0e, 0x04, 0xc0, 0x99, 0x00, 0xa0, 0x= c0, +0xd5, 0x84, 0x09, 0x10, 0x24, 0x60, 0x06, 0x03, 0xd0, 0xe0, 0x1a, 0x84, 0x= 07, +0xc5, 0x09, 0x82, 0x1f, 0x21, 0x06, 0x00, 0x04, 0xe0, 0x10, 0x42, 0x01, 0x= 70, +0xff, 0xc0, 0x17, 0xd1, 0x1b, 0xa1, 0x78, 0x73, 0xf4, 0x6e, 0x16, 0x02, 0x= 00, +0x80, 0x00, 0x12, 0x04, 0xec, 0x18, 0x42, 0x48, 0x6f, 0x36, 0x01, 0x04, 0x= e0, +0x0b, 0xa1, 0xb5, 0xb0, 0x04, 0x1c, 0x06, 0x11, 0xd0, 0xe0, 0x19, 0x10, 0x= 24, +0x6e, 0x46, 0x05, 0xb8, 0xe0, 0xa4, 0x9e, 0x09, 0x00, 0xb0, 0xe0, 0x18, 0x= 08, +0x5a, 0x02, 0x00, 0xe0, 0x1c, 0x06, 0x00, 0xe2, 0x36, 0x3e, 0x09, 0x86, 0x= 0b, +0x21, 0x19, 0x82, 0x0c, 0x04, 0x00, 0x62, 0x0b, 0xa5, 0x16, 0x7c, 0x64, 0x= 02, +0x80, 0xfb, 0x26, 0x3c, 0x6b, 0x9e, 0x1e, 0xbe, 0x19, 0x0e, 0x60, 0xe0, 0x= 2b, +0x10, 0x30, 0xf8, 0x0c, 0x00, 0x00, 0xe2, 0x16, 0x1b, 0x11, 0x81, 0x06, 0x= 7e, +0x2b, 0xa3, 0x19, 0x14, 0x5c, 0xc0, 0x09, 0x0e, 0x80, 0xe0, 0x25, 0x10, 0x= a4, +0xe3, 0x35, 0x10, 0xa8, 0x63, 0x10, 0x42, 0x3c, 0xd0, 0x0c, 0x0b, 0x01, 0x= 81, +0x16, 0x1d, 0x11, 0x81, 0x26, 0x1f, 0x46, 0x05, 0x04, 0xe0, 0x0c, 0x89, 0x= 06, +0x99, 0x06, 0xa5, 0x0c, 0x91, 0x3e, 0x8b, 0x0e, 0x91, 0x0e, 0x8f, 0x0e, 0x= 0d, +0x60, 0x00, 0xa0, 0xe4, 0x91, 0x5e, 0x90, 0xe0, 0xc8, 0x7a, 0xf4, 0xee, 0x= 09, +0x14, 0x58, 0xe0, 0x19, 0x10, 0xf0, 0xf8, 0x0e, 0x3f, 0xfe, 0x41, 0x3d, 0x= 70, +0xff, 0xc0, 0x1b, 0x25, 0xf6, 0x43, 0x3c, 0xe0, 0x05, 0x5e, 0x80, 0x60, 0x= 16, +0x00, 0x00, 0x80, 0x15, 0x5e, 0x84, 0xe0, 0x01, 0x5e, 0x34, 0x80, 0x05, 0x= 14, +0x18, 0xe0, 0x38, 0x47, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, 0x= 2a, +0x20, 0x11, 0x91, 0x0e, 0x97, 0x78, 0x5d, 0xfc, 0x6f, 0x0b, 0x84, 0x19, 0x= 10, +0xc0, 0xe9, 0x0e, 0xb7, 0x4a, 0x42, 0x80, 0xe0, 0xc5, 0x82, 0x60, 0x00, 0x= c0, +0x65, 0x11, 0xfb, 0x75, 0x81, 0x24, 0x37, 0x11, 0x82, 0x2e, 0xc1, 0x24, 0x= 97, +0x25, 0x40, 0x44, 0xf8, 0x1b, 0xa1, 0x35, 0xfe, 0xe5, 0x85, 0x04, 0x9e, 0x= 05, +0x00, 0x1c, 0xe0, 0x28, 0x45, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0x= c7, +0x14, 0x9e, 0x0e, 0x99, 0x05, 0x02, 0x20, 0xe0, 0x98, 0x44, 0x00, 0x68, 0x= 00, +0x40, 0xfc, 0x73, 0xff, 0xc7, 0x14, 0x9e, 0x0e, 0x9b, 0x05, 0x02, 0x24, 0x= e0, +0x08, 0x44, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, 0x2a, 0x22, 0x= 11, +0x91, 0x0e, 0x9d, 0x48, 0x5a, 0xfc, 0x6f, 0x0b, 0x84, 0x2a, 0x60, 0x11, 0x= 91, +0x0e, 0xb9, 0xe8, 0x59, 0xfc, 0x6f, 0x0b, 0x84, 0x2a, 0x62, 0x11, 0x91, 0x= 0e, +0xbb, 0x88, 0x59, 0xfc, 0x6f, 0x0b, 0x84, 0x0e, 0xbd, 0x04, 0x9c, 0x09, 0x= 00, +0x24, 0xe0, 0x0a, 0x40, 0x88, 0xe0, 0xa5, 0x84, 0x04, 0xb7, 0xf8, 0x7a, 0x= f4, +0x6e, 0x1b, 0x80, 0x14, 0xb9, 0x0e, 0xb7, 0xa8, 0x7a, 0xf4, 0x6e, 0x0b, 0x= 82, +0x14, 0xbb, 0x0e, 0xb9, 0x58, 0x7a, 0xf4, 0x6e, 0x0b, 0x82, 0x14, 0xbd, 0x= 0e, +0xbb, 0x08, 0x7a, 0xf4, 0x6e, 0x0b, 0x82, 0x0e, 0xbd, 0x86, 0x41, 0x30, 0x= 61, +0x1b, 0x9e, 0xd8, 0x4c, 0x08, 0xef, 0x78, 0x75, 0x44, 0x6f, 0x46, 0x01, 0x= 04, +0xe0, 0xf0, 0x1e, 0x20, 0xe6, 0x0c, 0x0c, 0x3c, 0xf2, 0x93, 0xdd, 0x4c, 0x= 00, +0x00, 0xfa, 0x08, 0x74, 0x24, 0x6f, 0x11, 0x8f, 0x4c, 0x08, 0x00, 0xf2, 0x= 93, +0xdd, 0x0c, 0x04, 0x7c, 0xfe, 0x6b, 0x04, 0xf0, 0x1e, 0x60, 0xec, 0xb5, 0x= 0c, +0x10, 0xe0, 0x85, 0x0c, 0x18, 0xe0, 0x79, 0x0c, 0x24, 0xe0, 0xa4, 0xda, 0x= 1e, +0x0b, 0x11, 0x81, 0x0e, 0x7e, 0x0b, 0x96, 0x68, 0x79, 0xf4, 0xee, 0x0b, 0x= a1, +0x15, 0x82, 0x14, 0x18, 0x0b, 0x96, 0x88, 0x79, 0xf4, 0xee, 0x0b, 0xa1, 0x= b5, +0x4c, 0x00, 0xc0, 0x11, 0x01, 0x0b, 0x94, 0x98, 0x78, 0xf4, 0xee, 0x94, 0x= 18, +0x0b, 0xa1, 0x05, 0x1e, 0x14, 0xc0, 0xbe, 0xbe, 0x75, 0x82, 0x0b, 0x14, 0x= 1b, +0x92, 0xf8, 0x78, 0xf4, 0xee, 0x04, 0x0b, 0x0b, 0xa1, 0xa5, 0x4c, 0x00, 0x= 40, +0xa0, 0x52, 0x00, 0xdc, 0xae, 0x7c, 0xab, 0x80, 0x77, 0x42, 0x0b, 0x92, 0x= 15, +0x14, 0x1c, 0xfe, 0x58, 0x75, 0xf4, 0xee, 0x0b, 0x14, 0x44, 0x60, 0x9b, 0x= 80, +0x88, 0x75, 0xf4, 0xee, 0xbb, 0x00, 0x0b, 0x92, 0x08, 0x77, 0xf4, 0x6e, 0x= 1b, +0x96, 0x0b, 0xa1, 0x90, 0x56, 0x00, 0x1c, 0xa0, 0x12, 0x88, 0xe4, 0xc8, 0x= 75, +0xf4, 0x6e, 0x0b, 0x96, 0xab, 0x00, 0x01, 0x81, 0x01, 0x4c, 0x20, 0x60, 0x= 8b, +0xa1, 0x04, 0x7e, 0x76, 0x03, 0x71, 0x7b, 0x34, 0xce, 0xac, 0xd8, 0x03, 0x= 8e, +0x00, 0x00, 0x70, 0xe7, 0x0e, 0x89, 0x65, 0x88, 0x8b, 0xa3, 0x35, 0x08, 0x= 06, +0x02, 0x01, 0x00, 0xc0, 0xcf, 0x58, 0x74, 0xf4, 0x6e, 0x0b, 0x96, 0x28, 0x= 73, +0xf4, 0x6e, 0x8b, 0x80, 0x1b, 0x00, 0x0b, 0x96, 0x58, 0x73, 0xf4, 0xee, 0x= d8, +0x49, 0x00, 0xe8, 0x18, 0x74, 0xf4, 0x6e, 0x76, 0x03, 0x70, 0x7b, 0x34, 0x= ce, +0x0b, 0xa1, 0x25, 0x84, 0x11, 0x01, 0x0b, 0x96, 0x48, 0x74, 0xf4, 0xee, 0x= 0b, +0xa1, 0x80, 0x14, 0x04, 0x04, 0x80, 0x54, 0x00, 0xdc, 0x75, 0x81, 0xc8, 0x= 70, +0xf4, 0x6e, 0x0b, 0x96, 0x58, 0x72, 0xf4, 0xee, 0xab, 0x80, 0xac, 0xd8, 0x= 0a, +0xa4, 0x08, 0x71, 0xf4, 0xee, 0x04, 0x0b, 0x9b, 0x80, 0x73, 0x80, 0x0b, 0x= 0e, +0x40, 0xe0, 0x98, 0x70, 0xf4, 0xee, 0xbb, 0x00, 0xa4, 0x00, 0x80, 0xfb, 0x= 48, +0x70, 0xf4, 0xee, 0x1b, 0x00, 0x0b, 0x96, 0x68, 0x49, 0x00, 0xe8, 0x1b, 0x= 00, +0x0b, 0x92, 0xc8, 0x47, 0x00, 0xe8, 0xa8, 0x70, 0xf4, 0xee, 0x04, 0x09, 0x= ab, +0x80, 0xac, 0xd8, 0x9a, 0x80, 0x9c, 0xda, 0x0b, 0x0e, 0x4c, 0xe0, 0x18, 0x= 6f, +0xf4, 0xee, 0x0b, 0x0e, 0x48, 0x60, 0xbb, 0x80, 0xc8, 0x6e, 0xf4, 0xee, 0x= 8b, +0x00, 0x0b, 0x92, 0x88, 0x6e, 0xf4, 0xee, 0x1b, 0x00, 0x0b, 0x90, 0xa8, 0x= 47, +0x00, 0xe8, 0x1b, 0x00, 0x0b, 0x96, 0x08, 0x46, 0x00, 0xe8, 0xe8, 0x6e, 0x= f4, +0xee, 0xb4, 0x3e, 0x9b, 0x80, 0x84, 0xfc, 0x9c, 0xda, 0x1b, 0x96, 0xf8, 0x= 6d, +0xf4, 0x6e, 0x0b, 0x90, 0x68, 0x44, 0x00, 0xe8, 0xe8, 0x6e, 0xf4, 0x6e, 0x= 11, +0x81, 0x0b, 0xa1, 0x85, 0x8e, 0x11, 0x01, 0x0b, 0x96, 0xf8, 0x6d, 0xf4, 0x= ee, +0x2a, 0x00, 0x00, 0x60, 0x0b, 0x94, 0x24, 0x7e, 0x1b, 0x92, 0x34, 0x8b, 0x= f8, +0x74, 0x18, 0xef, 0x58, 0x01, 0x01, 0x40, 0x00, 0x40, 0x9b, 0x80, 0x0b, 0x= 16, +0x1b, 0x92, 0x78, 0x6d, 0xf4, 0xee, 0x0b, 0xa1, 0x85, 0x82, 0x1a, 0xd8, 0x= 09, +0x0c, 0x20, 0xe0, 0x11, 0x82, 0x04, 0x09, 0x0b, 0xa1, 0x1c, 0x58, 0x70, 0x= 00, +0x90, 0xc4, 0x0a, 0x80, 0x0c, 0xda, 0x11, 0x01, 0x0b, 0x90, 0xe8, 0x6b, 0x= f4, +0xee, 0x0b, 0xa1, 0xb5, 0x84, 0x0b, 0x10, 0x1b, 0x92, 0x88, 0x6c, 0xf4, 0x= ee, +0x0b, 0xa1, 0xe5, 0x82, 0x09, 0x0c, 0x20, 0xe0, 0x1a, 0xd8, 0x0b, 0xa1, 0x= 70, +0x0e, 0x98, 0x44, 0x10, 0x00, 0x04, 0xec, 0x75, 0x5e, 0x10, 0xc0, 0x0c, 0x= d8, +0x04, 0x89, 0x0a, 0x80, 0x0c, 0xda, 0xf1, 0xb0, 0x0c, 0x0c, 0x7c, 0xf6, 0x= 93, +0xdd, 0x0c, 0x04, 0x00, 0xfa, 0x6b, 0x00, 0x11, 0x81, 0xe8, 0x6a, 0xf4, 0x= ee, +0x0b, 0xa1, 0x64, 0x0c, 0x7c, 0xdd, 0x0b, 0x8c, 0x0c, 0x0c, 0x00, 0xf2, 0x= 93, +0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0x6b, 0x02, 0x7b, 0x80, 0x08, 0x= 6a, +0xf4, 0xee, 0x8b, 0x00, 0x0b, 0x8e, 0x48, 0x69, 0xf4, 0x6e, 0x1b, 0x8c, 0x= 0b, +0xa1, 0x70, 0x4c, 0x00, 0x1c, 0x8b, 0xa1, 0x70, 0x4c, 0x00, 0xdc, 0x0b, 0x= 8c, +0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0x= 6b, +0x02, 0x7b, 0x80, 0xa8, 0x68, 0xf4, 0xee, 0x0b, 0xa1, 0x70, 0x4c, 0x00, 0x= 9c, +0x0b, 0x8c, 0x4c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x= 00, +0xfa, 0x6b, 0x00, 0x21, 0x81, 0x04, 0x18, 0x31, 0x83, 0x68, 0x53, 0xfc, 0x= ef, +0x0e, 0x98, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0x18, 0xa9, 0x00, 0x00, 0x= 38, +0x90, 0x40, 0x00, 0x08, 0x14, 0xb8, 0xe0, 0x80, 0x2c, 0x40, 0x00, 0xa8, 0x= 3a, +0xe8, 0xe0, 0x08, 0x9f, 0x40, 0x00, 0x28, 0x28, 0xb0, 0xe0, 0x18, 0x72, 0x= 40, +0x00, 0x88, 0x19, 0xc8, 0xe0, 0xe0, 0xbb, 0x40, 0x00, 0x08, 0x0c, 0xa4, 0x= e0, +0xa8, 0xe3, 0x40, 0x00, 0x28, 0x13, 0x90, 0xe0, 0xf0, 0xec, 0x40, 0x00, 0x= 68, +0x0d, 0x8c, 0xe0, 0x48, 0xa8, 0x40, 0x00, 0xa8, 0x3c, 0xac, 0xe0, 0x28, 0x= e4, +0x40, 0x00, 0x08, 0x0e, 0x94, 0xe0, 0xb8, 0xe2, 0x40, 0x00, 0x28, 0x3d, 0x= 90, +0xe0, 0x90, 0xa7, 0x40, 0x00, 0xc8, 0x13, 0xb0, 0xe0, 0x18, 0xc1, 0x40, 0x= 00, +0xa8, 0x2a, 0xa4, 0xe0, 0xa8, 0x91, 0x40, 0x00, 0x68, 0x2f, 0xbc, 0xe0, 0x= 88, +0xf1, 0x40, 0x00, 0x08, 0x1c, 0x88, 0xe0, 0xd0, 0x8e, 0x40, 0x00, 0xa8, 0x= 19, +0xb8, 0xe0, 0x38, 0x82, 0x40, 0x00, 0x28, 0x38, 0xbc, 0xe0, 0x88, 0xe0, 0x= 40, +0x00, 0xa8, 0x0e, 0x98, 0xe0, 0xd8, 0xe4, 0x40, 0x00, 0x68, 0x32, 0x94, 0x= e0, +0x18, 0xd7, 0x40, 0x00, 0x28, 0x2d, 0x9c, 0xe0, 0x40, 0xe8, 0x40, 0x00, 0x= 28, +0x19, 0x94, 0xe0, 0xa8, 0x78, 0x40, 0x00, 0x28, 0x18, 0xcc, 0xe0, 0xf0, 0x= 95, +0x40, 0x00, 0x48, 0x34, 0xbc, 0xe0, 0xa8, 0xd2, 0x40, 0x00, 0x48, 0x16, 0x= a0, +0xe0, 0x18, 0x52, 0x40, 0x00, 0x68, 0x2b, 0xe0, 0xe0, 0x00, 0xb9, 0x00, 0x= 00, +0x23, 0xdb, 0x00, 0x00 +}; + +static const u8 cut2_patch[] =3D { +0x37, 0x00, 0x05, 0x00, 0x0c, 0x04, 0x3c, 0xfa, 0x86, 0x0e, 0x84, 0x60, 0x= 06, +0x11, 0x84, 0xe0, 0x04, 0x1c, 0x06, 0x13, 0x88, 0xe1, 0x14, 0xa0, 0x0d, 0x= c2, +0x95, 0x80, 0x04, 0xa4, 0x0b, 0xa3, 0xb5, 0x88, 0x78, 0x6c, 0x40, 0xef, 0x= 6b, +0x00, 0x46, 0x01, 0x84, 0xe0, 0x88, 0x53, 0x48, 0x6f, 0x46, 0x15, 0x84, 0x= e0, +0x6b, 0x25, 0xc6, 0x0d, 0x84, 0xe0, 0x95, 0x84, 0x08, 0xa8, 0x4a, 0x00, 0x= fc, +0xfb, 0x05, 0x84, 0x09, 0x12, 0x1c, 0xe0, 0xa8, 0x46, 0x48, 0xef, 0x04, 0x= 1c, +0x11, 0x83, 0x16, 0x18, 0xc6, 0x04, 0x84, 0xe0, 0x0e, 0x08, 0x01, 0x87, 0x= f8, +0x6a, 0x40, 0xef, 0x46, 0x0c, 0x84, 0xe0, 0x04, 0x1c, 0x11, 0x81, 0x16, 0x= 98, +0x0e, 0xa0, 0x06, 0x41, 0x84, 0x60, 0xc6, 0x02, 0xd8, 0xe0, 0x04, 0x80, 0x= 08, +0x80, 0x06, 0x84, 0x0c, 0x0c, 0x3c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x= 00, +0x80, 0xfa, 0xc6, 0x40, 0x84, 0x60, 0x86, 0x43, 0xd8, 0xe0, 0x04, 0x80, 0x= 09, +0x00, 0x18, 0xe1, 0x06, 0x84, 0x88, 0x41, 0x68, 0xef, 0x0c, 0x08, 0x80, 0x= f2, +0x48, 0x20, 0x68, 0xff, 0x1e, 0xc0, 0xb5, 0x00, 0x2c, 0xe0, 0xb4, 0x02, 0x= 00, +0xfc, 0x15, 0x40, 0x2c, 0xe0, 0x19, 0x10, 0x31, 0x78, 0x01, 0x40, 0x86, 0x= 04, +0x0c, 0xe0, 0x4a, 0x04, 0x00, 0x64, 0x31, 0x81, 0x30, 0x0a, 0x04, 0x64, 0x= 4b, +0x82, 0x1b, 0x06, 0x3b, 0x8a, 0xc8, 0x44, 0xfc, 0x87, 0x41, 0x50, 0x31, 0x= 78, +0x01, 0x40, 0xa1, 0xe1, 0xe6, 0x43, 0x99, 0x6c, 0x10, 0xc0, 0x08, 0x42, 0x= 00, +0xf8, 0x00, 0x00, 0x03, 0xa9, 0x00, 0x00, 0x30, 0x85, 0x40, 0x00, 0xa8, 0x= 16, +0xbc, 0xe0, 0xcc, 0xc1, 0x40, 0x00, 0xa8, 0x35, 0x9c, 0xe0, 0xb0, 0xc9, 0x= 40, +0x00, 0x88, 0x37, 0x98, 0xe0, 0x00, 0xb9, 0x00, 0x00, 0x49, 0xa7, 0x00, 0x= 00, +}; + +struct vd55g0_patch { +=09const u8 *bin; +=09const uint size; +=09const u16 major; +=09const u16 minor; +}; + +static const struct vd55g0_patch vd55g0_patch_cut1 =3D { +=09.bin =3D cut1_patch, +=09.size =3D ARRAY_SIZE(cut1_patch), +=09.major =3D 2, +=09.minor =3D 11, +}; + +static const struct vd55g0_patch vd55g0_patch_cut2 =3D { +=09.bin =3D cut2_patch, +=09.size =3D ARRAY_SIZE(cut2_patch), +=09.major =3D 0, +=09.minor =3D 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, +}; + +/* + * On ACPI, the INT3472 registers the rails the platform wired under its o= wn + * names; the DT names would get dummy regulators there. + */ +static const char * const vd55g0_dt_supply_name[] =3D { +=09"vcore", +=09"vddio", +=09"vana", +}; + +static const char * const vd55g0_acpi_supply_name[] =3D { +=09"avdd", +=09"dovdd", +}; + +static const struct acpi_device_id vd55g0_acpi_ids[] =3D { +=09{ "SMO55F0" }, +=09{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, vd55g0_acpi_ids); + +#define VD55G0_NUM_SUPPLIES=09ARRAY_SIZE(vd55g0_dt_supply_name) + +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; +=09enum vd55g0_bin_mode bin_mode; +=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.bin_mode =3D VD55G0_BIN_MODE_NORMAL, +=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.bin_mode =3D VD55G0_BIN_MODE_NORMAL, +=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.bin_mode =3D VD55G0_BIN_MODE_NORMAL, +=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.bin_mode =3D VD55G0_BIN_MODE_DIGITAL_X2, +=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[VD55G0_NUM_SUPPLIES]; +=09unsigned int nb_supplies; +=09struct gpio_desc *reset_gpio; +=09struct clk *xclk; +=09u32 clk_freq; +=09u16 oif_ctrl; +=09u32 mipi_rate; +=09u32 pixel_rate; +=09u64 link_freq; +=09u16 line_length; +=09u16 revision; +=09/* Lock to protect all members below */ +=09struct mutex lock; +=09struct v4l2_ctrl_handler ctrl_handler; +=09struct v4l2_ctrl *vblank_ctrl; +=09struct v4l2_ctrl *hblank_ctrl; +=09struct v4l2_ctrl *vflip_ctrl; +=09struct v4l2_ctrl *hflip_ctrl; +=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}; +=09bool streaming; +=09u32 code; +=09const struct vd55g0_mode_info *current_mode; +=09bool hflip; +=09bool vflip; +=09u16 manual_expo; +=09enum vd55g0_expo_state expo_state; +=09u16 digital_gain; +=09u8 analog_gain; +=09u16 vblank; +=09u16 vblank_min; +=09u16 frame_length; +=09bool ae_frozen; +=09u32 pattern; +=09u16 exposure_target; +=09u32 leds[VD55G0_NB_GPIOS]; +=09bool flash_en; +=09unsigned int nb_leds; +=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) +{ +=09unsigned int i; + +=09for (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) +{ +=09unsigned int i; + +=09for (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 int get_chunk_size(struct vd55g0_dev *sensor) +{ +=09int max_write_len =3D VD55G0_WRITE_MULTIPLE_CHUNK_MAX; +=09struct i2c_adapter *adapter =3D sensor->i2c_client->adapter; + +=09if (adapter->quirks && adapter->quirks->max_write_len) +=09=09max_write_len =3D adapter->quirks->max_write_len - 2; + +=09max_write_len =3D min(max_write_len, VD55G0_WRITE_MULTIPLE_CHUNK_MAX); + +=09return max(max_write_len, 1); +} + +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); +} + +static int vd55g0_prepare_clock_tree(struct vd55g0_dev *sensor) +{ +=09struct device *dev =3D &sensor->i2c_client->dev; +=09u32 pixel_div; + +=09if (sensor->clk_freq < VD55G0_XCLK_FREQ_MIN || +=09 sensor->clk_freq > VD55G0_XCLK_FREQ_MAX) { +=09=09dev_err(dev, +=09=09=09"Only %luMHz-%luMHz clock range supported. Provided %lu MHz\n", +=09=09=09VD55G0_XCLK_FREQ_MIN / HZ_PER_MHZ, +=09=09=09VD55G0_XCLK_FREQ_MAX / HZ_PER_MHZ, +=09=09=09sensor->clk_freq / HZ_PER_MHZ); +=09=09return -EINVAL; +=09} + +=09/* +=09 * The MIPI bus is double data rate, and its rate is an integer multipl= e +=09 * of the input clock. The sensor would round any other rate down +=09 * (UM2829 13.6), so it is refused 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, VD55G0_MIPI_RATE_MAX / MEGA, +=09=09=09sensor->link_freq); +=09=09return -EINVAL; +=09} +=09sensor->mipi_rate =3D sensor->link_freq * 2; +=09if (sensor->mipi_rate % 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} + +=09pixel_div =3D sensor->mipi_rate <=3D VD55G0_MIPI_RATE_FAST ? 6 : 8; +=09sensor->pixel_rate =3D sensor->mipi_rate / pixel_div; + +=09return 0; +} + +static int vd55g0_update_gpio_mode(struct vd55g0_dev *sensor, u32 mode, +=09=09=09=09 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 int size, enum vd55g0_gpio_modes mode) +{ +=09unsigned int i; +=09int ret; + +=09for (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_auto(struct vd55g0_dev *sensor) +{ +=09enum vd55g0_expo_state exp =3D sensor->expo_state; + +=09if (sensor->ae_frozen && sensor->expo_state =3D=3D VD55G0_EXP_AUTO) +=09=09exp =3D VD55G0_EXP_FREEZE; + +=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; +=09const char * const *names; +=09unsigned int i; + +=09/* A PRP0001 device has DT names; only the ACPI ID has INT3472's */ +=09if (acpi_match_device(vd55g0_acpi_ids, dev)) { +=09=09names =3D vd55g0_acpi_supply_name; +=09=09sensor->nb_supplies =3D ARRAY_SIZE(vd55g0_acpi_supply_name); +=09} else { +=09=09names =3D vd55g0_dt_supply_name; +=09=09sensor->nb_supplies =3D ARRAY_SIZE(vd55g0_dt_supply_name); +=09} + +=09for (i =3D 0; i < sensor->nb_supplies; i++) +=09=09sensor->supplies[i].supply =3D names[i]; + +=09return devm_regulator_bulk_get(dev, sensor->nb_supplies, +=09=09=09=09 sensor->supplies); +} + +static int vd55g0_apply_patgen(struct vd55g0_dev *sensor) +{ +=09static const u8 index2val[] =3D { +=09=090x0, 0x0, 0x8, 0x10, 0x20, 0x21, 0x22, 0x28 +=09}; +=09u32 pattern =3D index2val[sensor->pattern]; +=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 (sensor->pattern !=3D 0) { +=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) +{ +=09enum vd55g0_gpio_modes mode =3D sensor->flash_en ? +=09=09=09=09 VD55G0_GPIO_MODE_STROBE : +=09=09=09=09 VD55G0_GPIO_MODE_DISABLED; + +=09return vd55g0_set_gpios_array(sensor, sensor->leds, +=09=09=09=09 ARRAY_SIZE(sensor->leds), mode); +} + +/* The helpers below cache a value only once the sensor has taken it */ +static int vd55g0_update_exposure_auto(struct vd55g0_dev *sensor, u32 inde= x) +{ +=09enum vd55g0_expo_state old =3D sensor->expo_state; +=09int ret; + +=09switch (index) { +=09case V4L2_EXPOSURE_AUTO: +=09=09sensor->expo_state =3D VD55G0_EXP_AUTO; +=09=09break; +=09case V4L2_EXPOSURE_MANUAL: +=09=09sensor->expo_state =3D VD55G0_EXP_MANUAL; +=09=09break; +=09default: +=09=09/* Should never happen */ +=09=09return -EINVAL; +=09} + +=09if (!sensor->streaming) +=09=09return 0; + +=09ret =3D vd55g0_apply_exposure_auto(sensor); +=09if (ret) +=09=09sensor->expo_state =3D old; + +=09return ret; +} + +static int vd55g0_lock_exposure(struct vd55g0_dev *sensor, +=09=09=09=09struct v4l2_ctrl *ctrl) +{ +=09/* Only exposure lock is supported */ +=09bool ae_lock =3D ctrl->val & V4L2_LOCK_EXPOSURE; +=09bool old =3D sensor->ae_frozen; +=09int ret; + +=09sensor->ae_frozen =3D ae_lock; + +=09/* Cap control value to reflect the hardware state */ +=09ctrl->val =3D ae_lock; + +=09if (!sensor->streaming) +=09=09return 0; + +=09ret =3D vd55g0_apply_exposure_auto(sensor); +=09if (ret) +=09=09sensor->ae_frozen =3D old; + +=09return ret; +} + +static int vd55g0_apply_framelength(struct vd55g0_dev *sensor) +{ +=09return vd55g0_write(sensor, VD55G0_REG_FRAME_LENGTH, +=09=09=09 sensor->frame_length, NULL); +} + +static int vd55g0_update_vblank(struct vd55g0_dev *sensor, u16 vblank) +{ +=09u16 old_vblank =3D sensor->vblank, old_frame_length =3D sensor->frame_l= ength; +=09int ret; + +=09sensor->vblank_min =3D VD55G0_MIN_FRAME_LENGTH - +=09=09=09 sensor->current_mode->crop.height; +=09sensor->vblank =3D vblank; +=09sensor->frame_length =3D sensor->current_mode->crop.height + +=09=09=09 sensor->vblank; + +=09if (!sensor->streaming) +=09=09return 0; + +=09ret =3D vd55g0_apply_framelength(sensor); +=09if (ret) { +=09=09sensor->vblank =3D old_vblank; +=09=09sensor->frame_length =3D old_frame_length; +=09} + +=09return ret; +} + +static int vd55g0_update_analog_gain(struct vd55g0_dev *sensor, u32 target= ) +{ +=09int ret =3D 0; + +=09if (sensor->streaming) +=09=09ret =3D vd55g0_write(sensor, VD55G0_REG_MANUAL_ANALOG_GAIN, +=09=09=09=09 target, NULL); +=09if (!ret) +=09=09sensor->analog_gain =3D target; + +=09return ret; +} + +static int vd55g0_update_digital_gain(struct vd55g0_dev *sensor, u32 targe= t) +{ +=09int ret =3D 0; + +=09if (sensor->streaming) +=09=09ret =3D vd55g0_write(sensor, VD55G0_REG_MANUAL_DIGITAL_GAIN, +=09=09=09=09 target, NULL); +=09if (!ret) +=09=09sensor->digital_gain =3D target; + +=09return ret; +} + +static int vd55g0_update_exposure(struct vd55g0_dev *sensor, int expo_ms) +{ +=09int ret =3D 0; + +=09if (sensor->streaming) +=09=09ret =3D vd55g0_write(sensor, VD55G0_REG_MANUAL_COARSE_EXPOSURE, +=09=09=09=09 expo_ms, NULL); +=09if (!ret) +=09=09sensor->manual_expo =3D expo_ms; + +=09return ret; +} + +static int vd55g0_update_exposure_target(struct vd55g0_dev *sensor, int in= dex) +{ +=09/* +=09 * Find auto exposure target with: default target exposure * 2^EV, +=09 * the default being VD55G0_EXPO_TARGET_DEF 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}; +=09unsigned int target =3D index2exposure_target[index]; +=09int ret =3D 0; + +=09if (sensor->streaming) +=09=09ret =3D vd55g0_write(sensor, VD55G0_REG_AE_TARGET_PERCENTAGE, +=09=09=09=09 target, NULL); +=09if (!ret) +=09=09sensor->exposure_target =3D target; + +=09return ret; +} + +static int vd55g0_update_flash(struct vd55g0_dev *sensor, int flash_en) +{ +=09bool old =3D sensor->flash_en; +=09int ret; + +=09sensor->flash_en =3D flash_en; +=09if (!sensor->streaming) +=09=09return 0; + +=09ret =3D vd55g0_apply_flash(sensor); +=09if (ret) +=09=09sensor->flash_en =3D old; + +=09return ret; +} + +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(struct vd55g0_dev *sensor, +=09=09=09=09 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 int vd55g0_try_fmt_internal(struct v4l2_subdev *sd, +=09=09=09=09 struct v4l2_mbus_framefmt *fmt, +=09=09=09=09 const struct vd55g0_mode_info **new_mode) +{ +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(sd); +=09const struct vd55g0_mode_info *mode =3D vd55g0_mode_data; +=09unsigned int index; + +=09for (index =3D 0; index < ARRAY_SIZE(vd55g0_supported_codes); index++) = { +=09=09if (vd55g0_supported_codes[index].code =3D=3D fmt->code) +=09=09=09break; +=09} +=09if (index =3D=3D ARRAY_SIZE(vd55g0_supported_codes)) +=09=09index =3D 0; + +=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); +=09if (new_mode) +=09=09*new_mode =3D mode; + +=09vd55g0_fill_framefmt(sensor, mode, fmt, +=09=09=09 vd55g0_supported_codes[index].code); + +=09return 0; +} + +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_settings(struct vd55g0_dev *sensor) +{ +=09int ret; + +=09ret =3D vd55g0_apply_framelength(sensor); +=09if (ret) +=09=09return ret; + +=09ret =3D vd55g0_apply_exposure_auto(sensor); +=09if (ret) +=09=09return ret; + +=09vd55g0_write(sensor, VD55G0_REG_MANUAL_COARSE_EXPOSURE, +=09=09 sensor->manual_expo, &ret); +=09vd55g0_write(sensor, VD55G0_REG_MANUAL_ANALOG_GAIN, +=09=09 sensor->analog_gain, &ret); +=09vd55g0_write(sensor, VD55G0_REG_MANUAL_DIGITAL_GAIN, +=09=09 sensor->digital_gain, &ret); +=09vd55g0_write(sensor, VD55G0_REG_AE_TARGET_PERCENTAGE, +=09=09 sensor->exposure_target, &ret); +=09if (ret) +=09=09return ret; + +=09ret =3D vd55g0_apply_cold_start(sensor); +=09if (ret) +=09=09return ret; + +=09vd55g0_write(sensor, VD55G0_REG_ORIENTATION, +=09=09 sensor->hflip | (sensor->vflip << 1), &ret); +=09if (ret) +=09=09return ret; + +=09ret =3D vd55g0_apply_patgen(sensor); +=09if (ret) +=09=09return ret; + +=09return 0; +} + +static int vd55g0_apply_frame_format(struct vd55g0_dev *sensor) +{ +=09const struct v4l2_rect *crop =3D &sensor->current_mode->crop; +=09int ret =3D 0; + +=09vd55g0_write(sensor, VD55G0_REG_READOUT_CTRL, +=09=09 sensor->current_mode->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; +} + +static int vd55g0_set_gpios(struct vd55g0_dev *sensor) +{ +=09int ret; +=09unsigned int i; + +=09/* GPIOs in input (disabled) by default */ +=09for (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} + +=09ret =3D vd55g0_apply_flash(sensor); +=09if (ret) +=09=09return ret; + +=09return 0; +} + +static int vd55g0_stream_enable(struct vd55g0_dev *sensor) +{ +=09struct i2c_client *client =3D v4l2_get_subdevdata(&sensor->sd); +=09int ret; + +=09ret =3D pm_runtime_resume_and_get(&client->dev); +=09if (ret < 0) +=09=09return ret; + +=09ret =3D vd55g0_set_gpios(sensor); +=09if (ret) +=09=09goto err_rpm_put; + +=09vd55g0_write(sensor, VD55G0_REG_FORMAT_CTRL, +=09=09 get_bpp_by_code(sensor->code), &ret); +=09vd55g0_write(sensor, VD55G0_REG_OIF_IMG_CTRL, +=09=09 get_data_type_by_code(sensor->code), &ret); +=09if (ret) +=09=09goto err_rpm_put; + +=09ret =3D vd55g0_apply_frame_format(sensor); +=09if (ret) +=09=09goto err_rpm_put; + +=09ret =3D vd55g0_apply_settings(sensor); +=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(&client->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, 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; +=09struct v4l2_fwnode_endpoint ep_node =3D { .bus_type =3D +=09=09V4L2_MBUS_CSI2_DPHY +=09}; +=09int ret; + +=09ep =3D &ep_node; +=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->major << 8) + patch->minor) { +=09=09dev_err(&client->dev, +=09=09=09"bad patch version expected %d.%d got %llu.%llu\n", +=09=09=09patch->major, patch->minor, +=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; + +=09sensor->line_length =3D VD55G0_LINE_LENGTH_FAST; +=09if (sensor->mipi_rate <=3D VD55G0_MIPI_RATE_FAST) +=09=09sensor->line_length =3D VD55G0_LINE_LENGTH_SLOW; +=09vd55g0_write(sensor, VD55G0_REG_LINE_LENGTH, sensor->line_length, +=09=09 &ret); + +=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, sensor->mipi_rate, &ret); + +=09return ret; +} + +/* Called with sensor->lock held, which is also the control handler's 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); +=09if (ret) +=09=09return ret; + +=09sensor->streaming =3D true; +=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); + +=09sensor->streaming =3D false; +=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) +{ +=09const struct vd55g0_mode_info *mode; +=09const struct v4l2_mbus_framefmt *fmt; + +=09switch (sel->target) { +=09case V4L2_SEL_TGT_CROP: +=09=09/* From the state asked about, so that TRY gets its own crop */ +=09=09fmt =3D v4l2_subdev_state_get_format(sd_state, 0); +=09=09mode =3D v4l2_find_nearest_size(vd55g0_mode_data, +=09=09=09=09=09 ARRAY_SIZE(vd55g0_mode_data), +=09=09=09=09=09 width, height, +=09=09=09=09=09 fmt->width, fmt->height); +=09=09sel->r =3D mode->crop; +=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; +} + +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 *new_mode; +=09struct v4l2_mbus_framefmt *fmt; +=09unsigned int expo_max, hblank; +=09u16 vblank_def; +=09int ret; + +=09/* The mode cannot change under a running stream */ +=09if (format->which =3D=3D V4L2_SUBDEV_FORMAT_ACTIVE && sensor->streaming= ) +=09=09return -EBUSY; + +=09ret =3D vd55g0_try_fmt_internal(sd, &format->format, &new_mode); +=09if (ret) +=09=09return ret; + +=09fmt =3D v4l2_subdev_state_get_format(sd_state, 0); +=09*fmt =3D format->format; + +=09if (format->which !=3D V4L2_SUBDEV_FORMAT_ACTIVE) +=09=09return 0; + +=09if (sensor->current_mode =3D=3D new_mode && sensor->code =3D=3D fmt->co= de) +=09=09return 0; + +=09sensor->code =3D fmt->code; +=09sensor->current_mode =3D new_mode; + +=09/* Reset vblank and framelength to default */ +=09vblank_def =3D VD55G0_FRAME_LENGTH_DEF - new_mode->crop.height; +=09ret =3D vd55g0_update_vblank(sensor, vblank_def); +=09if (ret) +=09=09return ret; + +=09/* The range change may clamp and apply the old vblank; set the default= */ +=09ret =3D __v4l2_ctrl_modify_range(sensor->vblank_ctrl, sensor->vblank_mi= n, +=09=09=09=09 0xffff - new_mode->crop.height, 1, +=09=09=09=09 vblank_def); +=09if (ret) +=09=09return ret; +=09ret =3D __v4l2_ctrl_s_ctrl(sensor->vblank_ctrl, vblank_def); +=09if (ret) +=09=09return ret; +=09/* Max exposure changes with vblank */ +=09expo_max =3D sensor->frame_length - VD55G0_EXPO_MAX_TERM; +=09ret =3D __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max, 1, +=09=09=09=09 VD55G0_EXPO_DEF); +=09if (ret) +=09=09return ret; +=09/* Blanking counts from the analogue crop, as in vd55g1 */ +=09hblank =3D sensor->line_length - sensor->current_mode->crop.width; +=09ret =3D __v4l2_ctrl_modify_range(sensor->hblank_ctrl, hblank, hblank, 1= , +=09=09=09=09 hblank); +=09if (ret) +=09=09return ret; + +=09return __v4l2_ctrl_s_ctrl(sensor->hblank_ctrl, hblank); +} + +static int vd55g0_init_state(struct v4l2_subdev *sd, +=09=09=09 struct v4l2_subdev_state *sd_state) +{ +=09struct vd55g0_dev *sensor =3D to_vd55g0_dev(sd); +=09struct v4l2_subdev_format fmt =3D { 0 }; + +=09vd55g0_fill_framefmt(sensor, &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 media_entity_operations vd55g0_subdev_entity_ops =3D { +=09.link_validate =3D v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops vd55g0_internal_ops =3D { +=09.init_state =3D vd55g0_init_state, +}; + +/* + * The manual values first, so that a switch to manual starts from them; t= he + * sensor ignores them under auto exposure. + */ +static int vd55g0_update_expo_cluster(struct vd55g0_dev *sensor) +{ +=09int ret =3D 0; + +=09if (sensor->ae_ctrl->val =3D=3D V4L2_EXPOSURE_MANUAL) { +=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 (sensor->expo_ctrl->is_new) +=09=09=09ret =3D vd55g0_update_exposure(sensor, +=09=09=09=09=09=09 sensor->expo_ctrl->val); +=09=09if (!ret && sensor->again_ctrl->is_new) +=09=09=09ret =3D vd55g0_update_analog_gain(sensor, +=09=09=09=09=09=09=09sensor->again_ctrl->val); +=09=09if (!ret && sensor->dgain_ctrl->is_new) +=09=09=09ret =3D vd55g0_update_digital_gain(sensor, +=09=09=09=09=09=09=09 sensor->dgain_ctrl->val); +=09=09if (ret) +=09=09=09return ret; +=09} + +=09if (sensor->ae_ctrl->is_new) +=09=09ret =3D vd55g0_update_exposure_auto(sensor, sensor->ae_ctrl->val); + +=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; + +=09if (ctrl->id !=3D V4L2_CID_EXPOSURE_AUTO) +=09=09return -EINVAL; + +=09/* Only a powered sensor has applied values; keep the last ones */ +=09if (!pm_runtime_get_if_in_use(dev)) +=09=09return 0; + +=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 expo; +=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); +=09unsigned int expo_max; +=09u16 old_vblank; +=09int ret; + +=09/* Read-only controls are set by the driver, there is nothing to apply = */ +=09if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) +=09=09return 0; + +=09switch (ctrl->id) { +=09case V4L2_CID_VFLIP: +=09case V4L2_CID_HFLIP: +=09=09if (sensor->streaming) { +=09=09=09ret =3D -EBUSY; +=09=09=09break; +=09=09} +=09=09if (ctrl->id =3D=3D V4L2_CID_VFLIP) +=09=09=09sensor->vflip =3D ctrl->val; +=09=09if (ctrl->id =3D=3D V4L2_CID_HFLIP) +=09=09=09sensor->hflip =3D ctrl->val; +=09=09ret =3D 0; +=09=09break; +=09case V4L2_CID_TEST_PATTERN: +=09=09/* Can't be done while streaming because of duster disabling */ +=09=09sensor->pattern =3D ctrl->val; +=09=09ret =3D 0; +=09=09break; +=09case V4L2_CID_EXPOSURE_AUTO: +=09=09ret =3D vd55g0_update_expo_cluster(sensor); +=09=09break; +=09case V4L2_CID_3A_LOCK: +=09=09ret =3D vd55g0_lock_exposure(sensor, ctrl); +=09=09break; +=09case V4L2_CID_VBLANK: +=09=09old_vblank =3D sensor->vblank; +=09=09ret =3D vd55g0_update_vblank(sensor, ctrl->val); +=09=09if (ret) +=09=09=09break; +=09=09/* Max exposure changes with vblank */ +=09=09expo_max =3D sensor->frame_length - VD55G0_EXPO_MAX_TERM; +=09=09ret =3D __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max, +=09=09=09=09=09 1, VD55G0_EXPO_DEF); +=09=09/* A clamped exposure failed to apply: put the frame back */ +=09=09if (ret) +=09=09=09vd55g0_update_vblank(sensor, old_vblank); +=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_update_exposure_target(sensor, ctrl->val); +=09=09break; +=09case V4L2_CID_FLASH_LED_MODE: +=09=09ret =3D vd55g0_update_flash(sensor, ctrl->val); +=09=09break; +=09default: +=09=09ret =3D -EINVAL; +=09=09break; +=09} + +=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; +=09const struct vd55g0_mode_info *cur_mode =3D sensor->current_mode; +=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 sensor->line_length - cur_mode->crop.width; +=09unsigned int expo_mode =3D sensor->expo_state =3D=3D VD55G0_EXP_AUTO ? +=09=09V4L2_EXPOSURE_AUTO : V4L2_EXPOSURE_MANUAL; +=09int ret; + +=09v4l2_ctrl_handler_init(hdl, 16); +=09/* we can use our own mutex for the ctrl lock */ +=09hdl->lock =3D &sensor->lock; +=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, sensor->pixel_rate, +=09=09=09 sensor->pixel_rate, 1, sensor->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, expo_mode); +=09sensor->again_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GA= IN, +=09=09=09=09=09 0, 24, 1, sensor->analog_gain); +=09sensor->dgain_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAI= N, +=09=09=09=09=09 256, 2048, 1, +=09=09=09=09=09 sensor->digital_gain); +=09v4l2_ctrl_new_std(hdl, ops, V4L2_CID_3A_LOCK, 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 sensor->flash_en); + +=09/* +=09 * Keep a pointer to these controls as we need to update them when +=09 * setting the format +=09 */ +=09sensor->vblank_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, +=09=09=09=09=09=09sensor->vblank_min, +=09=09=09=09=09=090xffff - cur_mode->crop.height, +=09=09=09=09=09=091, sensor->vblank); +=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->vflip_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, +=09=09=09=09=09 0, 1, 1, sensor->vflip); +=09sensor->hflip_ctrl =3D v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, +=09=09=09=09=09 0, 1, 1, sensor->hflip); +=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 sensor->frame_length - VD55G0_EXPO_MAX_TERM, +=09=09=09=09 1, sensor->manual_expo); +=09if (!hdl->error) +=09=09v4l2_ctrl_auto_cluster(4, &sensor->ae_ctrl, +=09=09=09=09 V4L2_EXPOSURE_MANUAL, true); + +=09ret =3D v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &fwnode_prop= s); +=09if (ret) +=09=09goto free_ctrls; + +=09ret =3D v4l2_ctrl_new_fwnode_properties(hdl, ops, &fwnode_props); +=09if (ret) +=09=09goto free_ctrls; + +=09if (hdl->error) { +=09=09ret =3D hdl->error; +=09=09goto free_ctrls; +=09} + +=09sensor->sd.ctrl_handler =3D hdl; +=09return 0; + +free_ctrls: +=09v4l2_ctrl_handler_free(hdl); +=09return ret; +} + +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(sensor->nb_supplies, 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(sensor->nb_supplies, 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(sensor->nb_supplies, 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; +=09unsigned int i; +=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 (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->analog_gain =3D 0; +=09sensor->digital_gain =3D 256; + +=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->streaming =3D false; +=09/* Must match what vd55g0_init_state() puts in the subdev state */ +=09sensor->code =3D VD55G0_MEDIA_BUS_FMT_DEF; +=09sensor->manual_expo =3D VD55G0_EXPO_DEF; +=09sensor->vflip =3D false; +=09sensor->hflip =3D false; +=09sensor->flash_en =3D false; +=09/* Written at every stream start, so it must match the control default = */ +=09sensor->exposure_target =3D VD55G0_EXPO_TARGET_DEF; +=09sensor->cold_start.expo =3D 0x32; +=09sensor->cold_start.digital_gain =3D 256; +=09sensor->cold_start.analog_gain =3D 0; + +=09sensor->current_mode =3D &vd55g0_mode_data[VD55G0_DEFAULT_MODE]; + +=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_prepare_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.ops =3D &vd55g0_subdev_entity_ops; +=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; + +=09mutex_init(&sensor->lock); + +=09ret =3D vd55g0_update_vblank(sensor, VD55G0_FRAME_LENGTH_DEF - +=09=09=09=09 sensor->current_mode->crop.height); +=09if (ret) +=09=09goto error_power_off; + +=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->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} + +=09pm_runtime_set_active(dev); +=09pm_runtime_enable(dev); + +=09ret =3D v4l2_async_register_subdev(&sensor->sd); +=09if (ret) { +=09=09dev_err(&client->dev, "async subdev register failed %d\n", ret); +=09=09goto error_pm_runtime; +=09} + +=09/* Runtime PM may power the sensor down only from here on */ +=09pm_runtime_set_autosuspend_delay(&client->dev, 1000); +=09pm_runtime_use_autosuspend(&client->dev); +=09pm_runtime_idle(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(&client->dev); +=09pm_runtime_set_suspended(&client->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: +=09mutex_destroy(&sensor->lock); +=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); +=09mutex_destroy(&sensor->lock); + +=09pm_runtime_disable(&client->dev); +=09if (!pm_runtime_status_suspended(&client->dev)) +=09=09vd55g0_power_off(&client->dev); +=09pm_runtime_set_suspended(&client->dev); +=09pm_runtime_dont_use_autosuspend(&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 dev_pm_ops vd55g0_pm_ops =3D { +=09SET_RUNTIME_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 &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