mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Sakari Ailus <sakari.ailus@linux.intel.com>
To: Sergey Lebedev <lsa.uz@pm.me>
Cc: Benjamin Mugnier <benjamin.mugnier@foss.st.com>,
	Sylvain Petinot <sylvain.petinot@foss.st.com>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	Dan Scally <dan.scally@ideasonboard.com>,
	Hans de Goede <hansg@kernel.org>, Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Peter Marshall <pm@petermarshall.ca>,
	George Neacsu <geocausa@gmail.com>, Hao Yao <hao.yao@intel.com>,
	Fernando Rimoli <fernandorimoli11@gmail.com>,
	"D. Manresa" <dmanresa@gmail.com>, Jizhou Tong <fqwqf@fqwqf.xyz>,
	linux-media@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 2/4] media: i2c: Add ST VD55G0 global shutter sensor driver
Date: Mon, 9 Nov 2026 13:36:37 +0200	[thread overview]
Message-ID: <avGwRaKSqXdtXkII@kekkonen.localdomain> (raw)
In-Reply-To: <20261109093353.3757-3-lsa.uz@pm.me>

Hi Sergey, Benjamin,

Thanks for the set.

On Mon, Nov 09, 2026 at 09:34:28AM +0000, Sergey Lebedev wrote:
> 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 <benjamin.mugnier@foss.st.com>
> Signed-off-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com>
> Signed-off-by: Sergey Lebedev <lsa.uz@pm.me>
> ---
> 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.
> 
> v3: Sashiko's three points on v2 (auto exposure readback after a
> stream, the runtime PM reference across probe, RUNTIME_PM_OPS() and
> pm_ptr()); registration through v4l2_async_register_subdev_sensor()
> (Jizhou Tong), with dev_err_probe() on failure.
> v2: no code change; MAINTAINERS no longer lists a binding for it.
> 
>  MAINTAINERS                |    9 +
>  drivers/media/i2c/Kconfig  |   11 +
>  drivers/media/i2c/Makefile |    1 +
>  drivers/media/i2c/vd55g0.c | 2442 ++++++++++++++++++++++++++++++++++++
>  4 files changed, 2463 insertions(+)
>  create mode 100644 drivers/media/i2c/vd55g0.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 93abbb31506..dbbc5b05954 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -26592,6 +26592,14 @@ F:	Documentation/devicetree/bindings/hwmon/st,tsc1641.yaml
>  F:	Documentation/hwmon/tsc1641.rst
>  F:	drivers/hwmon/tsc1641.c
>  
> +ST VD55G0 DRIVER
> +M:	Benjamin Mugnier <benjamin.mugnier@foss.st.com>
> +M:	Sergey Lebedev <lsa.uz@pm.me>
> +M:	Sylvain Petinot <sylvain.petinot@foss.st.com>
> +L:	linux-media@vger.kernel.org
> +S:	Maintained
> +F:	drivers/media/i2c/vd55g0.c
> +
>  ST VD55G1 DRIVER
>  M:	Benjamin Mugnier <benjamin.mugnier@foss.st.com>
>  M:	Sylvain Petinot <sylvain.petinot@foss.st.com>
> @@ -29317,6 +29325,7 @@ F:	drivers/media/i2c/mt*
>  F:	drivers/media/i2c/og*
>  F:	drivers/media/i2c/ov*
>  F:	drivers/media/i2c/s5*
> +F:	drivers/media/i2c/vd55g0.c
>  F:	drivers/media/i2c/vd55g1.c
>  F:	drivers/media/i2c/vd56g3.c
>  F:	drivers/media/i2c/vgxy61.c
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 11c30252540..f8a653154de 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -891,6 +891,17 @@ config VIDEO_T4KA3
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called t4ka3.
>  
> +config VIDEO_VD55G0
> +	tristate "ST VD55G0 sensor support"
> +	select V4L2_CCI_I2C
> +	depends on GPIOLIB
> +	help
> +	  This is a Video4Linux2 sensor driver for the ST VD55G0
> +	  camera sensor.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called vd55g0.
> +
>  config VIDEO_VD55G1
>  	tristate "ST VD55G1 sensor support"
>  	select 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) += tw9910.o
>  obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o
>  obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
>  obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
> +obj-$(CONFIG_VIDEO_VD55G0) += vd55g0.o
>  obj-$(CONFIG_VIDEO_VD55G1) += vd55g1.o
>  obj-$(CONFIG_VIDEO_VD56G3) += vd56g3.o
>  obj-$(CONFIG_VIDEO_VGXY61) += vgxy61.o
> diff --git a/drivers/media/i2c/vd55g0.c b/drivers/media/i2c/vd55g0.c
> new file mode 100644
> index 00000000000..6e9f9d44625
> --- /dev/null
> +++ b/drivers/media/i2c/vd55g0.c
> @@ -0,0 +1,2442 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for the ST VD55G0 global shutter sensor
> + *
> + * Copyright (C) 2026 STMicroelectronics SA
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/iopoll.h>
> +#include <linux/module.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/units.h>
> +
> +#include <media/mipi-csi2.h>
> +#include <media/v4l2-async.h>
> +#include <media/v4l2-cci.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-fwnode.h>
> +#include <media/v4l2-subdev.h>
> +
> +#define VD55G0_REG_MODEL_ID				CCI_REG16_LE(0x0000)
> +#define VD55G0_MODEL_ID					0x4730
> +#define VD55G0_REG_REVISION				CCI_REG16_LE(0x0004)
> +#define VD55G0_REVISION_CUT1				0x1111
> +#define VD55G0_REVISION_CUT2				0x1120
> +#define VD55G0_REG_FWPATCH_REVISION			CCI_REG16_LE(0x0022)
> +#define VD55G0_REG_FWPATCH_START_ADDR			CCI_REG8(0x2000)
> +#define VD55G0_REG_SYSTEM_FSM				CCI_REG8(0x002c)
> +#define VD55G0_SYSTEM_FSM_READY_TO_BOOT			0x01
> +#define VD55G0_SYSTEM_FSM_SW_STBY			0x02
> +#define VD55G0_SYSTEM_FSM_STREAMING			0x03
> +#define VD55G0_REG_BOOT					CCI_REG8(0x0200)
> +#define VD55G0_BOOT_BOOT				1
> +#define VD55G0_BOOT_PATCH_SETUP				2
> +#define VD55G0_REG_SW_STBY				CCI_REG8(0x0201)
> +#define VD55G0_SW_STBY_START_STREAM			1
> +#define VD55G0_REG_STREAMING				CCI_REG8(0x0202)
> +#define VD55G0_STREAMING_STOP_STREAM			1
> +#define VD55G0_REG_EXT_CLOCK				CCI_REG32_LE(0x0220)
> +#define VD55G0_REG_LINE_LENGTH				CCI_REG16_LE(0x0300)
> +#define VD55G0_REG_ORIENTATION				CCI_REG8(0x0302)
> +#define VD55G0_REG_FORMAT_CTRL				CCI_REG8(0x030a)
> +#define VD55G0_REG_OIF_CTRL				CCI_REG16_LE(0x030c)
> +#define VD55G0_REG_OIF_IMG_CTRL				CCI_REG8(0x030f)
> +#define VD55G0_REG_ISL_ENABLE				CCI_REG8(0x0329)
> +#define VD55G0_REG_CLK_PLL_MIPI				CCI_REG32_LE(0x0224)
> +#define VD55G0_REG_PATGEN_CTRL				CCI_REG16_LE(0x0400)
> +#define VD55G0_PATGEN_TYPE_SHIFT			4
> +#define VD55G0_PATGEN_ENABLE				BIT(0)
> +#define VD55G0_REG_MANUAL_ANALOG_GAIN			CCI_REG8(0x044d)
> +#define VD55G0_REG_MANUAL_COARSE_EXPOSURE		CCI_REG16_LE(0x044e)
> +#define VD55G0_REG_MANUAL_DIGITAL_GAIN			CCI_REG16_LE(0x0450)
> +#define VD55G0_REG_APPLIED_COARSE_EXPOSURE		CCI_REG16_LE(0x0064)
> +#define VD55G0_REG_APPLIED_ANALOG_GAIN			CCI_REG8(0x0066)
> +#define VD55G0_REG_APPLIED_DIGITAL_GAIN			CCI_REG16_LE(0x0068)
> +#define VD55G0_REG_AE_COLDSTART_COARSE_EXPOSURE		CCI_REG16_LE(0x042e)
> +#define VD55G0_REG_AE_COLDSTART_ANALOG_GAIN		CCI_REG8(0x0430)
> +#define VD55G0_REG_AE_COLDSTART_DIGITAL_GAIN		CCI_REG16_LE(0x0432)
> +#define VD55G0_REG_EXP_MODE				CCI_REG8(0x044c)
> +#define VD55G0_REG_FRAME_LENGTH				CCI_REG16_LE(0x0458)
> +#define VD55G0_REG_ROI_X_START				CCI_REG16_LE(0x045e)
> +#define VD55G0_REG_ROI_X_END				CCI_REG16_LE(0x0460)
> +#define VD55G0_REG_ROI_Y_START				CCI_REG16_LE(0x0462)
> +#define VD55G0_REG_ROI_Y_END				CCI_REG16_LE(0x0464)
> +#define VD55G0_REG_AE_ROI_START_H			CCI_REG16_LE(0x0436)
> +#define VD55G0_REG_AE_ROI_START_V			CCI_REG16_LE(0x0438)
> +#define VD55G0_REG_AE_ROI_END_H				CCI_REG16_LE(0x043a)
> +#define VD55G0_REG_AE_ROI_END_V				CCI_REG16_LE(0x043c)
> +#define VD55G0_REG_GPIO_0_CTRL				CCI_REG8(0x0467)
> +#define VD55G0_REG_READOUT_CTRL				CCI_REG8(0x047a)
> +#define VD55G0_REG_DARKCAL_CTRL				CCI_REG8(0x032c)
> +#define VD55G0_DARKCAL_BYPASS				0
> +#define VD55G0_DARKCAL_AUTO				1
> +#define VD55G0_REG_DUSTER_CTRL				CCI_REG8(0x0316)
> +#define VD55G0_DUSTER_ENABLE				BIT(0)
> +#define VD55G0_DUSTER_DISABLE				0
> +#define VD55G0_DUSTER_DYN_ENABLE			BIT(1)
> +#define VD55G0_DUSTER_RING_ENABLE			BIT(4)
> +#define VD55G0_REG_AE_TARGET_PERCENTAGE			CCI_REG8(0x0440)
> +
> +#define VD55G0_WIDTH					644
> +#define VD55G0_HEIGHT					604
> +#define VD55G0_DEFAULT_MODE				1
> +#define VD55G0_WRITE_MULTIPLE_CHUNK_MAX			16
> +#define VD55G0_NB_GPIOS					4
> +#define VD55G0_MIN_FRAME_LENGTH				(605 + 76)
> +#define VD55G0_FRAME_LENGTH_DEF				1860
> +#define VD55G0_TIMEOUT_MS				500
> +#define VD55G0_MEDIA_BUS_FMT_DEF			MEDIA_BUS_FMT_Y8_1X8
> +#define VD55G0_EXPO_MAX_TERM				64
> +#define VD55G0_EXPO_DEF					200
> +#define VD55G0_EXPO_TARGET_DEF				27
> +#define VD55G0_LINE_LENGTH_SLOW				1200
> +#define VD55G0_LINE_LENGTH_FAST				1128
> +#define VD55G0_XCLK_FREQ_MIN				(6 * HZ_PER_MHZ)
> +#define VD55G0_XCLK_FREQ_MAX				(27 * HZ_PER_MHZ)
> +#define VD55G0_MIPI_RATE_MIN				(750 * MEGA)
> +#define VD55G0_MIPI_RATE_MAX				(1200 * MEGA)
> +#define VD55G0_MIPI_RATE_FAST				(900 * MEGA)
> +
> +static const u8 cut1_patch[] = {
> +0x81, 0x06, 0x0b, 0x02, 0x00, 0x09, 0x42, 0x00, 0xd2, 0x08, 0x42, 0x00, 0xe6,

Some indentation would be nice here.

> +0x08, 0x42, 0x00, 0x12, 0x09, 0x42, 0x00, 0xe0, 0x3f, 0x80, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40, 0x01, 0x60, 0x10, 0x40, 0x11,
> +0x81, 0x16, 0x80, 0x93, 0xdd, 0x4c, 0x04, 0x04, 0xfa, 0x06, 0x4c, 0x94, 0x60,
> +0xe6, 0x0e, 0xdc, 0xe0, 0x04, 0x18, 0x70, 0x02, 0x08, 0xe7, 0xce, 0x44, 0x01,
> +0x60, 0x10, 0x40, 0x31, 0x85, 0x1e, 0x08, 0x4e, 0x43, 0x01, 0x60, 0x10, 0xc0,
> +0x31, 0x40, 0x20, 0xe0, 0x04, 0x98, 0x29, 0x00, 0x50, 0xeb, 0x2e, 0x84, 0x24,
> +0x84, 0x29, 0x86, 0x2e, 0x84, 0x24, 0x84, 0x2b, 0xa1, 0x15, 0xfe, 0xd8, 0x41,
> +0x00, 0xe8, 0xf8, 0x47, 0x00, 0xe8, 0x78, 0x44, 0x40, 0xef, 0x0a, 0x9c, 0x1a,
> +0x9e, 0x2a, 0xdc, 0x3a, 0xde, 0x03, 0x4e, 0x7c, 0xf9, 0x13, 0x4e, 0x78, 0xf9,
> +0x23, 0x4e, 0x74, 0xf9, 0x33, 0x4e, 0x70, 0xf9, 0x18, 0x50, 0x40, 0xef, 0x38,
> +0x49, 0x44, 0xef, 0x04, 0x18, 0x11, 0x83, 0x11, 0x40, 0x20, 0xe0, 0x4c, 0x0c,
> +0x04, 0xf2, 0x93, 0xdd, 0x86, 0x44, 0x88, 0xe0, 0x05, 0x04, 0x40, 0xf8, 0x09,
> +0x00, 0x24, 0xe0, 0x4a, 0x40, 0x88, 0x60, 0x06, 0x40, 0x94, 0xe0, 0x04, 0x80,
> +0x65, 0x86, 0x31, 0x01, 0x06, 0x02, 0x0c, 0xe1, 0x33, 0x40, 0xc8, 0xe2, 0x33,
> +0x40, 0x70, 0xe2, 0x14, 0x84, 0x18, 0x48, 0x1b, 0xa3, 0x55, 0x8a, 0x0a, 0x02,
> +0x08, 0x70, 0x16, 0x43, 0x58, 0xe0, 0x26, 0x08, 0x00, 0x40, 0x16, 0x0a, 0x00,
> +0xc0, 0x41, 0x44, 0x08, 0x40, 0x06, 0x46, 0x08, 0xe0, 0x51, 0x44, 0x04, 0xc0,
> +0x45, 0x85, 0x66, 0x02, 0x04, 0xe0, 0x13, 0x40, 0x70, 0x62, 0x06, 0x02, 0x0c,
> +0xe1, 0x14, 0x84, 0x18, 0x48, 0x1b, 0xa3, 0xb5, 0x86, 0x0a, 0x02, 0x08, 0x70,
> +0xa6, 0x02, 0x68, 0xe0, 0x26, 0x0a, 0x00, 0x40, 0x16, 0x18, 0x00, 0xc0, 0x31,
> +0x01, 0xc6, 0x09, 0x0c, 0xe0, 0x51, 0x44, 0x08, 0xc0, 0xc1, 0x44, 0x04, 0xc0,
> +0x95, 0x83, 0x0a, 0x02, 0x04, 0xf0, 0x16, 0x02, 0x00, 0xc0, 0x11, 0x44, 0x08,
> +0xc0, 0x11, 0x44, 0x04, 0x40, 0x11, 0x81, 0x33, 0x40, 0x18, 0xe3, 0x15, 0x83,
> +0x0a, 0x02, 0x04, 0x70, 0x11, 0x81, 0x16, 0x0a, 0x00, 0x40, 0x31, 0x9d, 0x51,
> +0x44, 0x08, 0x40, 0x06, 0x09, 0x04, 0xe0, 0x51, 0x44, 0x04, 0xc0, 0x43, 0x40,
> +0x18, 0xe3, 0x33, 0x40, 0xc8, 0xe2, 0x13, 0x40, 0xc0, 0x62, 0xa6, 0x05, 0x78,
> +0xe0, 0x23, 0x40, 0xd0, 0xe3, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x7c, 0xfa,
> +0x86, 0x42, 0x84, 0x60, 0x06, 0x00, 0x0c, 0xe1, 0x14, 0x04, 0xf6, 0x50, 0x78,
> +0xe3, 0x04, 0x00, 0x26, 0x0f, 0x28, 0xe2, 0x16, 0x15, 0x2c, 0x64, 0xb1, 0xbb,
> +0x6a, 0x84, 0x0b, 0xa3, 0x36, 0x10, 0x10, 0x41, 0x2e, 0x54, 0x08, 0xd8, 0x16,
> +0x4f, 0x44, 0x43, 0x06, 0x16, 0x00, 0xc0, 0x0b, 0x10, 0x1b, 0x8c, 0xb8, 0x4f,
> +0x00, 0x6f, 0xa4, 0x12, 0x80, 0xfb, 0x06, 0x42, 0x1a, 0x60, 0x00, 0x40, 0xfc,
> +0x73, 0x03, 0xc0, 0x83, 0x22, 0x0e, 0x02, 0xc1, 0x7f, 0x1f, 0xc0, 0x87, 0xd4,
> +0x8f, 0x02, 0x1b, 0x8c, 0x8f, 0x20, 0x0b, 0x8e, 0x98, 0x4e, 0x00, 0xef, 0x06,
> +0x42, 0x1a, 0x60, 0x00, 0x40, 0xfc, 0xf0, 0x73, 0xa2, 0x77, 0xcc, 0x70, 0x42,
> +0x01, 0x73, 0xff, 0xc7, 0x12, 0x4e, 0x80, 0x79, 0x0b, 0x92, 0xb8, 0x4d, 0x00,
> +0x6f, 0x1b, 0x8c, 0x06, 0x42, 0x94, 0x60, 0x06, 0x46, 0x1a, 0xe0, 0x24, 0x04,
> +0x00, 0x40, 0xfd, 0x73, 0x03, 0xc0, 0xa3, 0xa6, 0xa7, 0xd4, 0xb3, 0x44, 0x60,
> +0xe3, 0x85, 0x44, 0x9c, 0xe0, 0x24, 0x84, 0x75, 0x44, 0xa0, 0x60, 0x0e, 0x04,
> +0xc0, 0x7f, 0x1f, 0xc0, 0x14, 0x04, 0xaf, 0x84, 0xaf, 0xa0, 0xa5, 0x42, 0xa4,
> +0xe0, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x0c, 0x04, 0x0c, 0xfa, 0x46, 0x0d,
> +0xcc, 0xe0, 0x09, 0x0c, 0xbc, 0xee, 0x0a, 0x40, 0x80, 0xe0, 0x45, 0x82, 0xa6,
> +0x40, 0x08, 0xe0, 0x06, 0x98, 0x08, 0x7f, 0x74, 0xef, 0x0b, 0xa1, 0xb5, 0xfe,
> +0x01, 0x87, 0x06, 0x98, 0x06, 0x4c, 0x94, 0x60, 0x06, 0x42, 0x0c, 0xe0, 0x05,
> +0x0c, 0x14, 0xe0, 0x11, 0x40, 0x30, 0x62, 0x26, 0x42, 0x00, 0xe0, 0x05, 0x0c,
> +0x14, 0xe0, 0x11, 0x40, 0xa0, 0x62, 0x56, 0x43, 0x04, 0xe0, 0x05, 0x0c, 0x14,
> +0xe0, 0x11, 0x40, 0x40, 0x62, 0x76, 0x43, 0x04, 0xe0, 0x05, 0x0c, 0x14, 0xe0,
> +0x11, 0x40, 0x50, 0xe2, 0x04, 0x98, 0x19, 0x00, 0x50, 0xeb, 0x4a, 0x42, 0x88,
> +0xe0, 0xc5, 0x80, 0x28, 0x67, 0x54, 0x6f, 0x66, 0x00, 0xa0, 0xe0, 0x04, 0x98,
> +0x19, 0x00, 0x30, 0xe0, 0x19, 0xc4, 0x11, 0x40, 0x30, 0x60, 0x11, 0x83, 0x04,
> +0x9a, 0x11, 0x40, 0x10, 0xe0, 0x04, 0x98, 0x11, 0x40, 0x20, 0x60, 0x11, 0x81,
> +0x04, 0x98, 0x11, 0x40, 0xb0, 0xe7, 0x19, 0x00, 0x50, 0xeb, 0x4a, 0x02, 0x0c,
> +0xfc, 0x85, 0xfe, 0xc6, 0x4c, 0xb4, 0xe0, 0x60, 0x10, 0xb1, 0x64, 0x01, 0xc0,
> +0x0a, 0xe0, 0x0b, 0xa1, 0x95, 0x8c, 0x04, 0xe0, 0x0b, 0xa1, 0x25, 0x8c, 0xd8,
> +0x43, 0x5c, 0xef, 0x0a, 0xe0, 0x0b, 0xa1, 0x95, 0x8a, 0x04, 0xe0, 0x0b, 0xa1,
> +0x25, 0x8a, 0xc6, 0x4e, 0x84, 0xe0, 0x04, 0x9c, 0x09, 0x00, 0x20, 0xe1, 0x4a,
> +0x40, 0x80, 0xe0, 0x25, 0x86, 0x08, 0x22, 0x46, 0x43, 0x00, 0xe0, 0x06, 0x40,
> +0x06, 0xe0, 0x63, 0x80, 0x09, 0x0c, 0x40, 0xe2, 0x09, 0x86, 0x0b, 0xa5, 0xd5,
> +0x82, 0x68, 0x4e, 0x48, 0x6f, 0x01, 0x85, 0x78, 0x44, 0x48, 0x6f, 0x06, 0x00,
> +0x80, 0xe1, 0xf8, 0x75, 0x4c, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0x78, 0x48, 0x48,
> +0xef, 0x09, 0x0e, 0x48, 0xe0, 0x0b, 0xa1, 0xb5, 0x80, 0x58, 0x7b, 0x3c, 0xef,
> +0x78, 0x74, 0x40, 0xef, 0xa6, 0x40, 0x08, 0xe0, 0x0c, 0x0c, 0x0c, 0xf2, 0x18,
> +0x12, 0x50, 0xff, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0x7b, 0x00, 0x06, 0x01,
> +0x08, 0xe1, 0x08, 0x00, 0x6b, 0x82, 0x0b, 0xa1, 0x15, 0x82, 0xa6, 0x41, 0x84,
> +0xe0, 0x18, 0x00, 0x01, 0x89, 0x18, 0x42, 0x00, 0xef, 0x63, 0x80, 0x04, 0x1c,
> +0x64, 0x02, 0x84, 0xe0, 0x78, 0x40, 0x00, 0x68, 0x00, 0x00, 0x40, 0xe6, 0x4c,
> +0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x1e, 0x80, 0x93, 0xdd, 0x0c, 0x04, 0x3c, 0xfa,
> +0xf0, 0x1e, 0x40, 0x6c, 0x86, 0x0f, 0xe0, 0xe0, 0x01, 0x05, 0x91, 0x81, 0x06,
> +0x02, 0x00, 0x62, 0x81, 0xb1, 0x01, 0x4e, 0xd8, 0x69, 0x0e, 0x00, 0x00, 0x60,
> +0x01, 0xc0, 0x0e, 0x7c, 0x6b, 0x9e, 0x93, 0x4e, 0x14, 0x65, 0x86, 0x00, 0x30,
> +0xe1, 0x93, 0x4e, 0x18, 0x65, 0x2b, 0x8c, 0x91, 0x4e, 0x50, 0xe1, 0x81, 0x4e,
> +0xc8, 0xe9, 0x1e, 0xbe, 0x1e, 0x7e, 0x11, 0x8f, 0x9e, 0xbc, 0xd8, 0x55, 0x30,
> +0xef, 0x06, 0x00, 0x00, 0x64, 0x46, 0x02, 0x54, 0xe1, 0x0e, 0x3e, 0x06, 0x00,
> +0x20, 0xe0, 0x0e, 0x7e, 0x86, 0x00, 0x30, 0xe1, 0x1e, 0x7c, 0x11, 0x91, 0x9e,
> +0x3c, 0x2b, 0x8c, 0xd8, 0x54, 0x30, 0xef, 0x06, 0x00, 0x00, 0x66, 0xa1, 0x83,
> +0x0e, 0x3e, 0xf6, 0x41, 0xfc, 0xe9, 0x0e, 0x7e, 0x06, 0x00, 0x01, 0x60, 0x20,
> +0xc0, 0x0e, 0x7c, 0x86, 0x00, 0x30, 0xe1, 0xae, 0x3c, 0x11, 0x93, 0xc8, 0x53,
> +0x30, 0x6f, 0x2b, 0x8c, 0x06, 0x40, 0x88, 0x60, 0xf6, 0x45, 0xfc, 0x63, 0xff,
> +0xc3, 0x14, 0x00, 0xf1, 0xa0, 0x95, 0x4e, 0xa8, 0xe2, 0xa1, 0x4e, 0x44, 0xea,
> +0x81, 0x4e, 0xf0, 0x69, 0x10, 0x42, 0x00, 0x7c, 0x00, 0xcc, 0x1f, 0x04, 0x21,
> +0x8b, 0x1e, 0x00, 0x86, 0x40, 0xfc, 0xe7, 0x05, 0x4e, 0xa4, 0x62, 0xc6, 0x01,
> +0x5c, 0xe0, 0x05, 0x4e, 0xac, 0x62, 0x9e, 0x00, 0x00, 0x60, 0x02, 0xc0, 0x05,
> +0x4e, 0x94, 0x62, 0x86, 0x40, 0x3c, 0x60, 0x10, 0xe7, 0x0e, 0x9c, 0x09, 0x0e,
> +0x0c, 0xe1, 0x15, 0x4e, 0x3c, 0x79, 0x06, 0x02, 0x80, 0xe0, 0x13, 0x4e, 0xf4,
> +0x64, 0x86, 0x02, 0x00, 0x60, 0x02, 0xc0, 0x21, 0x4e, 0x5c, 0x69, 0x00, 0x40,
> +0xc0, 0xf3, 0x1e, 0x9e, 0x01, 0x4e, 0x0c, 0xe1, 0x0c, 0x0c, 0x3c, 0xf2, 0x93,
> +0xdd, 0xc6, 0x01, 0xcc, 0x60, 0x06, 0x42, 0x88, 0xe0, 0x29, 0x00, 0x98, 0xee,
> +0x34, 0x84, 0x4a, 0x44, 0x80, 0x60, 0x86, 0x04, 0x30, 0xe1, 0x24, 0x08, 0x30,
> +0x46, 0xfd, 0x73, 0xff, 0xc3, 0x3e, 0x04, 0xa6, 0x08, 0xa0, 0x80, 0x34, 0x06,
> +0xc8, 0x9c, 0x45, 0x44, 0xa0, 0x80, 0x35, 0x42, 0x00, 0x00, 0x06, 0x06, 0x00,
> +0xc0, 0x35, 0x44, 0xa0, 0xc0, 0x35, 0x02, 0x00, 0xc0, 0x3e, 0x80, 0x93, 0xdd,
> +0x4c, 0x00, 0x00, 0xfa, 0x88, 0x40, 0x00, 0xe8, 0x86, 0x02, 0x0c, 0xe1, 0x0e,
> +0x84, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04,
> +0x00, 0xf8, 0xc6, 0x40, 0xb4, 0xe0, 0x00, 0x02, 0xb1, 0x64, 0x01, 0xc0, 0x2a,
> +0xc4, 0x2b, 0xa1, 0x35, 0x92, 0x24, 0xc4, 0x2b, 0xa1, 0xc5, 0x90, 0x38, 0x06,
> +0x46, 0x45, 0x00, 0xe0, 0x36, 0x46, 0x0a, 0xe0, 0x33, 0x80, 0x49, 0x06, 0xf0,
> +0xe2, 0x4d, 0xe6, 0xc6, 0x40, 0x48, 0x41, 0x16, 0x02, 0x00, 0xc0, 0x11, 0x40,
> +0x00, 0xc0, 0xd5, 0x8c, 0xc9, 0x06, 0x44, 0x62, 0x06, 0x4b, 0x00, 0xe0, 0x46,
> +0x48, 0x16, 0x60, 0x86, 0x4a, 0xc8, 0xe0, 0x53, 0x08, 0xc0, 0x58, 0x80, 0xf3,
> +0x49, 0x0a, 0xa4, 0xe7, 0x6b, 0x0a, 0xd8, 0xe3, 0x49, 0xbe, 0xcf, 0xa8, 0xc1,
> +0x46, 0x44, 0xe2, 0x48, 0x86, 0xc9, 0x0a, 0xa0, 0xe7, 0x46, 0x48, 0x0a, 0xe0,
> +0xc1, 0x46, 0x40, 0xe2, 0xcb, 0x0a, 0xe0, 0x63, 0x43, 0x80, 0x63, 0x48, 0x28,
> +0xe1, 0x38, 0x86, 0x36, 0x46, 0x0a, 0xe0, 0x33, 0x80, 0xc3, 0x46, 0x30, 0xe1,
> +0x18, 0x86, 0xcb, 0x0a, 0xd4, 0xe3, 0x2b, 0x0a, 0xdc, 0x63, 0x16, 0x42, 0x0a,
> +0xe0, 0x5b, 0x0a, 0xe4, 0xe3, 0xc3, 0x48, 0x24, 0x61, 0x03, 0x82, 0x23, 0x46,
> +0x2c, 0xe1, 0x53, 0x40, 0x34, 0xe1, 0x4c, 0x0c, 0x00, 0xf0, 0x93, 0xdd, 0xc3,
> +0xc1, 0x0c, 0x00, 0x80, 0xfa, 0x86, 0x43, 0xcc, 0x60, 0x0b, 0xa3, 0x29, 0x02,
> +0xc4, 0xee, 0xb5, 0x84, 0x4a, 0x04, 0xfc, 0xfb, 0x45, 0x84, 0xc6, 0x40, 0x84,
> +0xe0, 0x14, 0x82, 0x18, 0x84, 0x19, 0x86, 0x1b, 0xa5, 0x85, 0x8c, 0x04, 0x80,
> +0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, 0xc5, 0x8a, 0x0c, 0x08, 0x80,
> +0xf2, 0x08, 0x34, 0x44, 0xff, 0x0b, 0xa5, 0x15, 0x8a, 0x0a, 0x04, 0x04, 0xf0,
> +0xb5, 0x88, 0xc6, 0x40, 0x84, 0xe0, 0x24, 0x82, 0x28, 0x88, 0x29, 0x86, 0x2b,
> +0xa5, 0xc5, 0x86, 0x04, 0x80, 0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0,
> +0x05, 0x86, 0x09, 0x02, 0x24, 0xee, 0x0b, 0xa3, 0xd5, 0x80, 0x08, 0x84, 0x0a,
> +0x40, 0x80, 0xe0, 0x75, 0xf8, 0xf5, 0x81, 0x38, 0x72, 0x44, 0xef, 0xf8, 0x51,
> +0xfc, 0xef, 0x4e, 0x40, 0x01, 0x60, 0x10, 0xc0, 0x08, 0x80, 0x0b, 0xa1, 0xa5,
> +0x80, 0x0c, 0x08, 0x80, 0xf2, 0xb8, 0x11, 0xfc, 0xff, 0x0c, 0x08, 0x80, 0xf2,
> +0x93, 0xdd, 0xcc, 0x04, 0x0c, 0xfa, 0x06, 0x4f, 0x84, 0x60, 0x86, 0x50, 0x4c,
> +0xe1, 0x04, 0x1c, 0x80, 0x0c, 0x21, 0x6f, 0x01, 0xc0, 0xf0, 0x04, 0x50, 0x64,
> +0x11, 0x81, 0x09, 0x00, 0x6c, 0xe0, 0x06, 0x29, 0x0b, 0x8c, 0x58, 0x4c, 0x58,
> +0xef, 0x04, 0x9c, 0x19, 0x00, 0x6c, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, 0xa3,
> +0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, 0x2f,
> +0xa2, 0x21, 0x40, 0x6c, 0xe0, 0x86, 0x43, 0xcc, 0xe0, 0x29, 0x02, 0x24, 0xee,
> +0x2b, 0xa3, 0xd5, 0x80, 0x18, 0x84, 0x4a, 0x42, 0x80, 0x60, 0x11, 0x8b, 0x65,
> +0x80, 0x19, 0x00, 0x70, 0xe0, 0x16, 0x29, 0xf0, 0x04, 0x50, 0xe4, 0x11, 0x03,
> +0x0b, 0x8c, 0x28, 0x4a, 0x58, 0xef, 0x04, 0x9c, 0x19, 0x00, 0x70, 0xe0, 0x10,
> +0x44, 0x3c, 0xf0, 0x2b, 0xa3, 0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3,
> +0x27, 0xc8, 0x29, 0xa0, 0x2f, 0xa2, 0x21, 0x40, 0x70, 0xe0, 0x09, 0x00, 0x74,
> +0x60, 0xf0, 0x04, 0x50, 0xe4, 0x11, 0x85, 0x06, 0x29, 0x0b, 0x8c, 0xa8, 0x48,
> +0x58, 0xef, 0x04, 0x9c, 0x19, 0x00, 0x74, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b,
> +0xa3, 0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0,
> +0x2f, 0xa2, 0x21, 0x40, 0x74, 0xe0, 0x09, 0x00, 0x78, 0x60, 0xf0, 0x04, 0x50,
> +0xe4, 0x11, 0x87, 0x06, 0x29, 0x0b, 0x8c, 0x28, 0x47, 0x58, 0xef, 0x04, 0x9c,
> +0x19, 0x00, 0x78, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, 0xa3, 0x35, 0x82, 0x28,
> +0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, 0x2f, 0xa2, 0x21, 0x40,
> +0x78, 0xe0, 0x19, 0x0e, 0xd0, 0xe0, 0x1b, 0xa1, 0x85, 0x86, 0x05, 0x00, 0x24,
> +0xe0, 0x1a, 0xa2, 0x04, 0x04, 0xc0, 0xe1, 0x2b, 0x83, 0xd5, 0x80, 0x19, 0x10,
> +0x10, 0x60, 0x09, 0x9e, 0x0b, 0x83, 0x85, 0x84, 0x08, 0xa0, 0x0b, 0xa1, 0x38,
> +0x61, 0x74, 0xcf, 0x58, 0x49, 0x34, 0xef, 0x14, 0x9c, 0x25, 0x02, 0x24, 0xe0,
> +0x24, 0x02, 0xc0, 0x61, 0x29, 0x9e, 0x18, 0x58, 0x74, 0xef, 0x55, 0x81, 0x08,
> +0xa0, 0x0b, 0xa1, 0x48, 0x60, 0x74, 0xcf, 0x28, 0x72, 0x4c, 0x6f, 0x46, 0x01,
> +0x08, 0xe0, 0xcc, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x65, 0x5e, 0x04,
> +0xfa, 0xf0, 0x0c, 0x10, 0xec, 0x60, 0x5e, 0x1c, 0x74, 0x61, 0x88, 0x6e, 0xbc,
> +0xfc, 0x07, 0x80, 0xfe, 0xf0, 0x1e, 0x20, 0x6c, 0xe6, 0x40, 0x00, 0xe0, 0xc8,
> +0x70, 0x4c, 0xef, 0x0b, 0xa1, 0xb5, 0x88, 0xc6, 0x0d, 0xdc, 0xe0, 0x09, 0x0c,
> +0x94, 0xea, 0x0b, 0xa3, 0xf5, 0x80, 0x09, 0x0c, 0x91, 0x79, 0x01, 0xc0, 0x0a,
> +0x40, 0x80, 0xe0, 0xe5, 0x82, 0xc8, 0x71, 0x44, 0xef, 0x04, 0x18, 0x86, 0x02,
> +0x84, 0xe0, 0x24, 0x04, 0x31, 0x83, 0x01, 0x82, 0x0e, 0x18, 0xe6, 0x00, 0x48,
> +0xe1, 0x36, 0x00, 0x21, 0x82, 0x2e, 0x84, 0x46, 0x00, 0x2c, 0x61, 0x21, 0x83,
> +0x14, 0x00, 0x46, 0x40, 0x34, 0xe1, 0x25, 0x42, 0x44, 0xe0, 0x28, 0x51, 0x28,
> +0xef, 0x88, 0x40, 0x00, 0xe8, 0xf1, 0x90, 0xfc, 0x0f, 0x80, 0xf6, 0xf4, 0xbc,
> +0x64, 0xfd, 0x53, 0xc1, 0x4c, 0x00, 0x00, 0xfa, 0x01, 0x03, 0x11, 0x81, 0x48,
> +0x79, 0x08, 0xef, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x00,
> +0x00, 0xfa, 0x0d, 0x62, 0x8e, 0x45, 0xf0, 0xff, 0x75, 0x82, 0x4e, 0x05, 0x01,
> +0x60, 0x10, 0x40, 0x07, 0xc8, 0x24, 0x88, 0x23, 0x80, 0x1e, 0x8a, 0x78, 0x40,
> +0x00, 0xe8, 0x21, 0x81, 0x0b, 0x84, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0x83,
> +0xc1, 0x93, 0xdd, 0x0c, 0x04, 0x00, 0xfa, 0x41, 0xb9, 0x06, 0x48, 0x12, 0xe0,
> +0x33, 0x88, 0x45, 0x06, 0x14, 0xe0, 0x4b, 0xa3, 0xc5, 0x80, 0x35, 0x06, 0x18,
> +0xe0, 0x3b, 0x23, 0x31, 0x81, 0x55, 0x80, 0x31, 0x83, 0x0d, 0xe6, 0x04, 0x00,
> +0x88, 0x00, 0x4e, 0x08, 0x00, 0x00, 0x10, 0x80, 0x05, 0x00, 0x10, 0x9c, 0x08,
> +0x40, 0x00, 0x98, 0x25, 0x0b, 0x8e, 0x40, 0xf0, 0xff, 0x3b, 0xa1, 0x45, 0x8a,
> +0x2b, 0x23, 0x06, 0x4c, 0x00, 0xe0, 0x45, 0x90, 0x2b, 0x25, 0x6e, 0x40, 0xf0,
> +0xff, 0x25, 0x87, 0x3b, 0xa1, 0x25, 0x8a, 0x2b, 0x23, 0x06, 0x0c, 0x08, 0xe0,
> +0x05, 0x8e, 0x2b, 0x25, 0x5e, 0x40, 0xf0, 0xff, 0x85, 0x0c, 0x06, 0x0c, 0x04,
> +0xe0, 0x95, 0x87, 0x3b, 0xa1, 0xc5, 0x88, 0x2b, 0x23, 0x61, 0x91, 0x85, 0x8a,
> +0x2b, 0x25, 0x7e, 0x40, 0xf0, 0xff, 0x25, 0x83, 0x2b, 0xa3, 0xc5, 0x08, 0x06,
> +0x0c, 0x08, 0x80, 0x2b, 0x25, 0x4e, 0x40, 0xf0, 0xff, 0x15, 0x8a, 0xf5, 0x03,
> +0x06, 0x0c, 0x04, 0xe0, 0x2b, 0x23, 0x61, 0x91, 0x45, 0x86, 0x2b, 0x25, 0x6e,
> +0x40, 0xf0, 0xff, 0xc5, 0x04, 0x61, 0x89, 0xc5, 0x83, 0x2b, 0x23, 0x06, 0x4c,
> +0x00, 0xe0, 0x05, 0x84, 0x2b, 0x25, 0x5e, 0x40, 0xf0, 0xff, 0x85, 0x02, 0x61,
> +0xa1, 0x25, 0x83, 0x2b, 0x23, 0x61, 0x85, 0xe5, 0x80, 0x2b, 0x25, 0x7e, 0x40,
> +0xf0, 0xff, 0x65, 0x00, 0x61, 0x83, 0x95, 0x81, 0x0b, 0x02, 0x1b, 0x8c, 0x48,
> +0x78, 0xfc, 0xef, 0x0b, 0xa1, 0x00, 0x4c, 0x00, 0xdc, 0x0b, 0x8c, 0x0c, 0x0c,
> +0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x04, 0xfa, 0x6b, 0x00, 0xc6,
> +0x40, 0xdc, 0xe0, 0x04, 0x00, 0xf0, 0x1e, 0x30, 0xec, 0x48, 0x55, 0xfc, 0x6e,
> +0x0e, 0x02, 0x24, 0x74, 0x03, 0xc0, 0xb8, 0x68, 0xfc, 0xee, 0x58, 0x71, 0x08,
> +0xef, 0x78, 0x68, 0xfc, 0x6e, 0x0b, 0x8c, 0x71, 0x01, 0x5b, 0x80, 0x7e, 0x3c,
> +0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0, 0x11, 0x03, 0x21, 0x81, 0x31, 0x05, 0x41,
> +0x81, 0xa8, 0x77, 0x08, 0xef, 0x0e, 0x3e, 0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0,
> +0x48, 0x4b, 0x0c, 0xef, 0x0e, 0x7c, 0x11, 0x81, 0x04, 0x3e, 0x21, 0x83, 0x68,
> +0x76, 0xfc, 0x6f, 0x0e, 0x06, 0x04, 0x60, 0x10, 0xc0, 0xce, 0x0d, 0x01, 0x60,
> +0x10, 0xc0, 0x76, 0x98, 0x04, 0xfc, 0xc8, 0x59, 0x0c, 0xef, 0x13, 0xc3, 0x08,
> +0x98, 0x0b, 0xa1, 0xa5, 0xfe, 0x04, 0xfc, 0x18, 0x5c, 0x0c, 0xef, 0x14, 0x3e,
> +0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0, 0x38, 0x46, 0x0c, 0xef, 0x01, 0x01, 0xf1,
> +0x98, 0x0c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x65, 0x5e, 0x04, 0xfa, 0xf0, 0x0c,
> +0x10, 0xec, 0x60, 0x5e, 0x1c, 0x74, 0x61, 0x88, 0x6e, 0xbc, 0xfc, 0x03, 0x80,
> +0xfe, 0x26, 0x00, 0x4c, 0x61, 0x11, 0x83, 0x16, 0x00, 0xce, 0x01, 0x01, 0x60,
> +0x10, 0xc0, 0x16, 0x00, 0x46, 0x00, 0x2c, 0xe1, 0x04, 0x00, 0xf0, 0x1e, 0x30,
> +0xec, 0x14, 0xc0, 0x14, 0x02, 0x20, 0xfc, 0x1e, 0xc0, 0x98, 0x40, 0x00, 0xe8,
> +0xf1, 0x98, 0xfc, 0x0b, 0x80, 0xf6, 0xf4, 0xbc, 0x64, 0xfd, 0x53, 0xc1, 0xc3,
> +0xc1, 0x06, 0x00, 0x01, 0x60, 0x00, 0xe0, 0x06, 0x00, 0x62, 0xf4, 0x93, 0xdd,
> +0x4c, 0x04, 0x7c, 0xfa, 0xc6, 0x54, 0x84, 0x60, 0x06, 0x0f, 0xdc, 0xe0, 0x04,
> +0x2a, 0xae, 0x4d, 0x01, 0x60, 0x10, 0xc0, 0x29, 0x14, 0x70, 0x60, 0x8e, 0x51,
> +0x00, 0x60, 0x10, 0xc0, 0x3b, 0x0e, 0x9c, 0x65, 0x06, 0x52, 0x94, 0xe0, 0x1b,
> +0x00, 0x20, 0x60, 0x0e, 0x57, 0x08, 0x60, 0x10, 0xc0, 0x0b, 0x00, 0x1c, 0xe0,
> +0x13, 0x20, 0x01, 0x81, 0x13, 0x84, 0x13, 0x86, 0x11, 0x9e, 0x1c, 0x98, 0x0c,
> +0xa0, 0x04, 0xa4, 0x0b, 0x00, 0xa0, 0xe5, 0x0c, 0xac, 0x0a, 0x98, 0x1a, 0xac,
> +0x0d, 0xc3, 0xf5, 0x82, 0x04, 0xa4, 0x0b, 0x00, 0xa0, 0xe5, 0x0c, 0x2c, 0x01,
> +0x8b, 0x08, 0x56, 0x2c, 0xef, 0x0a, 0xa0, 0x01, 0x82, 0x0c, 0xa0, 0x0a, 0xa0,
> +0x8a, 0x00, 0x24, 0xe7, 0xf5, 0xfa, 0x05, 0x0e, 0xbc, 0x61, 0x06, 0x04, 0x00,
> +0x60, 0x00, 0xf0, 0x13, 0x0e, 0xb8, 0x79, 0x06, 0x06, 0x00, 0x60, 0x00, 0xe0,
> +0x2f, 0x80, 0x2b, 0x07, 0x0e, 0x45, 0x01, 0x60, 0x10, 0xc0, 0x1c, 0x88, 0x95,
> +0x86, 0x07, 0xe1, 0x09, 0xbe, 0x0b, 0xa1, 0x05, 0x86, 0x21, 0xff, 0x1d, 0x84,
> +0x85, 0x02, 0x00, 0x00, 0x08, 0x8c, 0x10, 0x04, 0x18, 0xec, 0x8a, 0x04, 0x14,
> +0xed, 0xb5, 0x80, 0x8a, 0x02, 0x40, 0xe1, 0x75, 0x82, 0x01, 0x84, 0x14, 0x24,
> +0x09, 0xbe, 0x29, 0x02, 0x00, 0xe3, 0x20, 0x44, 0x80, 0xf3, 0x2f, 0xa0, 0x21,
> +0x42, 0x00, 0xe3, 0x8e, 0x41, 0x09, 0x60, 0x10, 0x40, 0xc6, 0x0d, 0x30, 0xe1,
> +0x04, 0x80, 0x0b, 0xa3, 0x75, 0xa0, 0x19, 0x0c, 0xcc, 0xe5, 0x4a, 0x02, 0xfc,
> +0xfb, 0xc5, 0x9e, 0xa8, 0x54, 0x00, 0x68, 0x01, 0x81, 0x04, 0x24, 0x11, 0x85,
> +0x11, 0x40, 0x20, 0x60, 0x4e, 0x43, 0x00, 0x60, 0x10, 0xc0, 0x04, 0xa4, 0x29,
> +0x00, 0x50, 0xeb, 0x2e, 0x84, 0x24, 0x84, 0x29, 0x86, 0x2e, 0x84, 0x24, 0x84,
> +0x2b, 0xa1, 0x15, 0xfe, 0xa8, 0x52, 0x44, 0xef, 0x04, 0xaa, 0x08, 0x80, 0x0b,
> +0xa5, 0xe5, 0x80, 0x04, 0xa8, 0x09, 0x00, 0x20, 0xe1, 0x0b, 0xa1, 0x48, 0x4a,
> +0x44, 0x8f, 0x46, 0x10, 0x74, 0xe1, 0x04, 0xa0, 0x14, 0xc0, 0x14, 0x02, 0x2c,
> +0xfc, 0x1e, 0xc0, 0x14, 0xc0, 0x14, 0x02, 0x08, 0xfc, 0x1e, 0x40, 0x11, 0x83,
> +0x04, 0xa4, 0x11, 0x40, 0xb0, 0x67, 0x11, 0x81, 0x04, 0xa6, 0x11, 0x40, 0x10,
> +0xe0, 0xb8, 0x73, 0x74, 0xef, 0x84, 0x20, 0x70, 0x06, 0x00, 0xe7, 0x8e, 0x17,
> +0x01, 0x60, 0x10, 0x40, 0xce, 0x54, 0x01, 0x60, 0x10, 0xc0, 0x04, 0xe0, 0x04,
> +0x00, 0x04, 0xfc, 0x0e, 0xe0, 0x04, 0xe0, 0x04, 0x00, 0x0c, 0xfc, 0x0e, 0xe0,
> +0x04, 0xe0, 0x04, 0x00, 0x10, 0xfc, 0x0e, 0xe0, 0x45, 0x10, 0x2c, 0xe0, 0x44,
> +0x00, 0x00, 0xfc, 0x05, 0x50, 0x2c, 0x60, 0x4e, 0x41, 0x08, 0x60, 0x10, 0xc0,
> +0x1b, 0x0e, 0xa0, 0xe1, 0x04, 0x80, 0x2b, 0x0e, 0x9c, 0xe1, 0x1b, 0xc2, 0x03,
> +0x02, 0xce, 0x42, 0x01, 0x60, 0x10, 0xc0, 0x3e, 0x04, 0x03, 0x84, 0x00, 0x00,
> +0xf4, 0xec, 0x0e, 0xac, 0x09, 0x0e, 0x00, 0xe3, 0x4e, 0x8f, 0x0b, 0xa5, 0x0b,
> +0x0e, 0x10, 0xd8, 0x95, 0x96, 0x0b, 0x0e, 0x84, 0xe1, 0x15, 0x0e, 0x10, 0xe0,
> +0x03, 0x4e, 0x10, 0xf8, 0x1d, 0xc1, 0x13, 0x4e, 0x10, 0x58, 0x10, 0x40, 0x00,
> +0xdc, 0x1a, 0x5e, 0x04, 0x04, 0x80, 0xfb, 0x2d, 0xc3, 0x13, 0x4e, 0x10, 0x58,
> +0x10, 0x40, 0x00, 0xdc, 0x85, 0x89, 0x0b, 0xa1, 0x98, 0x0c, 0x00, 0xc0, 0x68,
> +0x7b, 0x68, 0x6f, 0x01, 0x85, 0x60, 0x00, 0x10, 0x64, 0x11, 0x81, 0xc8, 0x71,
> +0x54, 0xef, 0x28, 0x45, 0x70, 0xef, 0x09, 0x0e, 0xe8, 0xea, 0x4a, 0x40, 0x90,
> +0xe0, 0x06, 0x00, 0x00, 0xc0, 0xa8, 0x4b, 0x00, 0xc8, 0x09, 0x0e, 0x5c, 0xeb,
> +0x0a, 0x40, 0x80, 0xe0, 0x25, 0xac, 0x19, 0x0c, 0xcc, 0xe5, 0x4a, 0x02, 0xfc,
> +0xfb, 0x85, 0xaa, 0x0a, 0x40, 0x90, 0xe0, 0x45, 0x82, 0x46, 0x00, 0x74, 0xe1,
> +0x04, 0x80, 0x14, 0xc0, 0x14, 0x02, 0x2c, 0xfc, 0x1e, 0xc0, 0x09, 0x0e, 0x5c,
> +0xeb, 0x0a, 0x40, 0x84, 0xe0, 0x25, 0x82, 0xb8, 0x68, 0x30, 0x6f, 0x01, 0x81,
> +0xc8, 0x58, 0x2c, 0x6f, 0x0b, 0x8c, 0x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x94,
> +0xe0, 0x45, 0x82, 0x46, 0x00, 0x74, 0xe1, 0x04, 0x80, 0x14, 0xc0, 0x14, 0x02,
> +0x08, 0xfc, 0x1e, 0xc0, 0x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x98, 0xe0, 0x18,
> +0x49, 0x00, 0xc8, 0x45, 0x91, 0x14, 0x2c, 0x04, 0x00, 0x80, 0xfb, 0x13, 0x20,
> +0x06, 0x41, 0x2c, 0xe0, 0x16, 0x40, 0x02, 0x60, 0x46, 0x42, 0x04, 0xe0, 0xc8,
> +0x7a, 0xf8, 0xee, 0x0e, 0x2c, 0x0e, 0x4c, 0x01, 0x60, 0x10, 0xc0, 0x04, 0xac,
> +0x00, 0x00, 0xd1, 0x6f, 0x0f, 0xc0, 0x0e, 0xac, 0x05, 0x10, 0x40, 0xe0, 0x04,
> +0x00, 0x38, 0xfc, 0x0e, 0x98, 0x05, 0x50, 0x40, 0xe0, 0x04, 0xac, 0xd8, 0x63,
> +0xfc, 0xef, 0x46, 0x10, 0x74, 0xe1, 0x04, 0xa0, 0x15, 0x00, 0x40, 0xe0, 0x14,
> +0x02, 0xb8, 0xfc, 0x1e, 0x98, 0x15, 0x40, 0x40, 0xe0, 0x98, 0x52, 0x30, 0xef,
> +0x0b, 0xa1, 0xa5, 0xfe, 0x34, 0x28, 0xc6, 0x0d, 0x30, 0xe1, 0x08, 0x8c, 0x0b,
> +0xa5, 0x0b, 0x0e, 0x04, 0xd8, 0x1b, 0x0e, 0x00, 0xc0, 0x2b, 0x0e, 0x04, 0xc0,
> +0x3b, 0x0e, 0x08, 0xc0, 0x75, 0x84, 0x08, 0x8e, 0x19, 0x0e, 0x10, 0xeb, 0x12,
> +0x40, 0x80, 0xfb, 0x01, 0x4e, 0x10, 0xf8, 0x0a, 0xcc, 0x03, 0x4e, 0x04, 0xf8,
> +0x1a, 0xce, 0x1c, 0x9c, 0x2b, 0x06, 0x10, 0xe0, 0x2c, 0x9e, 0x3b, 0x06, 0x14,
> +0xe0, 0x3c, 0xdc, 0xa4, 0x8f, 0x03, 0x4e, 0x80, 0xf9, 0x13, 0x4e, 0x7c, 0xf9,
> +0x23, 0x4e, 0x78, 0xf9, 0x33, 0x4e, 0x74, 0xf9, 0xc8, 0x6d, 0x38, 0xef, 0xe8,
> +0x66, 0x3c, 0xef, 0x04, 0x20, 0xa9, 0xc2, 0xa5, 0x40, 0x2c, 0xe0, 0x19, 0x0c,
> +0x40, 0xe6, 0x1b, 0xa1, 0x55, 0x88, 0x14, 0xc0, 0x19, 0xd0, 0x1e, 0xc0, 0x14,
> +0xc0, 0x19, 0xe0, 0x1e, 0xc0, 0x14, 0xc0, 0x19, 0xc4, 0x1e, 0x40, 0x01, 0x83,
> +0xa8, 0x41, 0x00, 0xe8, 0x04, 0xa0, 0x14, 0xc0, 0x14, 0x02, 0xac, 0xfc, 0x1e,
> +0xc0, 0x14, 0xc0, 0x19, 0xc8, 0x1e, 0xc0, 0x48, 0x51, 0x74, 0xef, 0x04, 0x26,
> +0x11, 0x83, 0x11, 0x40, 0x10, 0xe0, 0x04, 0xa4, 0x11, 0x40, 0x20, 0x60, 0x11,
> +0x81, 0x04, 0xa4, 0x11, 0x40, 0xb0, 0xe7, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd,
> +0x1b, 0x00, 0x06, 0x01, 0x38, 0xe1, 0x04, 0x80, 0xc8, 0x20, 0x04, 0x60, 0x01,
> +0xb8, 0xc3, 0xc1, 0x83, 0xc1, 0x13, 0xc3, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04,
> +0x00, 0xfa, 0xe6, 0x41, 0x84, 0x60, 0x8e, 0x42, 0x00, 0x60, 0x10, 0xc0, 0x08,
> +0x80, 0x14, 0x84, 0x0b, 0x21, 0xa6, 0x41, 0x04, 0xe1, 0x1c, 0x80, 0x05, 0x82,
> +0x28, 0x47, 0x64, 0xef, 0x88, 0x7b, 0x28, 0x6f, 0x46, 0x40, 0x04, 0xe0, 0x35,
> +0x81, 0x38, 0x56, 0x40, 0xef, 0xd8, 0x67, 0x64, 0xef, 0x38, 0x63, 0x64, 0xef,
> +0xd8, 0x44, 0x44, 0xef, 0x06, 0x40, 0x94, 0xe0, 0x04, 0x80, 0x09, 0x00, 0x50,
> +0xeb, 0x0a, 0x40, 0x88, 0xe0, 0x76, 0x00, 0xa0, 0xc0, 0x68, 0x4e, 0x50, 0xcf,
> +0xc6, 0x0d, 0x30, 0xe1, 0x09, 0x0c, 0x30, 0xe7, 0x0b, 0xa1, 0x78, 0x6c, 0x70,
> +0xcf, 0x98, 0x7f, 0x6c, 0xef, 0x38, 0x4b, 0x2c, 0x6f, 0x0b, 0x8c, 0xc8, 0x5a,
> +0x30, 0x6f, 0x01, 0x81, 0x58, 0x49, 0x30, 0xef, 0xb8, 0x5f, 0x70, 0xef, 0x01,
> +0x83, 0x01, 0x4c, 0xc0, 0xe5, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1,
> +0x0c, 0x04, 0x84, 0xfa, 0x06, 0x4e, 0x88, 0x60, 0x06, 0x0c, 0x0c, 0xe1, 0x05,
> +0x0e, 0x38, 0x78, 0x06, 0x04, 0x00, 0x70, 0x40, 0xc0, 0x19, 0x0c, 0x94, 0x78,
> +0x06, 0x06, 0x10, 0x60, 0x40, 0xc0, 0x08, 0xc0, 0x4a, 0x02, 0x00, 0xe0, 0x09,
> +0x86, 0x07, 0xc6, 0x2f, 0x61, 0x3f, 0xe1, 0x21, 0x4e, 0x10, 0xf8, 0x0c, 0x00,
> +0x00, 0xe2, 0x31, 0x4e, 0x0c, 0xf8, 0x18, 0x62, 0x30, 0xef, 0x05, 0x0e, 0x38,
> +0xf8, 0x14, 0x98, 0x09, 0x00, 0x24, 0xe0, 0x4a, 0x40, 0x88, 0xe0, 0x65, 0x82,
> +0x0b, 0x0c, 0x28, 0x78, 0x1b, 0xa1, 0x0c, 0xde, 0x05, 0x84, 0x0a, 0x01, 0x20,
> +0xec, 0xf5, 0x84, 0x55, 0x03, 0x01, 0x93, 0x0b, 0x0c, 0x24, 0x78, 0x1b, 0xa1,
> +0x0c, 0xde, 0x65, 0x82, 0x0a, 0x01, 0x24, 0xec, 0xb5, 0x82, 0xb5, 0x01, 0x01,
> +0x95, 0x0a, 0x01, 0x48, 0xec, 0x15, 0x82, 0x65, 0x01, 0x01, 0xa7, 0x0a, 0x01,
> +0x50, 0xec, 0x75, 0x80, 0x01, 0xab, 0x0c, 0xde, 0x15, 0x0c, 0x20, 0x79, 0x06,
> +0x04, 0x00, 0x60, 0x00, 0xf0, 0x49, 0x0c, 0x64, 0x78, 0x06, 0x06, 0x00, 0x60,
> +0x00, 0xe0, 0x2f, 0x82, 0x3b, 0x0c, 0x8c, 0x78, 0x2b, 0x87, 0x30, 0x42, 0x00,
> +0x5c, 0x4a, 0x08, 0x14, 0xfc, 0x14, 0x04, 0x80, 0x7a, 0xce, 0x43, 0x00, 0x60,
> +0x10, 0xc0, 0x2c, 0x04, 0x8e, 0x48, 0x01, 0x60, 0x10, 0xc0, 0x3e, 0x90, 0x85,
> +0x88, 0x45, 0x0e, 0x30, 0xf8, 0x3b, 0x08, 0x18, 0xe0, 0x5b, 0x08, 0x20, 0xe0,
> +0x4b, 0x08, 0x1c, 0xe0, 0x32, 0x4a, 0x94, 0xf1, 0x53, 0x88, 0x8a, 0x0a, 0x89,
> +0x63, 0x05, 0xc0, 0xb5, 0x84, 0x54, 0x1a, 0x8e, 0x59, 0x09, 0x60, 0x10, 0xc0,
> +0x71, 0x83, 0x7e, 0x30, 0x2e, 0x59, 0x09, 0x60, 0x10, 0xc0, 0x5c, 0x30, 0x54,
> +0x08, 0x80, 0xfb, 0x4d, 0x44, 0x4e, 0x45, 0x09, 0x60, 0x10, 0xc0, 0x3e, 0x88,
> +0x43, 0x42, 0x00, 0xc0, 0x65, 0x81, 0x8e, 0x43, 0x09, 0x60, 0x10, 0x40, 0x21,
> +0x81, 0x2e, 0x84, 0x03, 0x4c, 0xd5, 0x79, 0x02, 0x40, 0xd6, 0x41, 0x00, 0xe0,
> +0x0c, 0x0c, 0x84, 0xf2, 0x18, 0x34, 0x48, 0xff, 0xc3, 0xc1, 0x0c, 0x04, 0xfc,
> +0xfa, 0x6b, 0x00, 0x06, 0x41, 0x08, 0xe0, 0x98, 0x73, 0x48, 0xef, 0x0b, 0xa1,
> +0x78, 0x14, 0x00, 0xc0, 0x86, 0x52, 0x84, 0xe0, 0x74, 0xe4, 0x08, 0x9c, 0x09,
> +0x86, 0x0b, 0xa3, 0x36, 0x40, 0x98, 0x40, 0x06, 0x02, 0x00, 0xc0, 0x11, 0x40,
> +0x00, 0xc0, 0xf5, 0x80, 0x21, 0x01, 0x36, 0x40, 0x98, 0xe0, 0x2e, 0x18, 0x11,
> +0x83, 0x16, 0x80, 0x84, 0x26, 0x16, 0x44, 0x98, 0xe0, 0x18, 0x9c, 0x09, 0x10,
> +0xb4, 0xe0, 0x0a, 0x02, 0x0c, 0xfc, 0x0c, 0x02, 0x00, 0xe2, 0x01, 0x4c, 0x10,
> +0xe1, 0x0b, 0x10, 0x80, 0xe0, 0x16, 0x88, 0xe8, 0x75, 0xf8, 0xee, 0x05, 0x4c,
> +0x48, 0xe0, 0x08, 0x9c, 0x00, 0x42, 0x08, 0xfc, 0x19, 0x86, 0x1b, 0xa5, 0xd5,
> +0x80, 0x4a, 0x00, 0x0c, 0xf8, 0x0c, 0x00, 0x00, 0xe2, 0x0e, 0x98, 0x09, 0x10,
> +0xb0, 0xe0, 0x98, 0x51, 0x00, 0x68, 0x09, 0x82, 0x01, 0x4c, 0x18, 0x60, 0x11,
> +0x9f, 0x0b, 0x10, 0x88, 0xe0, 0x78, 0x51, 0x00, 0xe8, 0x14, 0xa6, 0x05, 0x4c,
> +0x4c, 0xe0, 0x0b, 0x02, 0x84, 0x60, 0x11, 0x91, 0xf8, 0x50, 0x00, 0xe8, 0xb4,
> +0xa6, 0x05, 0x4c, 0x50, 0xe0, 0x09, 0x16, 0xd0, 0xe0, 0x0a, 0x40, 0x84, 0x60,
> +0x06, 0x00, 0x00, 0x60, 0x48, 0xd0, 0x56, 0x01, 0x55, 0x15, 0x41, 0xd0, 0x05,
> +0x4c, 0x34, 0xe0, 0x09, 0x16, 0xd0, 0xe0, 0x68, 0x4f, 0x00, 0x68, 0x09, 0x82,
> +0x14, 0x64, 0x06, 0x54, 0xdc, 0xe0, 0x01, 0x4c, 0x10, 0x60, 0xce, 0x41, 0x00,
> +0x60, 0x10, 0xc0, 0x0a, 0x80, 0x2b, 0x02, 0x18, 0xe0, 0x23, 0xa0, 0x23, 0x4c,
> +0x60, 0xe0, 0x09, 0x14, 0x70, 0xea, 0x22, 0x40, 0x80, 0xf1, 0x03, 0x4c, 0x60,
> +0xe0, 0x25, 0x14, 0xe0, 0xe2, 0x2b, 0xa3, 0x35, 0x88, 0x24, 0xa4, 0x3b, 0x02,
> +0x18, 0xe0, 0x4b, 0x02, 0x20, 0xe0, 0x1b, 0x02, 0x1c, 0xe0, 0x59, 0x04, 0x24,
> +0xe0, 0x33, 0xa8, 0x32, 0x44, 0x84, 0x70, 0x2e, 0x47, 0x08, 0x60, 0x10, 0xc0,
> +0x20, 0x02, 0xfc, 0x6c, 0x0a, 0x4a, 0x88, 0xe0, 0x1c, 0x0c, 0x20, 0x02, 0x14,
> +0xcc, 0x10, 0x02, 0xf0, 0xcc, 0x13, 0x46, 0x00, 0x40, 0x0a, 0x41, 0x04, 0xec,
> +0x13, 0x4c, 0x60, 0x40, 0x10, 0x40, 0x00, 0xdc, 0x15, 0x14, 0xdc, 0x62, 0x04,
> +0x00, 0x80, 0xfb, 0x86, 0x05, 0x74, 0xe1, 0x1d, 0xc1, 0x13, 0x4c, 0x60, 0x40,
> +0x14, 0x00, 0x80, 0xdb, 0x14, 0xa4, 0x0e, 0xa8, 0x04, 0x88, 0x7a, 0x84, 0x73,
> +0x4c, 0x64, 0xe0, 0xe8, 0x6d, 0xf8, 0xee, 0x1b, 0x00, 0x8e, 0x40, 0xb1, 0x66,
> +0x9b, 0xd3, 0x08, 0x6d, 0xf8, 0xee, 0x8b, 0x00, 0x0b, 0x8e, 0x85, 0x4c, 0x3c,
> +0xe0, 0x28, 0x6d, 0xf8, 0xee, 0x1b, 0x00, 0x0b, 0x90, 0x28, 0x6d, 0xf8, 0xee,
> +0x48, 0x6c, 0xf8, 0x6e, 0x0e, 0x02, 0x00, 0x60, 0x1e, 0xd1, 0x05, 0x4c, 0x40,
> +0x60, 0x11, 0x91, 0x0b, 0x16, 0x64, 0xe0, 0x7b, 0x16, 0x5c, 0xe0, 0x89, 0x16,
> +0xc0, 0xe0, 0x08, 0x49, 0x00, 0xe8, 0x3b, 0x00, 0x80, 0x44, 0x7c, 0xf0, 0x81,
> +0x01, 0x11, 0x81, 0xb8, 0x40, 0x40, 0x6f, 0x0b, 0x8e, 0x4b, 0x0c, 0x60, 0x60,
> +0x06, 0x0e, 0x00, 0x60, 0xe0, 0xcf, 0x0e, 0x5a, 0x11, 0x81, 0x21, 0x01, 0x06,
> +0x06, 0x01, 0x60, 0xe0, 0xcf, 0xd8, 0x7f, 0x3c, 0x6f, 0x0b, 0x88, 0x14, 0x64,
> +0x86, 0x57, 0x94, 0xe1, 0x05, 0x4c, 0x2c, 0xe0, 0x0a, 0x86, 0x83, 0x4c, 0xe4,
> +0xe0, 0x03, 0x4c, 0xe0, 0xe0, 0x08, 0x86, 0x09, 0xbe, 0x03, 0x4c, 0xe8, 0xe0,
> +0x08, 0x86, 0x09, 0xbe, 0x07, 0xc4, 0x05, 0x00, 0x2c, 0xfc, 0x05, 0x4c, 0x54,
> +0xe0, 0x0a, 0xc4, 0x03, 0x4c, 0xec, 0xe0, 0x0a, 0x44, 0x11, 0x91, 0xe8, 0x45,
> +0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x58, 0xe0, 0x0a, 0x46, 0x11, 0x91, 0x78,
> +0x45, 0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x5c, 0xe0, 0x0b, 0x02, 0x10, 0x60,
> +0x11, 0x91, 0xf8, 0x44, 0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x60, 0xe0, 0x0b,
> +0x02, 0x14, 0x60, 0x11, 0x91, 0x78, 0x44, 0x00, 0xe8, 0x14, 0xa6, 0x05, 0x4c,
> +0x64, 0xe0, 0x85, 0x4c, 0x14, 0xe0, 0x85, 0x4c, 0x18, 0xe0, 0x0b, 0x02, 0x7c,
> +0x60, 0x11, 0x91, 0xb8, 0x43, 0x00, 0xe8, 0x05, 0x4c, 0x10, 0x60, 0x11, 0x91,
> +0x81, 0x4c, 0x14, 0xe0, 0x75, 0x4c, 0x1c, 0xe0, 0x09, 0x14, 0xd0, 0xea, 0x07,
> +0xc4, 0x05, 0x00, 0x2c, 0xfc, 0x05, 0x4c, 0x20, 0xe0, 0x0b, 0x14, 0x94, 0xe5,
> +0x98, 0x42, 0x00, 0xe8, 0x05, 0x4c, 0x38, 0x60, 0x11, 0x91, 0x0b, 0x14, 0x64,
> +0xe5, 0x28, 0x42, 0x00, 0xe8, 0x05, 0x4c, 0x28, 0x60, 0x11, 0x81, 0x09, 0x14,
> +0x8c, 0x6a, 0x21, 0x81, 0x0b, 0x12, 0x7c, 0x60, 0x0a, 0x40, 0x88, 0xe0, 0xd6,
> +0x0e, 0xcd, 0x0c, 0x73, 0xcf, 0x75, 0x4c, 0x24, 0x60, 0x3b, 0x8e, 0x28, 0x79,
> +0x3c, 0xef, 0x0e, 0xd8, 0x16, 0x41, 0x08, 0xe0, 0x0c, 0x0c, 0xfc, 0xf2, 0xb8,
> +0x1e, 0x48, 0xff, 0xc3, 0xc1, 0x4a, 0x00, 0x00, 0xe0, 0x0c, 0x00, 0x00, 0xe2,
> +0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x00, 0x00, 0xfa, 0x88, 0x61, 0x28, 0xef, 0x4c,
> +0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x88, 0x5d,
> +0x48, 0x6f, 0xf6, 0x40, 0x04, 0xe0, 0x0b, 0xa1, 0x85, 0x80, 0x0c, 0x0c, 0x00,
> +0xf2, 0x93, 0xdd, 0xb8, 0x6b, 0x54, 0xef, 0xc6, 0x4c, 0x84, 0xe0, 0x04, 0x98,
> +0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, 0x85, 0x88, 0xc6, 0x40, 0xb4,
> +0x60, 0x46, 0x45, 0x00, 0xe0, 0x19, 0x00, 0xb4, 0xe4, 0x16, 0x42, 0x0a, 0xe0,
> +0x03, 0x82, 0x09, 0x00, 0x40, 0xe2, 0x0b, 0xa5, 0xf5, 0x84, 0x48, 0x56, 0x40,
> +0x6f, 0x01, 0x85, 0x58, 0x4c, 0x40, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0xd8, 0x7d,
> +0x44, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0x58, 0x50, 0x40, 0xef, 0x18, 0x70, 0xf4,
> +0xef, 0x4e, 0x40, 0x01, 0x60, 0x10, 0xc0, 0x08, 0x80, 0x0b, 0xa1, 0x08, 0x70,
> +0xf4, 0xcf, 0x09, 0x0c, 0x48, 0xe0, 0x0b, 0xa1, 0x95, 0x84, 0xe8, 0x70, 0x38,
> +0xef, 0x06, 0x40, 0x94, 0x60, 0x16, 0x07, 0x04, 0xe1, 0x04, 0x80, 0x1b, 0x00,
> +0x18, 0xe1, 0x2b, 0x00, 0x50, 0xe1, 0x48, 0x8c, 0x39, 0x06, 0xac, 0xe0, 0x13,
> +0xa4, 0x13, 0xa8, 0x13, 0xa6, 0x15, 0x40, 0x2c, 0xe0, 0xc6, 0x00, 0x2c, 0x61,
> +0x11, 0xa1, 0x04, 0x80, 0x13, 0x40, 0xd0, 0x65, 0xe6, 0x40, 0xe0, 0xe0, 0x0a,
> +0x00, 0x06, 0x42, 0x94, 0xe0, 0x14, 0x84, 0x03, 0x42, 0x10, 0x62, 0x06, 0x41,
> +0x04, 0xe0, 0x0c, 0x0c, 0x00, 0xf2, 0x98, 0x17, 0x48, 0xff, 0xc3, 0xc1, 0x66,
> +0x01, 0xcc, 0xe0, 0x18, 0x80, 0x0a, 0x42, 0x84, 0xe0, 0x10, 0x42, 0xf8, 0xd3,
> +0x11, 0x40, 0x00, 0xc0, 0x93, 0xdd, 0x4a, 0x40, 0x80, 0xe0, 0x55, 0x84, 0x14,
> +0x04, 0xa0, 0x60, 0x0e, 0x06, 0x00, 0x70, 0x3f, 0xc0, 0x2f, 0x06, 0x14, 0x06,
> +0xa0, 0xe1, 0x14, 0x00, 0xe0, 0x61, 0x30, 0x46, 0x00, 0x70, 0xff, 0xc0, 0x17,
> +0x70, 0x3f, 0xa0, 0x1f, 0xa4, 0x1f, 0xa6, 0x93, 0x5d, 0x0b, 0x82, 0x4c, 0x04,
> +0x04, 0xfa, 0x86, 0x0d, 0xcc, 0x60, 0x71, 0x81, 0x7c, 0x98, 0x88, 0x55, 0x68,
> +0xef, 0x0a, 0x98, 0x00, 0x42, 0xf1, 0x73, 0xff, 0xc0, 0x19, 0xc2, 0x1c, 0x18,
> +0x60, 0x02, 0xe1, 0x65, 0x02, 0xc0, 0x65, 0x81, 0x24, 0x84, 0x2b, 0xa1, 0xf5,
> +0x80, 0x71, 0x02, 0x11, 0x88, 0x0a, 0x0e, 0x00, 0xe1, 0x35, 0xfe, 0x75, 0x81,
> +0x77, 0x50, 0x00, 0x40, 0xf0, 0xf3, 0x0f, 0xae, 0x09, 0xc4, 0x0c, 0x98, 0x4c,
> +0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x4c, 0x04, 0x7c, 0xfa, 0xbb, 0x06, 0x6b, 0x82,
> +0x14, 0x2c, 0x9b, 0x80, 0x74, 0x24, 0xab, 0x84, 0xa4, 0x00, 0xa0, 0x61, 0x8b,
> +0x88, 0x1b, 0x81, 0x65, 0x82, 0x0e, 0x2c, 0x0b, 0x8e, 0x78, 0x56, 0x30, 0x6f,
> +0x1b, 0x8c, 0x24, 0x2c, 0x0b, 0x8e, 0x28, 0x59, 0x30, 0x6f, 0x1b, 0x8c, 0x04,
> +0x18, 0xb1, 0x83, 0x11, 0x01, 0x21, 0x83, 0x38, 0x44, 0x00, 0x68, 0x31, 0x85,
> +0xa4, 0x02, 0x80, 0x7a, 0x21, 0x8b, 0xd8, 0x43, 0x00, 0x68, 0x06, 0x46, 0xfc,
> +0xe1, 0xab, 0x00, 0x0b, 0x8e, 0x78, 0x40, 0xf8, 0x6f, 0x1b, 0x94, 0x09, 0x12,
> +0x10, 0x60, 0x1b, 0x90, 0x98, 0x79, 0xfc, 0x6f, 0x70, 0x12, 0x10, 0xe4, 0x1b,
> +0x00, 0x0b, 0x92, 0xb8, 0x7f, 0xf4, 0xef, 0x11, 0x03, 0x21, 0x85, 0x31, 0x09,
> +0x0b, 0x94, 0x58, 0x42, 0x00, 0xe8, 0x8b, 0x00, 0x0b, 0x8e, 0x18, 0x7f, 0xf4,
> +0x6f, 0x1b, 0x90, 0x70, 0x12, 0x50, 0x64, 0x36, 0x54, 0x48, 0xe1, 0x08, 0x42,
> +0x00, 0x68, 0x0b, 0x92, 0x0a, 0x00, 0x00, 0xfb, 0xb1, 0x54, 0x00, 0x40, 0x0a,
> +0x40, 0xa0, 0xe0, 0xe5, 0xfc, 0x11, 0x01, 0x21, 0x85, 0x31, 0x09, 0x0b, 0x90,
> +0xc8, 0x40, 0x00, 0xe8, 0x8b, 0x00, 0x0b, 0x8e, 0x88, 0x7d, 0xf4, 0x6f, 0x1b,
> +0x90, 0x8e, 0x98, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x1f, 0x25,
> +0x32, 0x40, 0x80, 0xf8, 0x1f, 0x86, 0x93, 0x5d, 0x0f, 0xa2, 0x04, 0x80, 0x93,
> +0xdd, 0x0c, 0x00, 0x80, 0xfa, 0xa8, 0x4c, 0x48, 0x6f, 0xe6, 0x40, 0x08, 0xe0,
> +0x0b, 0xa1, 0x95, 0x84, 0xc8, 0x46, 0x40, 0xef, 0x86, 0x02, 0x84, 0x60, 0xc6,
> +0x04, 0x84, 0xe0, 0x14, 0x04, 0x5a, 0x00, 0x08, 0xe0, 0x24, 0x88, 0x4a, 0x42,
> +0x08, 0x60, 0x46, 0x02, 0x84, 0xe0, 0x0a, 0x42, 0x80, 0xe1, 0x0c, 0x00, 0x00,
> +0xe2, 0x06, 0x84, 0xf6, 0x40, 0x08, 0xe0, 0x0c, 0x08, 0x80, 0xf2, 0xd8, 0x0a,
> +0x48, 0xff, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0xf0, 0x1e, 0x60, 0x6c, 0xa6,
> +0x01, 0x04, 0xe0, 0x48, 0x4a, 0x48, 0xef, 0x0b, 0xa1, 0x15, 0x90, 0xc8, 0x5d,
> +0x2c, 0xef, 0xe8, 0x7a, 0xf4, 0x6e, 0x0e, 0x02, 0x24, 0x74, 0x03, 0xc0, 0x86,
> +0x50, 0x84, 0xe0, 0x69, 0x10, 0x44, 0xe0, 0x58, 0x7a, 0xf4, 0x6e, 0x1b, 0x8c,
> +0x04, 0x60, 0x7b, 0x80, 0x1b, 0x00, 0x28, 0xe0, 0x0b, 0x00, 0x24, 0xe0, 0x13,
> +0xa0, 0x10, 0x00, 0x04, 0x64, 0x1b, 0x8c, 0x88, 0x79, 0xf4, 0xee, 0x14, 0xa0,
> +0x19, 0x02, 0x28, 0xe0, 0x19, 0xbe, 0x06, 0x44, 0x06, 0x60, 0x06, 0x41, 0xdc,
> +0xe0, 0x04, 0x00, 0x16, 0x42, 0x1e, 0xe0, 0x21, 0xbe, 0x1e, 0x7c, 0x27, 0xcb,
> +0x2c, 0x7c, 0x0e, 0x02, 0x25, 0x74, 0x03, 0xc0, 0x48, 0x78, 0xf4, 0xee, 0x0e,
> +0x7e, 0x11, 0x81, 0x1e, 0x09, 0xf0, 0x00, 0x10, 0xe4, 0x1c, 0x95, 0x88, 0x7e,
> +0x1c, 0xef, 0x0a, 0x95, 0x18, 0x41, 0x00, 0x68, 0x01, 0xa0, 0x06, 0x00, 0x38,
> +0x61, 0x11, 0x83, 0x78, 0x7c, 0x1c, 0xef, 0x18, 0x46, 0x48, 0x6f, 0xb6, 0x01,
> +0x04, 0xe0, 0xf1, 0xb0, 0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x1b,
> +0x00, 0x06, 0x00, 0x38, 0xe1, 0x04, 0x80, 0x08, 0x35, 0xf4, 0x7f, 0x01, 0xc8,
> +0xc3, 0xc1, 0x0c, 0x04, 0x3c, 0xfa, 0x86, 0x4e, 0x84, 0x60, 0xf0, 0x1e, 0x20,
> +0xee, 0x84, 0x9c, 0x19, 0x0e, 0x48, 0xe0, 0x0a, 0xe2, 0x2a, 0xe0, 0x03, 0xa4,
> +0x01, 0x82, 0x38, 0x75, 0xf4, 0x6e, 0x04, 0x00, 0x80, 0xfb, 0x0b, 0x10, 0x64,
> +0x60, 0x6b, 0x80, 0x0b, 0xa1, 0x05, 0x0e, 0x04, 0xc0, 0x99, 0x00, 0xa0, 0xc0,
> +0xd5, 0x84, 0x09, 0x10, 0x24, 0x60, 0x06, 0x03, 0xd0, 0xe0, 0x1a, 0x84, 0x07,
> +0xc5, 0x09, 0x82, 0x1f, 0x21, 0x06, 0x00, 0x04, 0xe0, 0x10, 0x42, 0x01, 0x70,
> +0xff, 0xc0, 0x17, 0xd1, 0x1b, 0xa1, 0x78, 0x73, 0xf4, 0x6e, 0x16, 0x02, 0x00,
> +0x80, 0x00, 0x12, 0x04, 0xec, 0x18, 0x42, 0x48, 0x6f, 0x36, 0x01, 0x04, 0xe0,
> +0x0b, 0xa1, 0xb5, 0xb0, 0x04, 0x1c, 0x06, 0x11, 0xd0, 0xe0, 0x19, 0x10, 0x24,
> +0x6e, 0x46, 0x05, 0xb8, 0xe0, 0xa4, 0x9e, 0x09, 0x00, 0xb0, 0xe0, 0x18, 0x08,
> +0x5a, 0x02, 0x00, 0xe0, 0x1c, 0x06, 0x00, 0xe2, 0x36, 0x3e, 0x09, 0x86, 0x0b,
> +0x21, 0x19, 0x82, 0x0c, 0x04, 0x00, 0x62, 0x0b, 0xa5, 0x16, 0x7c, 0x64, 0x02,
> +0x80, 0xfb, 0x26, 0x3c, 0x6b, 0x9e, 0x1e, 0xbe, 0x19, 0x0e, 0x60, 0xe0, 0x2b,
> +0x10, 0x30, 0xf8, 0x0c, 0x00, 0x00, 0xe2, 0x16, 0x1b, 0x11, 0x81, 0x06, 0x7e,
> +0x2b, 0xa3, 0x19, 0x14, 0x5c, 0xc0, 0x09, 0x0e, 0x80, 0xe0, 0x25, 0x10, 0xa4,
> +0xe3, 0x35, 0x10, 0xa8, 0x63, 0x10, 0x42, 0x3c, 0xd0, 0x0c, 0x0b, 0x01, 0x81,
> +0x16, 0x1d, 0x11, 0x81, 0x26, 0x1f, 0x46, 0x05, 0x04, 0xe0, 0x0c, 0x89, 0x06,
> +0x99, 0x06, 0xa5, 0x0c, 0x91, 0x3e, 0x8b, 0x0e, 0x91, 0x0e, 0x8f, 0x0e, 0x0d,
> +0x60, 0x00, 0xa0, 0xe4, 0x91, 0x5e, 0x90, 0xe0, 0xc8, 0x7a, 0xf4, 0xee, 0x09,
> +0x14, 0x58, 0xe0, 0x19, 0x10, 0xf0, 0xf8, 0x0e, 0x3f, 0xfe, 0x41, 0x3d, 0x70,
> +0xff, 0xc0, 0x1b, 0x25, 0xf6, 0x43, 0x3c, 0xe0, 0x05, 0x5e, 0x80, 0x60, 0x16,
> +0x00, 0x00, 0x80, 0x15, 0x5e, 0x84, 0xe0, 0x01, 0x5e, 0x34, 0x80, 0x05, 0x14,
> +0x18, 0xe0, 0x38, 0x47, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, 0x2a,
> +0x20, 0x11, 0x91, 0x0e, 0x97, 0x78, 0x5d, 0xfc, 0x6f, 0x0b, 0x84, 0x19, 0x10,
> +0xc0, 0xe9, 0x0e, 0xb7, 0x4a, 0x42, 0x80, 0xe0, 0xc5, 0x82, 0x60, 0x00, 0xc0,
> +0x65, 0x11, 0xfb, 0x75, 0x81, 0x24, 0x37, 0x11, 0x82, 0x2e, 0xc1, 0x24, 0x97,
> +0x25, 0x40, 0x44, 0xf8, 0x1b, 0xa1, 0x35, 0xfe, 0xe5, 0x85, 0x04, 0x9e, 0x05,
> +0x00, 0x1c, 0xe0, 0x28, 0x45, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7,
> +0x14, 0x9e, 0x0e, 0x99, 0x05, 0x02, 0x20, 0xe0, 0x98, 0x44, 0x00, 0x68, 0x00,
> +0x40, 0xfc, 0x73, 0xff, 0xc7, 0x14, 0x9e, 0x0e, 0x9b, 0x05, 0x02, 0x24, 0xe0,
> +0x08, 0x44, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, 0x2a, 0x22, 0x11,
> +0x91, 0x0e, 0x9d, 0x48, 0x5a, 0xfc, 0x6f, 0x0b, 0x84, 0x2a, 0x60, 0x11, 0x91,
> +0x0e, 0xb9, 0xe8, 0x59, 0xfc, 0x6f, 0x0b, 0x84, 0x2a, 0x62, 0x11, 0x91, 0x0e,
> +0xbb, 0x88, 0x59, 0xfc, 0x6f, 0x0b, 0x84, 0x0e, 0xbd, 0x04, 0x9c, 0x09, 0x00,
> +0x24, 0xe0, 0x0a, 0x40, 0x88, 0xe0, 0xa5, 0x84, 0x04, 0xb7, 0xf8, 0x7a, 0xf4,
> +0x6e, 0x1b, 0x80, 0x14, 0xb9, 0x0e, 0xb7, 0xa8, 0x7a, 0xf4, 0x6e, 0x0b, 0x82,
> +0x14, 0xbb, 0x0e, 0xb9, 0x58, 0x7a, 0xf4, 0x6e, 0x0b, 0x82, 0x14, 0xbd, 0x0e,
> +0xbb, 0x08, 0x7a, 0xf4, 0x6e, 0x0b, 0x82, 0x0e, 0xbd, 0x86, 0x41, 0x30, 0x61,
> +0x1b, 0x9e, 0xd8, 0x4c, 0x08, 0xef, 0x78, 0x75, 0x44, 0x6f, 0x46, 0x01, 0x04,
> +0xe0, 0xf0, 0x1e, 0x20, 0xe6, 0x0c, 0x0c, 0x3c, 0xf2, 0x93, 0xdd, 0x4c, 0x00,
> +0x00, 0xfa, 0x08, 0x74, 0x24, 0x6f, 0x11, 0x8f, 0x4c, 0x08, 0x00, 0xf2, 0x93,
> +0xdd, 0x0c, 0x04, 0x7c, 0xfe, 0x6b, 0x04, 0xf0, 0x1e, 0x60, 0xec, 0xb5, 0x0c,
> +0x10, 0xe0, 0x85, 0x0c, 0x18, 0xe0, 0x79, 0x0c, 0x24, 0xe0, 0xa4, 0xda, 0x1e,
> +0x0b, 0x11, 0x81, 0x0e, 0x7e, 0x0b, 0x96, 0x68, 0x79, 0xf4, 0xee, 0x0b, 0xa1,
> +0x15, 0x82, 0x14, 0x18, 0x0b, 0x96, 0x88, 0x79, 0xf4, 0xee, 0x0b, 0xa1, 0xb5,
> +0x4c, 0x00, 0xc0, 0x11, 0x01, 0x0b, 0x94, 0x98, 0x78, 0xf4, 0xee, 0x94, 0x18,
> +0x0b, 0xa1, 0x05, 0x1e, 0x14, 0xc0, 0xbe, 0xbe, 0x75, 0x82, 0x0b, 0x14, 0x1b,
> +0x92, 0xf8, 0x78, 0xf4, 0xee, 0x04, 0x0b, 0x0b, 0xa1, 0xa5, 0x4c, 0x00, 0x40,
> +0xa0, 0x52, 0x00, 0xdc, 0xae, 0x7c, 0xab, 0x80, 0x77, 0x42, 0x0b, 0x92, 0x15,
> +0x14, 0x1c, 0xfe, 0x58, 0x75, 0xf4, 0xee, 0x0b, 0x14, 0x44, 0x60, 0x9b, 0x80,
> +0x88, 0x75, 0xf4, 0xee, 0xbb, 0x00, 0x0b, 0x92, 0x08, 0x77, 0xf4, 0x6e, 0x1b,
> +0x96, 0x0b, 0xa1, 0x90, 0x56, 0x00, 0x1c, 0xa0, 0x12, 0x88, 0xe4, 0xc8, 0x75,
> +0xf4, 0x6e, 0x0b, 0x96, 0xab, 0x00, 0x01, 0x81, 0x01, 0x4c, 0x20, 0x60, 0x8b,
> +0xa1, 0x04, 0x7e, 0x76, 0x03, 0x71, 0x7b, 0x34, 0xce, 0xac, 0xd8, 0x03, 0x8e,
> +0x00, 0x00, 0x70, 0xe7, 0x0e, 0x89, 0x65, 0x88, 0x8b, 0xa3, 0x35, 0x08, 0x06,
> +0x02, 0x01, 0x00, 0xc0, 0xcf, 0x58, 0x74, 0xf4, 0x6e, 0x0b, 0x96, 0x28, 0x73,
> +0xf4, 0x6e, 0x8b, 0x80, 0x1b, 0x00, 0x0b, 0x96, 0x58, 0x73, 0xf4, 0xee, 0xd8,
> +0x49, 0x00, 0xe8, 0x18, 0x74, 0xf4, 0x6e, 0x76, 0x03, 0x70, 0x7b, 0x34, 0xce,
> +0x0b, 0xa1, 0x25, 0x84, 0x11, 0x01, 0x0b, 0x96, 0x48, 0x74, 0xf4, 0xee, 0x0b,
> +0xa1, 0x80, 0x14, 0x04, 0x04, 0x80, 0x54, 0x00, 0xdc, 0x75, 0x81, 0xc8, 0x70,
> +0xf4, 0x6e, 0x0b, 0x96, 0x58, 0x72, 0xf4, 0xee, 0xab, 0x80, 0xac, 0xd8, 0x0a,
> +0xa4, 0x08, 0x71, 0xf4, 0xee, 0x04, 0x0b, 0x9b, 0x80, 0x73, 0x80, 0x0b, 0x0e,
> +0x40, 0xe0, 0x98, 0x70, 0xf4, 0xee, 0xbb, 0x00, 0xa4, 0x00, 0x80, 0xfb, 0x48,
> +0x70, 0xf4, 0xee, 0x1b, 0x00, 0x0b, 0x96, 0x68, 0x49, 0x00, 0xe8, 0x1b, 0x00,
> +0x0b, 0x92, 0xc8, 0x47, 0x00, 0xe8, 0xa8, 0x70, 0xf4, 0xee, 0x04, 0x09, 0xab,
> +0x80, 0xac, 0xd8, 0x9a, 0x80, 0x9c, 0xda, 0x0b, 0x0e, 0x4c, 0xe0, 0x18, 0x6f,
> +0xf4, 0xee, 0x0b, 0x0e, 0x48, 0x60, 0xbb, 0x80, 0xc8, 0x6e, 0xf4, 0xee, 0x8b,
> +0x00, 0x0b, 0x92, 0x88, 0x6e, 0xf4, 0xee, 0x1b, 0x00, 0x0b, 0x90, 0xa8, 0x47,
> +0x00, 0xe8, 0x1b, 0x00, 0x0b, 0x96, 0x08, 0x46, 0x00, 0xe8, 0xe8, 0x6e, 0xf4,
> +0xee, 0xb4, 0x3e, 0x9b, 0x80, 0x84, 0xfc, 0x9c, 0xda, 0x1b, 0x96, 0xf8, 0x6d,
> +0xf4, 0x6e, 0x0b, 0x90, 0x68, 0x44, 0x00, 0xe8, 0xe8, 0x6e, 0xf4, 0x6e, 0x11,
> +0x81, 0x0b, 0xa1, 0x85, 0x8e, 0x11, 0x01, 0x0b, 0x96, 0xf8, 0x6d, 0xf4, 0xee,
> +0x2a, 0x00, 0x00, 0x60, 0x0b, 0x94, 0x24, 0x7e, 0x1b, 0x92, 0x34, 0x8b, 0xf8,
> +0x74, 0x18, 0xef, 0x58, 0x01, 0x01, 0x40, 0x00, 0x40, 0x9b, 0x80, 0x0b, 0x16,
> +0x1b, 0x92, 0x78, 0x6d, 0xf4, 0xee, 0x0b, 0xa1, 0x85, 0x82, 0x1a, 0xd8, 0x09,
> +0x0c, 0x20, 0xe0, 0x11, 0x82, 0x04, 0x09, 0x0b, 0xa1, 0x1c, 0x58, 0x70, 0x00,
> +0x90, 0xc4, 0x0a, 0x80, 0x0c, 0xda, 0x11, 0x01, 0x0b, 0x90, 0xe8, 0x6b, 0xf4,
> +0xee, 0x0b, 0xa1, 0xb5, 0x84, 0x0b, 0x10, 0x1b, 0x92, 0x88, 0x6c, 0xf4, 0xee,
> +0x0b, 0xa1, 0xe5, 0x82, 0x09, 0x0c, 0x20, 0xe0, 0x1a, 0xd8, 0x0b, 0xa1, 0x70,
> +0x0e, 0x98, 0x44, 0x10, 0x00, 0x04, 0xec, 0x75, 0x5e, 0x10, 0xc0, 0x0c, 0xd8,
> +0x04, 0x89, 0x0a, 0x80, 0x0c, 0xda, 0xf1, 0xb0, 0x0c, 0x0c, 0x7c, 0xf6, 0x93,
> +0xdd, 0x0c, 0x04, 0x00, 0xfa, 0x6b, 0x00, 0x11, 0x81, 0xe8, 0x6a, 0xf4, 0xee,
> +0x0b, 0xa1, 0x64, 0x0c, 0x7c, 0xdd, 0x0b, 0x8c, 0x0c, 0x0c, 0x00, 0xf2, 0x93,
> +0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0x6b, 0x02, 0x7b, 0x80, 0x08, 0x6a,
> +0xf4, 0xee, 0x8b, 0x00, 0x0b, 0x8e, 0x48, 0x69, 0xf4, 0x6e, 0x1b, 0x8c, 0x0b,
> +0xa1, 0x70, 0x4c, 0x00, 0x1c, 0x8b, 0xa1, 0x70, 0x4c, 0x00, 0xdc, 0x0b, 0x8c,
> +0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0x6b,
> +0x02, 0x7b, 0x80, 0xa8, 0x68, 0xf4, 0xee, 0x0b, 0xa1, 0x70, 0x4c, 0x00, 0x9c,
> +0x0b, 0x8c, 0x4c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00,
> +0xfa, 0x6b, 0x00, 0x21, 0x81, 0x04, 0x18, 0x31, 0x83, 0x68, 0x53, 0xfc, 0xef,
> +0x0e, 0x98, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0x18, 0xa9, 0x00, 0x00, 0x38,
> +0x90, 0x40, 0x00, 0x08, 0x14, 0xb8, 0xe0, 0x80, 0x2c, 0x40, 0x00, 0xa8, 0x3a,
> +0xe8, 0xe0, 0x08, 0x9f, 0x40, 0x00, 0x28, 0x28, 0xb0, 0xe0, 0x18, 0x72, 0x40,
> +0x00, 0x88, 0x19, 0xc8, 0xe0, 0xe0, 0xbb, 0x40, 0x00, 0x08, 0x0c, 0xa4, 0xe0,
> +0xa8, 0xe3, 0x40, 0x00, 0x28, 0x13, 0x90, 0xe0, 0xf0, 0xec, 0x40, 0x00, 0x68,
> +0x0d, 0x8c, 0xe0, 0x48, 0xa8, 0x40, 0x00, 0xa8, 0x3c, 0xac, 0xe0, 0x28, 0xe4,
> +0x40, 0x00, 0x08, 0x0e, 0x94, 0xe0, 0xb8, 0xe2, 0x40, 0x00, 0x28, 0x3d, 0x90,
> +0xe0, 0x90, 0xa7, 0x40, 0x00, 0xc8, 0x13, 0xb0, 0xe0, 0x18, 0xc1, 0x40, 0x00,
> +0xa8, 0x2a, 0xa4, 0xe0, 0xa8, 0x91, 0x40, 0x00, 0x68, 0x2f, 0xbc, 0xe0, 0x88,
> +0xf1, 0x40, 0x00, 0x08, 0x1c, 0x88, 0xe0, 0xd0, 0x8e, 0x40, 0x00, 0xa8, 0x19,
> +0xb8, 0xe0, 0x38, 0x82, 0x40, 0x00, 0x28, 0x38, 0xbc, 0xe0, 0x88, 0xe0, 0x40,
> +0x00, 0xa8, 0x0e, 0x98, 0xe0, 0xd8, 0xe4, 0x40, 0x00, 0x68, 0x32, 0x94, 0xe0,
> +0x18, 0xd7, 0x40, 0x00, 0x28, 0x2d, 0x9c, 0xe0, 0x40, 0xe8, 0x40, 0x00, 0x28,
> +0x19, 0x94, 0xe0, 0xa8, 0x78, 0x40, 0x00, 0x28, 0x18, 0xcc, 0xe0, 0xf0, 0x95,
> +0x40, 0x00, 0x48, 0x34, 0xbc, 0xe0, 0xa8, 0xd2, 0x40, 0x00, 0x48, 0x16, 0xa0,
> +0xe0, 0x18, 0x52, 0x40, 0x00, 0x68, 0x2b, 0xe0, 0xe0, 0x00, 0xb9, 0x00, 0x00,
> +0x23, 0xdb, 0x00, 0x00
> +};
> +
> +static const u8 cut2_patch[] = {
> +0x37, 0x00, 0x05, 0x00, 0x0c, 0x04, 0x3c, 0xfa, 0x86, 0x0e, 0x84, 0x60, 0x06,
> +0x11, 0x84, 0xe0, 0x04, 0x1c, 0x06, 0x13, 0x88, 0xe1, 0x14, 0xa0, 0x0d, 0xc2,
> +0x95, 0x80, 0x04, 0xa4, 0x0b, 0xa3, 0xb5, 0x88, 0x78, 0x6c, 0x40, 0xef, 0x6b,
> +0x00, 0x46, 0x01, 0x84, 0xe0, 0x88, 0x53, 0x48, 0x6f, 0x46, 0x15, 0x84, 0xe0,
> +0x6b, 0x25, 0xc6, 0x0d, 0x84, 0xe0, 0x95, 0x84, 0x08, 0xa8, 0x4a, 0x00, 0xfc,
> +0xfb, 0x05, 0x84, 0x09, 0x12, 0x1c, 0xe0, 0xa8, 0x46, 0x48, 0xef, 0x04, 0x1c,
> +0x11, 0x83, 0x16, 0x18, 0xc6, 0x04, 0x84, 0xe0, 0x0e, 0x08, 0x01, 0x87, 0xf8,
> +0x6a, 0x40, 0xef, 0x46, 0x0c, 0x84, 0xe0, 0x04, 0x1c, 0x11, 0x81, 0x16, 0x98,
> +0x0e, 0xa0, 0x06, 0x41, 0x84, 0x60, 0xc6, 0x02, 0xd8, 0xe0, 0x04, 0x80, 0x08,
> +0x80, 0x06, 0x84, 0x0c, 0x0c, 0x3c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x00,
> +0x80, 0xfa, 0xc6, 0x40, 0x84, 0x60, 0x86, 0x43, 0xd8, 0xe0, 0x04, 0x80, 0x09,
> +0x00, 0x18, 0xe1, 0x06, 0x84, 0x88, 0x41, 0x68, 0xef, 0x0c, 0x08, 0x80, 0xf2,
> +0x48, 0x20, 0x68, 0xff, 0x1e, 0xc0, 0xb5, 0x00, 0x2c, 0xe0, 0xb4, 0x02, 0x00,
> +0xfc, 0x15, 0x40, 0x2c, 0xe0, 0x19, 0x10, 0x31, 0x78, 0x01, 0x40, 0x86, 0x04,
> +0x0c, 0xe0, 0x4a, 0x04, 0x00, 0x64, 0x31, 0x81, 0x30, 0x0a, 0x04, 0x64, 0x4b,
> +0x82, 0x1b, 0x06, 0x3b, 0x8a, 0xc8, 0x44, 0xfc, 0x87, 0x41, 0x50, 0x31, 0x78,
> +0x01, 0x40, 0xa1, 0xe1, 0xe6, 0x43, 0x99, 0x6c, 0x10, 0xc0, 0x08, 0x42, 0x00,
> +0xf8, 0x00, 0x00, 0x03, 0xa9, 0x00, 0x00, 0x30, 0x85, 0x40, 0x00, 0xa8, 0x16,
> +0xbc, 0xe0, 0xcc, 0xc1, 0x40, 0x00, 0xa8, 0x35, 0x9c, 0xe0, 0xb0, 0xc9, 0x40,
> +0x00, 0x88, 0x37, 0x98, 0xe0, 0x00, 0xb9, 0x00, 0x00, 0x49, 0xa7, 0x00, 0x00,
> +};
> +
> +struct vd55g0_patch {
> +	const u8 *bin;
> +	const uint size;
> +	const u16 major;
> +	const u16 minor;
> +};
> +
> +static const struct vd55g0_patch vd55g0_patch_cut1 = {
> +	.bin = cut1_patch,
> +	.size = ARRAY_SIZE(cut1_patch),
> +	.major = 2,
> +	.minor = 11,
> +};
> +
> +static const struct vd55g0_patch vd55g0_patch_cut2 = {
> +	.bin = cut2_patch,
> +	.size = ARRAY_SIZE(cut2_patch),
> +	.major = 0,
> +	.minor = 5,
> +};
> +
> +static const char * const vd55g0_test_pattern_menu[] = {
> +	"Disabled",
> +	"Solid",
> +	"Colorbar",
> +	"Gradbar",
> +	"Hgrey",
> +	"Vgrey",
> +	"Dgrey",
> +	"PN28",
> +};
> +
> +static const s64 vd55g0_ev_bias_menu[] = {
> +	-3000, -2500, -2000, -1500, -1000, -500,
> +	    0,
> +	  500,  1000,  1500,  2000,  2500, 3000,

Is this 

> +};
> +
> +/*
> + * On ACPI, the INT3472 registers the rails the platform wired under its own
> + * names; the DT names would get dummy regulators there.
> + */
> +static const char * const vd55g0_dt_supply_name[] = {
> +	"vcore",
> +	"vddio",
> +	"vana",
> +};
> +
> +static const char * const vd55g0_acpi_supply_name[] = {
> +	"avdd",
> +	"dovdd",
> +};
> +
> +static const struct acpi_device_id vd55g0_acpi_ids[] = {
> +	{ "SMO55F0" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(acpi, vd55g0_acpi_ids);

How did this find its place here?

> +
> +#define VD55G0_NUM_SUPPLIES	ARRAY_SIZE(vd55g0_dt_supply_name)

Just use plain ARRAY_SIZE() where you need it.

> +
> +enum vd55g0_bin_mode {
> +	VD55G0_BIN_MODE_NORMAL,
> +	VD55G0_BIN_MODE_DIGITAL_X2,
> +};
> +
> +enum vd55g0_gpio_modes {
> +	VD55G0_GPIO_MODE_DISABLED,
> +	VD55G0_GPIO_MODE_STROBE,
> +};
> +
> +struct vd55g0_mode_info {
> +	u32 width;
> +	u32 height;
> +	enum vd55g0_bin_mode bin_mode;
> +	struct v4l2_rect crop;
> +};
> +
> +struct vd55g0_fmt_desc {
> +	u32 code;
> +	u8 bpp;
> +	u8 data_type;
> +};
> +
> +static const struct vd55g0_fmt_desc vd55g0_supported_codes[] = {
> +	{
> +		.code = MEDIA_BUS_FMT_Y8_1X8,
> +		.bpp = 8,
> +		.data_type = MIPI_CSI2_DT_RAW8,
> +	},
> +	{
> +		.code = MEDIA_BUS_FMT_Y10_1X10,
> +		.bpp = 10,
> +		.data_type = MIPI_CSI2_DT_RAW10,
> +	},
> +};
> +
> +static const struct vd55g0_mode_info vd55g0_mode_data[] = {
> +	{
> +		.width = VD55G0_WIDTH,
> +		.height = VD55G0_HEIGHT,
> +		.bin_mode = VD55G0_BIN_MODE_NORMAL,
> +		.crop = {
> +			.left = 0,
> +			.top = 0,
> +			.width = VD55G0_WIDTH,
> +			.height = VD55G0_HEIGHT,
> +		},
> +	},
> +	{
> +		.width = 640,
> +		.height = 600,
> +		.bin_mode = VD55G0_BIN_MODE_NORMAL,
> +		.crop = {
> +			.left = 2,
> +			.top = 2,
> +			.width = 640,
> +			.height = 600,
> +		},
> +	},
> +	{
> +		.width = 640,
> +		.height = 480,
> +		.bin_mode = VD55G0_BIN_MODE_NORMAL,
> +		.crop = {
> +			.left = 2,
> +			.top = 62,
> +			.width = 640,
> +			.height = 480,
> +		},
> +	},
> +	{
> +		.width = 320,
> +		.height = 240,
> +		.bin_mode = VD55G0_BIN_MODE_DIGITAL_X2,
> +		.crop = {
> +			.left = 2,
> +			.top = 62,
> +			.width = 640,
> +			.height = 480,
> +		},
> +	},
> +};
> +
> +enum vd55g0_expo_state {
> +	VD55G0_EXP_AUTO,
> +	VD55G0_EXP_FREEZE,
> +	VD55G0_EXP_MANUAL
> +};
> +
> +struct vd55g0_dev {
> +	struct i2c_client *i2c_client;
> +	struct regmap *regmap;
> +	struct v4l2_subdev sd;
> +	struct media_pad pad;
> +	struct regulator_bulk_data supplies[VD55G0_NUM_SUPPLIES];
> +	unsigned int nb_supplies;
> +	struct gpio_desc *reset_gpio;
> +	struct clk *xclk;
> +	u32 clk_freq;
> +	u16 oif_ctrl;
> +	u32 mipi_rate;
> +	u32 pixel_rate;

Can you access the value in the pixel rate control instead?

> +	u64 link_freq;
> +	u16 line_length;

hblank + crop width?

> +	u16 revision;
> +	/* Lock to protect all members below */
> +	struct mutex lock;
> +	struct v4l2_ctrl_handler ctrl_handler;
> +	struct v4l2_ctrl *vblank_ctrl;
> +	struct v4l2_ctrl *hblank_ctrl;
> +	struct v4l2_ctrl *vflip_ctrl;
> +	struct v4l2_ctrl *hflip_ctrl;
> +	struct v4l2_ctrl *pattern_ctrl;
> +	/* The auto exposure cluster, the auto control first */
> +	struct {
> +		struct v4l2_ctrl *ae_ctrl;
> +		struct v4l2_ctrl *expo_ctrl;
> +		struct v4l2_ctrl *again_ctrl;
> +		struct v4l2_ctrl *dgain_ctrl;
> +	};
> +	bool streaming;
> +	u32 code;
> +	const struct vd55g0_mode_info *current_mode;
> +	bool hflip;
> +	bool vflip;
> +	u16 manual_expo;
> +	enum vd55g0_expo_state expo_state;
> +	u16 digital_gain;
> +	u8 analog_gain;
> +	u16 vblank;
> +	u16 vblank_min;
> +	u16 frame_length;
> +	bool ae_frozen;
> +	u32 pattern;
> +	u16 exposure_target;
> +	u32 leds[VD55G0_NB_GPIOS];
> +	bool flash_en;
> +	unsigned int nb_leds;
> +	struct {
> +		u16 expo;
> +		u16 digital_gain;
> +		u8 analog_gain;
> +	} cold_start;
> +};
> +
> +static inline struct vd55g0_dev *to_vd55g0_dev(struct v4l2_subdev *sd)
> +{
> +	return container_of(sd, struct vd55g0_dev, sd);
> +}
> +
> +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
> +{
> +	return &container_of(ctrl->handler, struct vd55g0_dev,
> +		ctrl_handler)->sd;
> +}
> +
> +static u8 get_bpp_by_code(__u32 code)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(vd55g0_supported_codes); i++) {
> +		if (vd55g0_supported_codes[i].code == code)
> +			return vd55g0_supported_codes[i].bpp;
> +	}
> +	/* Should never happen */
> +	WARN(1, "Unsupported code %d. default to 8 bpp\n", code);
> +	return 8;
> +}
> +
> +static u8 get_data_type_by_code(__u32 code)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(vd55g0_supported_codes); i++) {

Declare i here.

> +		if (vd55g0_supported_codes[i].code == code)
> +			return vd55g0_supported_codes[i].data_type;
> +	}
> +	/* Should never happen */
> +	WARN(1, "Unsupported code %d. default to MIPI_CSI2_DT_RAW8 data type\n",
> +	     code);
> +	return MIPI_CSI2_DT_RAW8;
> +}
> +
> +#define vd55g0_read(sensor, reg, val, err) \
> +	cci_read((sensor)->regmap, reg, val, err)
> +
> +#define vd55g0_write(sensor, reg, val, err) \
> +	cci_write((sensor)->regmap, reg, val, err)
> +
> +static int get_chunk_size(struct vd55g0_dev *sensor)
> +{
> +	int max_write_len = VD55G0_WRITE_MULTIPLE_CHUNK_MAX;

unsigned int? And the same for the macro value?

> +	struct i2c_adapter *adapter = sensor->i2c_client->adapter;
> +
> +	if (adapter->quirks && adapter->quirks->max_write_len)
> +		max_write_len = adapter->quirks->max_write_len - 2;
> +
> +	max_write_len = min(max_write_len, VD55G0_WRITE_MULTIPLE_CHUNK_MAX);
> +
> +	return max(max_write_len, 1);
> +}
> +
> +static int vd55g0_write_array(struct vd55g0_dev *sensor, u32 reg,
> +			      unsigned int nb, const u8 *array)
> +{
> +	const unsigned int chunk_size = get_chunk_size(sensor);
> +	unsigned int addr = CCI_REG_ADDR(reg);
> +	unsigned int sz;
> +	int ret;
> +
> +	while (nb) {
> +		sz = min(nb, chunk_size);
> +		ret = regmap_bulk_write(sensor->regmap, addr, array, sz);
> +		if (ret < 0)
> +			return ret;
> +		nb -= sz;
> +		addr += sz;
> +		array += sz;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vd55g0_poll_reg(struct vd55g0_dev *sensor, u32 reg, u8 poll_val,
> +			   unsigned int timeout_ms)
> +{
> +	unsigned int val = 0;
> +
> +	return regmap_read_poll_timeout(sensor->regmap, CCI_REG_ADDR(reg), val,
> +					(val == poll_val), 10 * USEC_PER_MSEC,
> +					timeout_ms * USEC_PER_MSEC);
> +}
> +
> +static int vd55g0_wait_state(struct vd55g0_dev *sensor, int state,
> +			     unsigned int timeout_ms)
> +{
> +	return vd55g0_poll_reg(sensor, VD55G0_REG_SYSTEM_FSM, state,
> +			       timeout_ms);
> +}
> +
> +static int vd55g0_prepare_clock_tree(struct vd55g0_dev *sensor)
> +{
> +	struct device *dev = &sensor->i2c_client->dev;
> +	u32 pixel_div;
> +
> +	if (sensor->clk_freq < VD55G0_XCLK_FREQ_MIN ||
> +	    sensor->clk_freq > VD55G0_XCLK_FREQ_MAX) {
> +		dev_err(dev,
> +			"Only %luMHz-%luMHz clock range supported. Provided %lu MHz\n",

I'd just use Hz here, the division loses possibly useful information.

> +			VD55G0_XCLK_FREQ_MIN / HZ_PER_MHZ,
> +			VD55G0_XCLK_FREQ_MAX / HZ_PER_MHZ,
> +			sensor->clk_freq / HZ_PER_MHZ);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * The MIPI bus is double data rate, and its rate is an integer multiple
> +	 * of the input clock. The sensor would round any other rate down
> +	 * (UM2829 13.6), so it is refused rather than used.
> +	 */
> +	if (sensor->link_freq < VD55G0_MIPI_RATE_MIN / 2 ||
> +	    sensor->link_freq > VD55G0_MIPI_RATE_MAX / 2) {
> +		dev_err(dev,
> +			"Only %luMbps-%luMbps data rate range supported. Provided link frequency %llu Hz\n",
> +			VD55G0_MIPI_RATE_MIN / MEGA, VD55G0_MIPI_RATE_MAX / MEGA,
> +			sensor->link_freq);
> +		return -EINVAL;
> +	}
> +	sensor->mipi_rate = sensor->link_freq * 2;

Is it useful to keep both in the context struct?

> +	if (sensor->mipi_rate % sensor->clk_freq) {
> +		dev_err(dev,
> +			"Link frequency %llu Hz is not a multiple of half the %u Hz input clock\n",
> +			sensor->link_freq, sensor->clk_freq);
> +		return -EINVAL;
> +	}
> +
> +	pixel_div = sensor->mipi_rate <= VD55G0_MIPI_RATE_FAST ? 6 : 8;
> +	sensor->pixel_rate = sensor->mipi_rate / pixel_div;
> +
> +	return 0;
> +}
> +
> +static int vd55g0_update_gpio_mode(struct vd55g0_dev *sensor, u32 mode,
> +				   int gpio)
> +{
> +	static const u8 index2val[] = {0x01, 0x02};

Spaces inside braces.

> +
> +	return vd55g0_write(sensor, VD55G0_REG_GPIO_0_CTRL + gpio,
> +			    index2val[mode], NULL);
> +}
> +
> +static int vd55g0_set_gpios_array(struct vd55g0_dev *sensor, u32 *array,
> +				  int size, enum vd55g0_gpio_modes mode)

Could size be unsigned, too?

> +{
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < size;  i++) {

i can be declared here.

> +		if (array[i] == ~0)
> +			break;
> +		ret = vd55g0_update_gpio_mode(sensor, mode, array[i]);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vd55g0_apply_exposure_auto(struct vd55g0_dev *sensor)
> +{
> +	enum vd55g0_expo_state exp = sensor->expo_state;
> +
> +	if (sensor->ae_frozen && sensor->expo_state == VD55G0_EXP_AUTO)
> +		exp = VD55G0_EXP_FREEZE;
> +
> +	return vd55g0_write(sensor, VD55G0_REG_EXP_MODE, exp, NULL);
> +}
> +
> +static int vd55g0_get_regulators(struct vd55g0_dev *sensor)
> +{
> +	struct device *dev = &sensor->i2c_client->dev;
> +	const char * const *names;
> +	unsigned int i;
> +
> +	/* A PRP0001 device has DT names; only the ACPI ID has INT3472's */
> +	if (acpi_match_device(vd55g0_acpi_ids, dev)) {
> +		names = vd55g0_acpi_supply_name;
> +		sensor->nb_supplies = ARRAY_SIZE(vd55g0_acpi_supply_name);

Shouldn't this be the same for DT and ACPI...?

> +	} else {
> +		names = vd55g0_dt_supply_name;
> +		sensor->nb_supplies = ARRAY_SIZE(vd55g0_dt_supply_name);
> +	}
> +
> +	for (i = 0; i < sensor->nb_supplies; i++)
> +		sensor->supplies[i].supply = names[i];
> +
> +	return devm_regulator_bulk_get(dev, sensor->nb_supplies,
> +				       sensor->supplies);
> +}
> +
> +static int vd55g0_apply_patgen(struct vd55g0_dev *sensor)
> +{
> +	static const u8 index2val[] = {
> +		0x0, 0x0, 0x8, 0x10, 0x20, 0x21, 0x22, 0x28
> +	};
> +	u32 pattern = index2val[sensor->pattern];
> +	u32 reg = pattern << VD55G0_PATGEN_TYPE_SHIFT;
> +	u8 darkcal = VD55G0_DARKCAL_AUTO;
> +	u8 duster = VD55G0_DUSTER_RING_ENABLE | VD55G0_DUSTER_DYN_ENABLE |
> +		    VD55G0_DUSTER_ENABLE;
> +	int ret = 0;
> +
> +	if (sensor->pattern != 0) {
> +		reg |= VD55G0_PATGEN_ENABLE;
> +		/*
> +		 * Take care of dark calibaration and duster to not mess up the
> +		 * test pattern output.
> +		 */
> +		darkcal = VD55G0_DARKCAL_BYPASS;
> +		duster = VD55G0_DUSTER_DISABLE;
> +	}
> +
> +	vd55g0_write(sensor, VD55G0_REG_DARKCAL_CTRL, darkcal, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_DUSTER_CTRL, duster, &ret);
> +	if (ret)
> +		return ret;
> +
> +	return vd55g0_write(sensor, VD55G0_REG_PATGEN_CTRL, reg, NULL);
> +}
> +
> +static int vd55g0_apply_flash(struct vd55g0_dev *sensor)
> +{
> +	enum vd55g0_gpio_modes mode = sensor->flash_en ?
> +				      VD55G0_GPIO_MODE_STROBE :
> +				      VD55G0_GPIO_MODE_DISABLED;
> +
> +	return vd55g0_set_gpios_array(sensor, sensor->leds,
> +				      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 index)
> +{
> +	enum vd55g0_expo_state old = sensor->expo_state;
> +	int ret;
> +
> +	switch (index) {
> +	case V4L2_EXPOSURE_AUTO:
> +		sensor->expo_state = VD55G0_EXP_AUTO;
> +		break;
> +	case V4L2_EXPOSURE_MANUAL:
> +		sensor->expo_state = VD55G0_EXP_MANUAL;
> +		break;
> +	default:
> +		/* Should never happen */
> +		return -EINVAL;
> +	}
> +
> +	if (!sensor->streaming)
> +		return 0;
> +
> +	ret = vd55g0_apply_exposure_auto(sensor);
> +	if (ret)
> +		sensor->expo_state = old;
> +
> +	return ret;
> +}
> +
> +static int vd55g0_lock_exposure(struct vd55g0_dev *sensor,
> +				struct v4l2_ctrl *ctrl)
> +{
> +	/* Only exposure lock is supported */
> +	bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
> +	bool old = sensor->ae_frozen;
> +	int ret;
> +
> +	sensor->ae_frozen = ae_lock;
> +
> +	/* Cap control value to reflect the hardware state */
> +	ctrl->val = ae_lock;
> +
> +	if (!sensor->streaming)
> +		return 0;
> +
> +	ret = vd55g0_apply_exposure_auto(sensor);
> +	if (ret)
> +		sensor->ae_frozen = old;
> +
> +	return ret;
> +}
> +
> +static int vd55g0_apply_framelength(struct vd55g0_dev *sensor)
> +{
> +	return vd55g0_write(sensor, VD55G0_REG_FRAME_LENGTH,
> +			    sensor->frame_length, NULL);
> +}
> +
> +static int vd55g0_update_vblank(struct vd55g0_dev *sensor, u16 vblank)
> +{
> +	u16 old_vblank = sensor->vblank, old_frame_length = sensor->frame_length;
> +	int ret;
> +
> +	sensor->vblank_min = VD55G0_MIN_FRAME_LENGTH -
> +			     sensor->current_mode->crop.height;
> +	sensor->vblank = vblank;
> +	sensor->frame_length = sensor->current_mode->crop.height +
> +			       sensor->vblank;
> +
> +	if (!sensor->streaming)
> +		return 0;
> +
> +	ret = vd55g0_apply_framelength(sensor);
> +	if (ret) {
> +		sensor->vblank = old_vblank;
> +		sensor->frame_length = old_frame_length;
> +	}
> +
> +	return ret;
> +}
> +
> +static int vd55g0_update_analog_gain(struct vd55g0_dev *sensor, u32 target)
> +{
> +	int ret = 0;
> +
> +	if (sensor->streaming)
> +		ret = vd55g0_write(sensor, VD55G0_REG_MANUAL_ANALOG_GAIN,
> +				   target, NULL);
> +	if (!ret)
> +		sensor->analog_gain = target;

Do you need to maintain this separately from the control value? The same
for those below.

> +
> +	return ret;
> +}
> +
> +static int vd55g0_update_digital_gain(struct vd55g0_dev *sensor, u32 target)
> +{
> +	int ret = 0;
> +
> +	if (sensor->streaming)
> +		ret = vd55g0_write(sensor, VD55G0_REG_MANUAL_DIGITAL_GAIN,
> +				   target, NULL);
> +	if (!ret)
> +		sensor->digital_gain = target;
> +
> +	return ret;
> +}
> +
> +static int vd55g0_update_exposure(struct vd55g0_dev *sensor, int expo_ms)
> +{
> +	int ret = 0;
> +
> +	if (sensor->streaming)
> +		ret = vd55g0_write(sensor, VD55G0_REG_MANUAL_COARSE_EXPOSURE,
> +				   expo_ms, NULL);
> +	if (!ret)
> +		sensor->manual_expo = expo_ms;
> +
> +	return ret;
> +}
> +
> +static int vd55g0_update_exposure_target(struct vd55g0_dev *sensor, int index)
> +{
> +	/*
> +	 * Find auto exposure target with: default target exposure * 2^EV,
> +	 * the default being VD55G0_EXPO_TARGET_DEF at index 6.
> +	 */
> +	static const unsigned int index2exposure_target[] = {
> +		3, 5, 7, 10, 14, 19, 27, 38, 54, 76, 108, 153, 216,
> +	};
> +	unsigned int target = index2exposure_target[index];
> +	int ret = 0;
> +
> +	if (sensor->streaming)
> +		ret = vd55g0_write(sensor, VD55G0_REG_AE_TARGET_PERCENTAGE,
> +				   target, NULL);
> +	if (!ret)
> +		sensor->exposure_target = target;
> +
> +	return ret;
> +}
> +
> +static int vd55g0_update_flash(struct vd55g0_dev *sensor, int flash_en)
> +{
> +	bool old = sensor->flash_en;
> +	int ret;
> +
> +	sensor->flash_en = flash_en;
> +	if (!sensor->streaming)
> +		return 0;
> +
> +	ret = vd55g0_apply_flash(sensor);
> +	if (ret)
> +		sensor->flash_en = old;
> +
> +	return ret;
> +}
> +
> +static void vd55g0_apply_reset(struct vd55g0_dev *sensor)
> +{
> +	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
> +	usleep_range(5000, 10000);
> +	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
> +	usleep_range(5000, 10000);
> +	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
> +	usleep_range(5000, 10000);
> +}
> +
> +static void vd55g0_fill_framefmt(struct vd55g0_dev *sensor,
> +				 const struct vd55g0_mode_info *mode,
> +				 struct v4l2_mbus_framefmt *fmt, u32 code)
> +{
> +	fmt->code = code;
> +	fmt->width = mode->width;
> +	fmt->height = mode->height;
> +	fmt->colorspace = V4L2_COLORSPACE_RAW;
> +	fmt->field = V4L2_FIELD_NONE;
> +	fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> +	fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
> +	fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +}
> +
> +static int vd55g0_try_fmt_internal(struct v4l2_subdev *sd,
> +				   struct v4l2_mbus_framefmt *fmt,
> +				   const struct vd55g0_mode_info **new_mode)
> +{
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(sd);
> +	const struct vd55g0_mode_info *mode = vd55g0_mode_data;
> +	unsigned int index;
> +
> +	for (index = 0; index < ARRAY_SIZE(vd55g0_supported_codes); index++) {
> +		if (vd55g0_supported_codes[index].code == fmt->code)
> +			break;
> +	}
> +	if (index == ARRAY_SIZE(vd55g0_supported_codes))
> +		index = 0;
> +
> +	mode = v4l2_find_nearest_size(vd55g0_mode_data,
> +				      ARRAY_SIZE(vd55g0_mode_data), width,
> +				      height, fmt->width, fmt->height);
> +	if (new_mode)
> +		*new_mode = mode;
> +
> +	vd55g0_fill_framefmt(sensor, mode, fmt,
> +			     vd55g0_supported_codes[index].code);
> +
> +	return 0;
> +}
> +
> +static int vd55g0_apply_cold_start(struct vd55g0_dev *sensor)
> +{
> +	int ret = 0;
> +
> +	vd55g0_write(sensor, VD55G0_REG_AE_COLDSTART_COARSE_EXPOSURE,
> +		     sensor->cold_start.expo, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_AE_COLDSTART_ANALOG_GAIN,
> +		     sensor->cold_start.analog_gain, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_AE_COLDSTART_DIGITAL_GAIN,
> +		     sensor->cold_start.digital_gain, &ret);
> +
> +	return ret;
> +}
> +
> +static int vd55g0_apply_settings(struct vd55g0_dev *sensor)
> +{
> +	int ret;
> +
> +	ret = vd55g0_apply_framelength(sensor);
> +	if (ret)
> +		return ret;
> +
> +	ret = vd55g0_apply_exposure_auto(sensor);
> +	if (ret)
> +		return ret;
> +
> +	vd55g0_write(sensor, VD55G0_REG_MANUAL_COARSE_EXPOSURE,
> +		     sensor->manual_expo, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_MANUAL_ANALOG_GAIN,
> +		     sensor->analog_gain, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_MANUAL_DIGITAL_GAIN,
> +		     sensor->digital_gain, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_AE_TARGET_PERCENTAGE,
> +		     sensor->exposure_target, &ret);

Please do rely on the control framework instead of doing this manually.

> +	if (ret)
> +		return ret;
> +
> +	ret = vd55g0_apply_cold_start(sensor);
> +	if (ret)
> +		return ret;
> +
> +	vd55g0_write(sensor, VD55G0_REG_ORIENTATION,
> +		     sensor->hflip | (sensor->vflip << 1), &ret);
> +	if (ret)
> +		return ret;
> +
> +	ret = vd55g0_apply_patgen(sensor);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int vd55g0_apply_frame_format(struct vd55g0_dev *sensor)
> +{
> +	const struct v4l2_rect *crop = &sensor->current_mode->crop;
> +	int ret = 0;
> +
> +	vd55g0_write(sensor, VD55G0_REG_READOUT_CTRL,
> +		     sensor->current_mode->bin_mode, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_ROI_X_START, crop->left, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_ROI_X_END,
> +		     crop->left + crop->width - 1, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_ROI_Y_START, crop->top, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_ROI_Y_END,
> +		     crop->top + crop->height - 1, &ret);
> +
> +	/*
> +	 * Use the same auto exposure crop as the image crop, performing auto
> +	 * exposure computation only on image boundaries.
> +	 */
> +	vd55g0_write(sensor, VD55G0_REG_AE_ROI_START_H, crop->left, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_AE_ROI_END_H,
> +		     crop->left + crop->width - 1, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_AE_ROI_START_V, crop->top, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_AE_ROI_END_V,
> +		     crop->top + crop->height - 1, &ret);
> +
> +	return ret;
> +}
> +
> +static int vd55g0_set_gpios(struct vd55g0_dev *sensor)
> +{
> +	int ret;
> +	unsigned int i;
> +
> +	/* GPIOs in input (disabled) by default */
> +	for (i = 0; i < VD55G0_NB_GPIOS; i++) {

You can declare i here.

> +		ret = vd55g0_update_gpio_mode(sensor,
> +					      VD55G0_GPIO_MODE_DISABLED, i);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = vd55g0_apply_flash(sensor);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int vd55g0_stream_enable(struct vd55g0_dev *sensor)
> +{
> +	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
> +	int ret;
> +
> +	ret = pm_runtime_resume_and_get(&client->dev);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = vd55g0_set_gpios(sensor);
> +	if (ret)
> +		goto err_rpm_put;
> +
> +	vd55g0_write(sensor, VD55G0_REG_FORMAT_CTRL,
> +		     get_bpp_by_code(sensor->code), &ret);
> +	vd55g0_write(sensor, VD55G0_REG_OIF_IMG_CTRL,
> +		     get_data_type_by_code(sensor->code), &ret);
> +	if (ret)
> +		goto err_rpm_put;
> +
> +	ret = vd55g0_apply_frame_format(sensor);
> +	if (ret)
> +		goto err_rpm_put;
> +
> +	ret = vd55g0_apply_settings(sensor);
> +	if (ret)
> +		goto err_rpm_put;
> +
> +	ret = vd55g0_write(sensor, VD55G0_REG_SW_STBY,
> +			   VD55G0_SW_STBY_START_STREAM, NULL);
> +	if (ret)
> +		goto err_rpm_put;
> +
> +	ret = vd55g0_poll_reg(sensor, VD55G0_REG_SW_STBY, 0, VD55G0_TIMEOUT_MS);
> +	if (ret)
> +		goto err_rpm_put;
> +
> +	ret = vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_STREAMING,
> +				VD55G0_TIMEOUT_MS);
> +	if (ret)
> +		goto err_rpm_put;
> +
> +	return 0;
> +
> +err_rpm_put:
> +	pm_runtime_put(&client->dev);
> +	return ret;
> +}
> +
> +static void vd55g0_save_exposure(struct vd55g0_dev *sensor)
> +{
> +	u64 val;
> +
> +	/* On a read error, keep what the previous stream left */
> +	if (!vd55g0_read(sensor, VD55G0_REG_APPLIED_COARSE_EXPOSURE, &val, NULL))
> +		sensor->cold_start.expo = val;
> +	if (!vd55g0_read(sensor, VD55G0_REG_APPLIED_DIGITAL_GAIN, &val, NULL))
> +		sensor->cold_start.digital_gain = val;
> +	if (!vd55g0_read(sensor, VD55G0_REG_APPLIED_ANALOG_GAIN, &val, NULL))
> +		sensor->cold_start.analog_gain = val;
> +}
> +
> +static void vd55g0_stream_disable(struct vd55g0_dev *sensor)
> +{
> +	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
> +	int ret;
> +
> +	/* Keep exposure values for next cold start boot */
> +	vd55g0_save_exposure(sensor);
> +
> +	ret = vd55g0_write(sensor, VD55G0_REG_STREAMING,
> +			   VD55G0_STREAMING_STOP_STREAM, NULL);
> +	if (ret)
> +		goto err_str_dis;
> +
> +	ret = vd55g0_poll_reg(sensor, VD55G0_REG_STREAMING, 0, 2000);
> +	if (ret)
> +		goto err_str_dis;
> +
> +	ret = vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_SW_STBY,
> +				VD55G0_TIMEOUT_MS);
> +
> +err_str_dis:
> +	if (ret)
> +		dev_err(&client->dev, "failed to stop streaming: %d\n", ret);
> +	pm_runtime_put_autosuspend(&client->dev);
> +}
> +
> +static int vd55g0_tx_from_ep(struct vd55g0_dev *sensor,
> +			     struct fwnode_handle *handle)
> +{
> +	struct i2c_client *client = sensor->i2c_client;
> +	struct v4l2_fwnode_endpoint *ep;
> +	struct v4l2_fwnode_endpoint ep_node = { .bus_type =
> +		V4L2_MBUS_CSI2_DPHY
> +	};
> +	int ret;
> +
> +	ep = &ep_node;

Why?

> +	ret = v4l2_fwnode_endpoint_alloc_parse(handle, ep);
> +	if (ret)
> +		return ret;
> +
> +	/* The sensor has a single data lane */
> +	if (ep->bus.mipi_csi2.num_data_lanes != 1) {
> +		dev_err(&client->dev, "only one data lane is supported, found %u\n",
> +			ep->bus.mipi_csi2.num_data_lanes);
> +		goto error_ep;
> +	}
> +
> +	if (ep->bus.mipi_csi2.clock_lane != 0) {
> +		dev_err(&client->dev, "clock lane must be lane 0\n");
> +		goto error_ep;
> +	}
> +
> +	/* Only the two polarity bits: the rest of OIF_CTRL is reserved */
> +	sensor->oif_ctrl = (ep->bus.mipi_csi2.lane_polarities[0] << 3) |
> +			   (ep->bus.mipi_csi2.lane_polarities[1] << 6);
> +
> +	if (ep->nr_of_link_frequencies != 1) {
> +		dev_err(&client->dev, "one link frequency is needed, found %u\n",
> +			ep->nr_of_link_frequencies);
> +		goto error_ep;
> +	}
> +	sensor->link_freq = ep->link_frequencies[0];
> +
> +	v4l2_fwnode_endpoint_free(ep);
> +
> +	return 0;
> +
> +error_ep:
> +	v4l2_fwnode_endpoint_free(ep);
> +
> +	return -EINVAL;
> +}
> +
> +static int vd55g0_patch(struct vd55g0_dev *sensor)
> +{
> +	struct i2c_client *client = sensor->i2c_client;
> +	const struct vd55g0_patch *patch;
> +	u64 patch_version;
> +	int ret;
> +
> +	/* Choose appropriate patch for sensor revision */
> +	if (sensor->revision == VD55G0_REVISION_CUT1)
> +		patch = &vd55g0_patch_cut1;
> +	else if (sensor->revision == VD55G0_REVISION_CUT2)
> +		patch = &vd55g0_patch_cut2;
> +	else
> +		return -EINVAL;
> +
> +	/* Write patch */
> +	ret = vd55g0_write_array(sensor, VD55G0_REG_FWPATCH_START_ADDR,
> +				 patch->size, patch->bin);
> +	if (ret)
> +		return ret;
> +
> +	ret = vd55g0_write(sensor, VD55G0_REG_BOOT,
> +			   VD55G0_BOOT_PATCH_SETUP, NULL);
> +	if (ret)
> +		return ret;
> +
> +	ret = vd55g0_poll_reg(sensor, VD55G0_REG_BOOT, 0, VD55G0_TIMEOUT_MS);
> +	if (ret)
> +		return ret;
> +
> +	/* Read back patch version */
> +	ret = vd55g0_read(sensor, VD55G0_REG_FWPATCH_REVISION, &patch_version,
> +			  NULL);
> +	if (ret)
> +		return ret;
> +
> +	if (patch_version != (patch->major << 8) + patch->minor) {

Why to keep minor and major in separate fields?

> +		dev_err(&client->dev,
> +			"bad patch version expected %d.%d got %llu.%llu\n",
> +			patch->major, patch->minor,
> +			patch_version >> 8, patch_version & 0xff);
> +		return -ENODEV;
> +	}
> +	dev_dbg(&client->dev, "patch %llu.%llu applied\n",
> +		patch_version >> 8, patch_version & 0xff);
> +
> +	return 0;
> +}
> +
> +static int vd55g0_boot(struct vd55g0_dev *sensor)
> +{
> +	int ret;
> +
> +	ret = vd55g0_write(sensor, VD55G0_REG_BOOT, VD55G0_BOOT_BOOT, NULL);
> +	if (ret)
> +		return ret;
> +
> +	ret = vd55g0_poll_reg(sensor, VD55G0_REG_BOOT, 0, VD55G0_TIMEOUT_MS);
> +	if (ret)
> +		return ret;
> +
> +	ret = vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_SW_STBY,
> +				VD55G0_TIMEOUT_MS);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int vd55g0_configure(struct vd55g0_dev *sensor)
> +{
> +	int ret = 0;
> +
> +	sensor->line_length = VD55G0_LINE_LENGTH_FAST;
> +	if (sensor->mipi_rate <= VD55G0_MIPI_RATE_FAST)
> +		sensor->line_length = VD55G0_LINE_LENGTH_SLOW;
> +	vd55g0_write(sensor, VD55G0_REG_LINE_LENGTH, sensor->line_length,
> +		     &ret);
> +
> +	/*
> +	 * PLL_PREDIV and PLL_MULT are not accessible. We rely on the firmware
> +	 * to set the correct multiplier for the clock. Hence we don't do
> +	 * anything more here.
> +	 */
> +	vd55g0_write(sensor, VD55G0_REG_EXT_CLOCK, sensor->clk_freq, &ret);
> +
> +	vd55g0_write(sensor, VD55G0_REG_OIF_CTRL, sensor->oif_ctrl, &ret);
> +	/* The status lines are not exposed, so do not send them, as vd55g1 */
> +	vd55g0_write(sensor, VD55G0_REG_ISL_ENABLE, 0, &ret);
> +	vd55g0_write(sensor, VD55G0_REG_CLK_PLL_MIPI, sensor->mipi_rate, &ret);
> +
> +	return 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)
> +{
> +	__v4l2_ctrl_grab(sensor->vflip_ctrl, grab);
> +	__v4l2_ctrl_grab(sensor->hflip_ctrl, grab);
> +	__v4l2_ctrl_grab(sensor->pattern_ctrl, grab);
> +}
> +
> +static int vd55g0_enable_streams(struct v4l2_subdev *sd,
> +				 struct v4l2_subdev_state *state, u32 pad,
> +				 u64 streams_mask)
> +{
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(sd);
> +	int ret;
> +
> +	ret = vd55g0_stream_enable(sensor);
> +	if (ret)
> +		return ret;
> +
> +	sensor->streaming = true;
> +	vd55g0_grab_stream_ctrls(sensor, true);
> +
> +	return 0;
> +}
> +
> +static int vd55g0_disable_streams(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *state, u32 pad,
> +				  u64 streams_mask)
> +{
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(sd);
> +
> +	/* Powered down either way, so report success as call_s_stream() does */
> +	vd55g0_stream_disable(sensor);
> +
> +	sensor->streaming = false;
> +	vd55g0_grab_stream_ctrls(sensor, false);
> +
> +	return 0;
> +}
> +
> +static int vd55g0_get_selection(struct v4l2_subdev *sd,
> +				const struct v4l2_subdev_client_info *ci,
> +				struct v4l2_subdev_state *sd_state,
> +				struct v4l2_subdev_selection *sel)
> +{
> +	const struct vd55g0_mode_info *mode;
> +	const struct v4l2_mbus_framefmt *fmt;
> +
> +	switch (sel->target) {
> +	case V4L2_SEL_TGT_CROP:
> +		/* From the state asked about, so that TRY gets its own crop */

Redundant comment.

> +		fmt = v4l2_subdev_state_get_format(sd_state, 0);
> +		mode = v4l2_find_nearest_size(vd55g0_mode_data,
> +					      ARRAY_SIZE(vd55g0_mode_data),
> +					      width, height,
> +					      fmt->width, fmt->height);
> +		sel->r = mode->crop;
> +		return 0;
> +	case V4L2_SEL_TGT_NATIVE_SIZE:
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> +		sel->r.top = 0;
> +		sel->r.left = 0;
> +		sel->r.width = VD55G0_WIDTH;
> +		sel->r.height = VD55G0_HEIGHT;
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int vd55g0_enum_mbus_code(struct v4l2_subdev *sd,
> +				 struct v4l2_subdev_state *sd_state,
> +				 struct v4l2_subdev_mbus_code_enum *code)
> +{
> +	if (code->index >= ARRAY_SIZE(vd55g0_supported_codes))
> +		return -EINVAL;
> +
> +	code->code = vd55g0_supported_codes[code->index].code;
> +
> +	return 0;
> +}
> +
> +static int vd55g0_set_fmt(struct v4l2_subdev *sd,
> +			  const struct v4l2_subdev_client_info *ci,
> +			  struct v4l2_subdev_state *sd_state,
> +			  struct v4l2_subdev_format *format)
> +{
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(sd);
> +	const struct vd55g0_mode_info *new_mode;
> +	struct v4l2_mbus_framefmt *fmt;
> +	unsigned int expo_max, hblank;
> +	u16 vblank_def;
> +	int ret;
> +
> +	/* The mode cannot change under a running stream */
> +	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && sensor->streaming)

Instead of maintaining streaming state locally, could you use
media_entity_is_streaming()?

> +		return -EBUSY;
> +
> +	ret = vd55g0_try_fmt_internal(sd, &format->format, &new_mode);
> +	if (ret)
> +		return ret;
> +
> +	fmt = v4l2_subdev_state_get_format(sd_state, 0);
> +	*fmt = format->format;
> +
> +	if (format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
> +		return 0;
> +
> +	if (sensor->current_mode == new_mode && sensor->code == fmt->code)
> +		return 0;
> +
> +	sensor->code = fmt->code;
> +	sensor->current_mode = new_mode;

This information would be better maintained as part of sub-device state.

> +
> +	/* Reset vblank and framelength to default */
> +	vblank_def = VD55G0_FRAME_LENGTH_DEF - new_mode->crop.height;
> +	ret = vd55g0_update_vblank(sensor, vblank_def);
> +	if (ret)
> +		return ret;
> +
> +	/* The range change may clamp and apply the old vblank; set the default */
> +	ret = __v4l2_ctrl_modify_range(sensor->vblank_ctrl, sensor->vblank_min,
> +				       0xffff - new_mode->crop.height, 1,
> +				       vblank_def);
> +	if (ret)
> +		return ret;
> +	ret = __v4l2_ctrl_s_ctrl(sensor->vblank_ctrl, vblank_def);
> +	if (ret)
> +		return ret;
> +	/* Max exposure changes with vblank */
> +	expo_max = sensor->frame_length - VD55G0_EXPO_MAX_TERM;
> +	ret = __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max, 1,
> +				       VD55G0_EXPO_DEF);
> +	if (ret)
> +		return ret;
> +	/* Blanking counts from the analogue crop, as in vd55g1 */
> +	hblank = sensor->line_length - sensor->current_mode->crop.width;
> +	ret = __v4l2_ctrl_modify_range(sensor->hblank_ctrl, hblank, hblank, 1,
> +				       hblank);
> +	if (ret)
> +		return ret;
> +
> +	return __v4l2_ctrl_s_ctrl(sensor->hblank_ctrl, hblank);
> +}
> +
> +static int vd55g0_init_state(struct v4l2_subdev *sd,
> +			     struct v4l2_subdev_state *sd_state)
> +{
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(sd);
> +	struct v4l2_subdev_format fmt = { 0 };
> +
> +	vd55g0_fill_framefmt(sensor, &vd55g0_mode_data[VD55G0_DEFAULT_MODE],
> +			     &fmt.format, VD55G0_MEDIA_BUS_FMT_DEF);
> +
> +	return vd55g0_set_fmt(sd, NULL, sd_state, &fmt);
> +}
> +
> +static int vd55g0_enum_frame_size(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *sd_state,
> +				  struct v4l2_subdev_frame_size_enum *fse)
> +{
> +	unsigned int i;
> +
> +	if (fse->index >= ARRAY_SIZE(vd55g0_mode_data))
> +		return -EINVAL;
> +
> +	for (i = 0; i < ARRAY_SIZE(vd55g0_supported_codes); i++)
> +		if (vd55g0_supported_codes[i].code == fse->code)
> +			break;
> +	if (i == ARRAY_SIZE(vd55g0_supported_codes))
> +		return -EINVAL;
> +
> +	fse->min_width = vd55g0_mode_data[fse->index].width;
> +	fse->max_width = fse->min_width;
> +	fse->min_height = vd55g0_mode_data[fse->index].height;
> +	fse->max_height = fse->min_height;
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_subdev_video_ops vd55g0_video_ops = {
> +	.s_stream = v4l2_subdev_s_stream_helper,
> +};
> +
> +static const struct v4l2_subdev_pad_ops vd55g0_pad_ops = {
> +	.enum_mbus_code = vd55g0_enum_mbus_code,
> +	.get_fmt = v4l2_subdev_get_fmt,
> +	.set_fmt = vd55g0_set_fmt,
> +	.enable_streams = vd55g0_enable_streams,
> +	.disable_streams = vd55g0_disable_streams,
> +	.get_selection = vd55g0_get_selection,
> +	.enum_frame_size = vd55g0_enum_frame_size,
> +};
> +
> +static const struct v4l2_subdev_ops vd55g0_subdev_ops = {
> +	.video = &vd55g0_video_ops,
> +	.pad = &vd55g0_pad_ops,
> +};
> +
> +static const struct media_entity_operations vd55g0_subdev_entity_ops = {
> +	.link_validate = v4l2_subdev_link_validate,
> +};
> +
> +static const struct v4l2_subdev_internal_ops vd55g0_internal_ops = {
> +	.init_state = vd55g0_init_state,
> +};
> +
> +/*
> + * The manual values first, so that a switch to manual starts from them; the
> + * sensor ignores them under auto exposure.
> + */
> +static int vd55g0_update_expo_cluster(struct vd55g0_dev *sensor)
> +{
> +	int ret = 0;
> +
> +	if (sensor->ae_ctrl->val == V4L2_EXPOSURE_MANUAL) {
> +		/* A range change under auto exposure did not clamp it */
> +		sensor->expo_ctrl->val = min(sensor->expo_ctrl->val,
> +					     sensor->expo_ctrl->maximum);
> +		if (sensor->expo_ctrl->is_new)
> +			ret = vd55g0_update_exposure(sensor,
> +						     sensor->expo_ctrl->val);
> +		if (!ret && sensor->again_ctrl->is_new)
> +			ret = vd55g0_update_analog_gain(sensor,
> +							sensor->again_ctrl->val);
> +		if (!ret && sensor->dgain_ctrl->is_new)
> +			ret = vd55g0_update_digital_gain(sensor,
> +							 sensor->dgain_ctrl->val);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (sensor->ae_ctrl->is_new)
> +		ret = vd55g0_update_exposure_auto(sensor, sensor->ae_ctrl->val);
> +
> +	return ret;
> +}
> +
> +/* Under auto exposure, the manual controls read what the sensor applies */
> +static int vd55g0_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(ctrl_to_sd(ctrl));
> +	struct device *dev = &sensor->i2c_client->dev;
> +	u64 expo, again, dgain;
> +	int ret = 0;
> +
> +	if (ctrl->id != V4L2_CID_EXPOSURE_AUTO)
> +		return -EINVAL;

Can this happen, 

> +
> +	/* Unpowered, the last stream's values, which the next one starts from */
> +	if (!pm_runtime_get_if_in_use(dev)) {
> +		sensor->expo_ctrl->val = min_t(u32, sensor->cold_start.expo,
> +					       sensor->expo_ctrl->maximum);
> +		sensor->again_ctrl->val = sensor->cold_start.analog_gain;
> +		sensor->dgain_ctrl->val = sensor->cold_start.digital_gain;
> +		return 0;
> +	}
> +
> +	vd55g0_read(sensor, VD55G0_REG_APPLIED_COARSE_EXPOSURE, &expo, &ret);
> +	vd55g0_read(sensor, VD55G0_REG_APPLIED_ANALOG_GAIN, &again, &ret);
> +	vd55g0_read(sensor, VD55G0_REG_APPLIED_DIGITAL_GAIN, &dgain, &ret);
> +	if (!ret) {
> +		sensor->expo_ctrl->val = expo;
> +		sensor->again_ctrl->val = again;
> +		sensor->dgain_ctrl->val = dgain;

Can you use __v4l2_ctrl_s_ctrl()? That way events get handled correctly.

> +	}
> +
> +	pm_runtime_put_autosuspend(dev);
> +
> +	return ret;
> +}
> +
> +static int vd55g0_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(sd);
> +	unsigned int expo_max;
> +	u16 old_vblank;
> +	int ret;
> +
> +	/* Read-only controls are set by the driver, there is nothing to apply */
> +	if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
> +		return 0;
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_VFLIP:
> +	case V4L2_CID_HFLIP:
> +		if (sensor->streaming) {
> +			ret = -EBUSY;
> +			break;
> +		}
> +		if (ctrl->id == V4L2_CID_VFLIP)
> +			sensor->vflip = ctrl->val;
> +		if (ctrl->id == V4L2_CID_HFLIP)
> +			sensor->hflip = ctrl->val;
> +		ret = 0;
> +		break;
> +	case V4L2_CID_TEST_PATTERN:
> +		/* Can't be done while streaming because of duster disabling */
> +		sensor->pattern = ctrl->val;
> +		ret = 0;
> +		break;
> +	case V4L2_CID_EXPOSURE_AUTO:
> +		ret = vd55g0_update_expo_cluster(sensor);
> +		break;
> +	case V4L2_CID_3A_LOCK:
> +		ret = vd55g0_lock_exposure(sensor, ctrl);
> +		break;
> +	case V4L2_CID_VBLANK:
> +		old_vblank = sensor->vblank;
> +		ret = vd55g0_update_vblank(sensor, ctrl->val);
> +		if (ret)
> +			break;
> +		/* Max exposure changes with vblank */
> +		expo_max = sensor->frame_length - VD55G0_EXPO_MAX_TERM;
> +		ret = __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max,
> +					       1, VD55G0_EXPO_DEF);
> +		/* A clamped exposure failed to apply: put the frame back */
> +		if (ret)
> +			vd55g0_update_vblank(sensor, old_vblank);
> +		break;
> +	case V4L2_CID_AUTO_EXPOSURE_BIAS:
> +		/*
> +		 * We use auto exposure target percentage register to control
> +		 * exposure bias for more precision.
> +		 */
> +		ret = vd55g0_update_exposure_target(sensor, ctrl->val);
> +		break;
> +	case V4L2_CID_FLASH_LED_MODE:
> +		ret = vd55g0_update_flash(sensor, ctrl->val);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct v4l2_ctrl_ops vd55g0_ctrl_ops = {
> +	.g_volatile_ctrl = vd55g0_g_volatile_ctrl,
> +	.s_ctrl = vd55g0_s_ctrl,
> +};
> +
> +static int vd55g0_init_controls(struct vd55g0_dev *sensor)
> +{
> +	const struct v4l2_ctrl_ops *ops = &vd55g0_ctrl_ops;
> +	struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler;
> +	const struct vd55g0_mode_info *cur_mode = sensor->current_mode;
> +	struct v4l2_fwnode_device_properties fwnode_props;
> +	struct v4l2_ctrl *ctrl;
> +	unsigned int patgen_size = ARRAY_SIZE(vd55g0_test_pattern_menu) - 1;
> +	unsigned int hblank = sensor->line_length - cur_mode->crop.width;
> +	unsigned int expo_mode = sensor->expo_state == VD55G0_EXP_AUTO ?
> +		V4L2_EXPOSURE_AUTO :  V4L2_EXPOSURE_MANUAL;
> +	int ret;
> +
> +	v4l2_ctrl_handler_init(hdl, 16);
> +	/* we can use our own mutex for the ctrl lock */
> +	hdl->lock = &sensor->lock;
> +	v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_AUTO_EXPOSURE_BIAS,
> +			       ARRAY_SIZE(vd55g0_ev_bias_menu) - 1,
> +			       ARRAY_SIZE(vd55g0_ev_bias_menu) / 2,
> +			       vd55g0_ev_bias_menu);
> +	ctrl = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,
> +				      0, 0, &sensor->link_freq);
> +	if (ctrl)
> +		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, sensor->pixel_rate,
> +			  sensor->pixel_rate, 1, sensor->pixel_rate);
> +	sensor->ae_ctrl = v4l2_ctrl_new_std_menu(hdl, ops,
> +						 V4L2_CID_EXPOSURE_AUTO, 1,
> +						 ~0x3, expo_mode);
> +	sensor->again_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
> +					       0, 24, 1, sensor->analog_gain);
> +	sensor->dgain_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAIN,
> +					       256, 2048, 1,
> +					       sensor->digital_gain);
> +	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_3A_LOCK, 0, 1, 0, 0);
> +	/* Only when the firmware describes the LED GPIOs */
> +	if (sensor->nb_leds)
> +		v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE,
> +				       V4L2_FLASH_LED_MODE_FLASH, ~0x7,
> +				       sensor->flash_en);
> +
> +	/*
> +	 * Keep a pointer to these controls as we need to update them when
> +	 * setting the format
> +	 */
> +	sensor->vblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
> +						sensor->vblank_min,
> +						0xffff - cur_mode->crop.height,
> +						1, sensor->vblank);
> +	sensor->hblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK,
> +						hblank, hblank, 1, hblank);
> +	if (sensor->hblank_ctrl)
> +		sensor->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +	sensor->vflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
> +					       0, 1, 1, sensor->vflip);
> +	sensor->hflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
> +					       0, 1, 1, sensor->hflip);
> +	sensor->pattern_ctrl =
> +		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
> +					     patgen_size, 0, 0,
> +					     vd55g0_test_pattern_menu);
> +	sensor->expo_ctrl =
> +		v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 0,
> +				  sensor->frame_length - VD55G0_EXPO_MAX_TERM,
> +				  1, sensor->manual_expo);
> +	if (!hdl->error)
> +		v4l2_ctrl_auto_cluster(4, &sensor->ae_ctrl,
> +				       V4L2_EXPOSURE_MANUAL, true);

You can move this past the handler's error check and omit the above check.

> +
> +	ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &fwnode_props);

This goes before initialising the handler, then error handling is
simplified.

> +	if (ret)
> +		goto free_ctrls;
> +
> +	ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &fwnode_props);
> +	if (ret)
> +		goto free_ctrls;
> +
> +	if (hdl->error) {

This check is redundant.

> +		ret = hdl->error;
> +		goto free_ctrls;
> +	}
> +
> +	sensor->sd.ctrl_handler = hdl;

One more newline here.

> +	return 0;
> +
> +free_ctrls:
> +	v4l2_ctrl_handler_free(hdl);

	return v4l2_ctrl_handler_free(hdl);

> +	return ret;
> +}
> +
> +static int vd55g0_detect(struct vd55g0_dev *sensor)
> +{
> +	struct i2c_client *client = sensor->i2c_client;
> +	u64 revision, id = 0;
> +	int ret;
> +
> +	ret = vd55g0_read(sensor, VD55G0_REG_MODEL_ID, &id, NULL);
> +	if (ret)
> +		return ret;
> +
> +	if (id != VD55G0_MODEL_ID) {
> +		dev_warn(&client->dev, "Unsupported sensor id %llx\n", id);
> +		return -ENODEV;
> +	}
> +
> +	ret = vd55g0_read(sensor, VD55G0_REG_REVISION, &revision, NULL);
> +	if (ret)
> +		return ret;
> +	dev_dbg(&client->dev, "Sensor revision 0x%llx\n", revision);
> +
> +	if (revision != VD55G0_REVISION_CUT1 &&
> +	    revision != VD55G0_REVISION_CUT2) {
> +		dev_err(&client->dev, "Unsupported device revision 0x%llx\n",
> +			revision);
> +		return -ENODEV;
> +	}
> +
> +	sensor->revision = revision;
> +
> +	return 0;
> +}
> +
> +/* Power/clock management functions */
> +static int vd55g0_power_on(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(sd);
> +	int ret;
> +
> +	ret = regulator_bulk_enable(sensor->nb_supplies, sensor->supplies);
> +	if (ret) {
> +		dev_err(&client->dev, "failed to enable regulators %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(sensor->xclk);
> +	if (ret) {
> +		dev_err(&client->dev, "failed to enable clock %d\n", ret);
> +		goto disable_bulk;
> +	}
> +
> +	if (sensor->reset_gpio)
> +		vd55g0_apply_reset(sensor);
> +
> +	ret = vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_READY_TO_BOOT,
> +				VD55G0_TIMEOUT_MS);
> +	if (ret) {
> +		dev_err(&client->dev, "sensor reset failed %d\n", ret);
> +		goto disable_clock;
> +	}
> +
> +	ret = vd55g0_detect(sensor);
> +	if (ret) {
> +		dev_err(&client->dev, "sensor detect failed %d\n", ret);
> +		goto disable_clock;
> +	}
> +
> +	ret = vd55g0_patch(sensor);
> +	if (ret) {
> +		dev_err(&client->dev, "sensor patch failed %d\n", ret);
> +		goto disable_clock;
> +	}
> +
> +	ret = vd55g0_boot(sensor);
> +	if (ret) {
> +		dev_err(&client->dev, "sensor boot failed %d\n", ret);
> +		goto disable_clock;
> +	}
> +
> +	ret = vd55g0_configure(sensor);
> +	if (ret) {
> +		dev_err(&client->dev, "sensor configuration failed %d\n", ret);
> +		goto disable_clock;
> +	}
> +
> +	return 0;
> +
> +disable_clock:
> +	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
> +	clk_disable_unprepare(sensor->xclk);
> +disable_bulk:
> +	regulator_bulk_disable(sensor->nb_supplies, sensor->supplies);
> +
> +	return ret;
> +}
> +
> +static int vd55g0_power_off(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(sd);
> +
> +	/* Hold the sensor in reset while its rails are off, as vd55g1 does */
> +	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
> +	clk_disable_unprepare(sensor->xclk);
> +	regulator_bulk_disable(sensor->nb_supplies, sensor->supplies);
> +	return 0;
> +}
> +
> +static int vd55g0_parse_dt_gpios_array(struct vd55g0_dev *sensor,
> +				       char *prop_name, u32 *array, int *nb)
> +{
> +	struct i2c_client *client = sensor->i2c_client;
> +	unsigned int i;
> +	int ret;
> +
> +	*nb = device_property_count_u32(&client->dev, prop_name);
> +	if (*nb == -EINVAL) {
> +		/* Property not found */
> +		*nb = 0;
> +		return 0;
> +	}
> +	if (*nb < 0)
> +		return *nb;
> +	if (*nb > VD55G0_NB_GPIOS) {
> +		dev_err(&client->dev, "%s lists %d GPIOs, the sensor has %d\n",
> +			prop_name, *nb, VD55G0_NB_GPIOS);
> +		return -EINVAL;
> +	}
> +
> +	ret = device_property_read_u32_array(&client->dev, prop_name, array,
> +					     *nb);
> +	if (ret) {
> +		dev_err(&client->dev, "Failed to read %s prop\n", prop_name);
> +		return ret;
> +	}
> +
> +	for (i = 0; i < *nb;  i++) {
> +		if (array[i] >= VD55G0_NB_GPIOS) {
> +			dev_err(&client->dev, "invalid GPIO %d for leds\n",
> +				array[i]);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int vd55g0_parse_dt_gpios(struct vd55g0_dev *sensor)
> +{
> +	int nb_gpios_leds;
> +	int ret;
> +
> +	memset(sensor->leds, ~0, sizeof(sensor->leds));
> +
> +	ret = vd55g0_parse_dt_gpios_array(sensor, "st,leds", sensor->leds,
> +					  &nb_gpios_leds);
> +	if (ret)
> +		return ret;
> +
> +	sensor->nb_leds = nb_gpios_leds;
> +
> +	return 0;
> +}
> +
> +static int vd55g0_probe(struct i2c_client *client)
> +{
> +	struct device *dev = &client->dev;
> +	struct fwnode_handle *handle;
> +	struct vd55g0_dev *sensor;
> +	int ret;
> +
> +	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
> +	if (!sensor)
> +		return -ENOMEM;
> +
> +	sensor->analog_gain = 0;
> +	sensor->digital_gain = 256;
> +
> +	sensor->i2c_client = client;
> +	sensor->regmap = devm_cci_regmap_init_i2c(client, 16);
> +	if (IS_ERR(sensor->regmap))
> +		return dev_err_probe(&client->dev, PTR_ERR(sensor->regmap),
> +				     "failed to init CCI\n");
> +	sensor->streaming = false;
> +	/* Must match what vd55g0_init_state() puts in the subdev state */
> +	sensor->code = VD55G0_MEDIA_BUS_FMT_DEF;
> +	sensor->manual_expo = VD55G0_EXPO_DEF;
> +	sensor->vflip = false;
> +	sensor->hflip = false;
> +	sensor->flash_en = false;
> +	/* Written at every stream start, so it must match the control default */
> +	sensor->exposure_target = VD55G0_EXPO_TARGET_DEF;
> +	sensor->cold_start.expo = 0x32;
> +	sensor->cold_start.digital_gain = 256;
> +	sensor->cold_start.analog_gain = 0;
> +
> +	sensor->current_mode = &vd55g0_mode_data[VD55G0_DEFAULT_MODE];
> +
> +	handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
> +
> +	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
> +						     GPIOD_OUT_HIGH);
> +	if (IS_ERR(sensor->reset_gpio)) {
> +		ret = dev_err_probe(dev, PTR_ERR(sensor->reset_gpio),
> +				    "Failed to get reset gpio\n");
> +		goto error_put_handle;
> +	}
> +
> +	ret = vd55g0_parse_dt_gpios(sensor);
> +	if (ret) {
> +		dev_err(dev, "Failed to get gpios\n");
> +		goto error_put_handle;
> +	}
> +
> +	ret = vd55g0_tx_from_ep(sensor, handle);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "Failed to parse endpoint\n");
> +		goto error_put_handle;
> +	}
> +	fwnode_handle_put(handle);
> +
> +	sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL);
> +	if (IS_ERR(sensor->xclk))
> +		return dev_err_probe(dev, PTR_ERR(sensor->xclk),
> +				     "failed to get xclk\n");
> +
> +	sensor->clk_freq = clk_get_rate(sensor->xclk);
> +	ret = vd55g0_prepare_clock_tree(sensor);
> +	if (ret)
> +		return ret;
> +
> +	v4l2_i2c_subdev_init(&sensor->sd, client, &vd55g0_subdev_ops);
> +	sensor->sd.internal_ops = &vd55g0_internal_ops;
> +	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
> +	sensor->sd.entity.ops = &vd55g0_subdev_entity_ops;
> +	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
> +
> +	ret = vd55g0_get_regulators(sensor);
> +	if (ret)
> +		return dev_err_probe(&client->dev, ret,
> +				     "failed to get regulators\n");
> +
> +	/* Power on once to check that the sensor answers */
> +	ret = vd55g0_power_on(dev);
> +	if (ret)
> +		return ret;
> +
> +	mutex_init(&sensor->lock);
> +
> +	ret = vd55g0_update_vblank(sensor, VD55G0_FRAME_LENGTH_DEF -
> +				   sensor->current_mode->crop.height);
> +	if (ret)
> +		goto error_power_off;
> +
> +	ret = vd55g0_init_controls(sensor);
> +	if (ret) {
> +		dev_err(&client->dev, "controls initialization failed %d\n",
> +			ret);
> +		goto error_power_off;
> +	}
> +
> +	sensor->sd.state_lock = &sensor->lock;
> +
> +	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
> +	if (ret) {
> +		dev_err(&client->dev, "pads init failed %d\n", ret);
> +		goto error_handler_free;
> +	}
> +
> +	ret = v4l2_subdev_init_finalize(&sensor->sd);
> +	if (ret) {
> +		dev_err(&client->dev, "subdev init error %d\n", ret);
> +		goto error_media_entity;
> +	}
> +
> +	/* Held until registered, so that runtime PM cannot power it down */
> +	pm_runtime_set_active(dev);
> +	pm_runtime_get_noresume(dev);
> +	pm_runtime_enable(dev);
> +	pm_runtime_set_autosuspend_delay(dev, 1000);
> +	pm_runtime_use_autosuspend(dev);
> +
> +	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "async subdev register failed\n");
> +		goto error_pm_runtime;
> +	}
> +
> +	pm_runtime_put_autosuspend(dev);
> +
> +	dev_dbg(&client->dev, "vd55g0 probe successfully\n");
> +
> +	return 0;
> +
> +error_put_handle:
> +	fwnode_handle_put(handle);
> +
> +	return ret;
> +
> +error_pm_runtime:
> +	pm_runtime_disable(dev);
> +	pm_runtime_set_suspended(dev);
> +	pm_runtime_put_noidle(dev);
> +	pm_runtime_dont_use_autosuspend(dev);
> +	v4l2_subdev_cleanup(&sensor->sd);
> +error_media_entity:
> +	media_entity_cleanup(&sensor->sd.entity);
> +error_handler_free:
> +	v4l2_ctrl_handler_free(sensor->sd.ctrl_handler);
> +error_power_off:
> +	mutex_destroy(&sensor->lock);
> +	vd55g0_power_off(dev);
> +
> +	return ret;
> +}
> +
> +static void vd55g0_remove(struct i2c_client *client)
> +{
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct vd55g0_dev *sensor = to_vd55g0_dev(sd);
> +
> +	v4l2_async_unregister_subdev(&sensor->sd);
> +	v4l2_subdev_cleanup(&sensor->sd);
> +	media_entity_cleanup(&sensor->sd.entity);
> +	v4l2_ctrl_handler_free(sensor->sd.ctrl_handler);
> +	mutex_destroy(&sensor->lock);
> +
> +	pm_runtime_disable(&client->dev);
> +	if (!pm_runtime_status_suspended(&client->dev))
> +		vd55g0_power_off(&client->dev);
> +	pm_runtime_set_suspended(&client->dev);
> +	pm_runtime_dont_use_autosuspend(&client->dev);
> +}
> +
> +static const struct of_device_id vd55g0_dt_ids[] = {
> +	{ .compatible = "st,vd55g0" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, vd55g0_dt_ids);
> +
> +static const struct dev_pm_ops vd55g0_pm_ops = {
> +	RUNTIME_PM_OPS(vd55g0_power_off, vd55g0_power_on, NULL)
> +};
> +
> +static struct i2c_driver vd55g0_i2c_driver = {
> +	.driver = {
> +		.name  = "vd55g0",
> +		.of_match_table = vd55g0_dt_ids,
> +		.acpi_match_table = vd55g0_acpi_ids,
> +		.pm = pm_ptr(&vd55g0_pm_ops),
> +	},
> +	.probe = vd55g0_probe,
> +	.remove = vd55g0_remove,
> +};
> +
> +module_i2c_driver(vd55g0_i2c_driver);
> +
> +MODULE_AUTHOR("Benjamin Mugnier <benjamin.mugnier@foss.st.com>");
> +MODULE_AUTHOR("Mickael Guene <mickael.guene@st.com>");
> +MODULE_AUTHOR("Sylvain Petinot <sylvain.petinot@foss.st.com>");
> +MODULE_AUTHOR("Sergey Lebedev <lsa.uz@pm.me>");
> +MODULE_DESCRIPTION("VD55G0 camera subdev driver");
> +MODULE_LICENSE("GPL");

-- 
Regards,

Sakari Ailus

  reply	other threads:[~2026-11-09 11:36 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-09  9:34 [PATCH v3 0/4] media: Add the ST VD55G0 global shutter sensor Sergey Lebedev
2026-11-09  9:34 ` [PATCH v3 1/4] dt-bindings: media: i2c: st,vd55g1: Add ST VD55G0 Sergey Lebedev
2026-11-09 10:28   ` Benjamin Mugnier
2026-11-09 10:36     ` Sergey Lebedev
2026-11-09  9:34 ` [PATCH v3 2/4] media: i2c: Add ST VD55G0 global shutter sensor driver Sergey Lebedev
2026-11-09 11:36   ` Sakari Ailus [this message]
2026-11-09  9:34 ` [PATCH v3 3/4] media: ipu-bridge: Add ST VD55G0 Sergey Lebedev
2026-11-09  9:34 ` [PATCH v3 4/4] media: ipu-bridge: Add the Surface Pro 9 and 11 infrared illuminator Sergey Lebedev
2026-11-09 11:39   ` Sakari Ailus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=avGwRaKSqXdtXkII@kekkonen.localdomain \
    --to=sakari.ailus@linux.intel.com \
    --cc=benjamin.mugnier@foss.st.com \
    --cc=conor+dt@kernel.org \
    --cc=dan.scally@ideasonboard.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dmanresa@gmail.com \
    --cc=fernandorimoli11@gmail.com \
    --cc=fqwqf@fqwqf.xyz \
    --cc=geocausa@gmail.com \
    --cc=hansg@kernel.org \
    --cc=hao.yao@intel.com \
    --cc=krzk+dt@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=lsa.uz@pm.me \
    --cc=mchehab@kernel.org \
    --cc=pm@petermarshall.ca \
    --cc=robh@kernel.org \
    --cc=sylvain.petinot@foss.st.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®