diff mbox series

[2/2] media: i2c: Add OV1063x sensor driver

Message ID 20210104053945.12409-3-laurent.pinchart@ideasonboard.com (mailing list archive)
State New, archived
Headers show
Series media: Driver for OV1063x camera sensor | expand

Commit Message

Laurent Pinchart Jan. 4, 2021, 5:39 a.m. UTC
Add a new V4L2 subdev driver for the OmniVision OV10633 and OV10635
camera sensors. The work is based on the driver from the TI BSP, itself
based on original work by Phil Edworthy posted to the linux-media
mailing list ([1]). This version of the code is a large rewrite of many
parts.

[1] http://www.spinics.net/lists/linux-media/msg64347.html

Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
Signed-off-by: Benoit Parrot <bparrot@ti.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 MAINTAINERS                      |    2 +
 drivers/media/i2c/Kconfig        |   12 +
 drivers/media/i2c/Makefile       |    1 +
 drivers/media/i2c/ov1063x.c      | 1692 ++++++++++++++++++++++++++++++
 drivers/media/i2c/ov1063x_regs.h |  626 +++++++++++
 5 files changed, 2333 insertions(+)
 create mode 100644 drivers/media/i2c/ov1063x.c
 create mode 100644 drivers/media/i2c/ov1063x_regs.h

Comments

Sakari Ailus Jan. 4, 2021, 11:41 a.m. UTC | #1
Hi Laurent,

Thanks for the patchset.

On Mon, Jan 04, 2021 at 07:39:45AM +0200, Laurent Pinchart wrote:
> Add a new V4L2 subdev driver for the OmniVision OV10633 and OV10635
> camera sensors. The work is based on the driver from the TI BSP, itself
> based on original work by Phil Edworthy posted to the linux-media
> mailing list ([1]). This version of the code is a large rewrite of many
> parts.

The driver seems generally quite nice. It doesn't check known-good link
frequencies are not defined in bindings nor checked by the driver. Could
you add them?

Same or the assigned-clock-rates in bindings.

Please see more comments below.

> 
> [1] http://www.spinics.net/lists/linux-media/msg64347.html
> 
> Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
> Signed-off-by: Benoit Parrot <bparrot@ti.com>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  MAINTAINERS                      |    2 +
>  drivers/media/i2c/Kconfig        |   12 +
>  drivers/media/i2c/Makefile       |    1 +
>  drivers/media/i2c/ov1063x.c      | 1692 ++++++++++++++++++++++++++++++
>  drivers/media/i2c/ov1063x_regs.h |  626 +++++++++++
>  5 files changed, 2333 insertions(+)
>  create mode 100644 drivers/media/i2c/ov1063x.c
>  create mode 100644 drivers/media/i2c/ov1063x_regs.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9dc3a7d75460..4b94061130cf 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -12873,6 +12873,8 @@ L:	linux-media@vger.kernel.org
>  S:	Maintained
>  T:	git git://linuxtv.org/media_tree.git
>  F:	Documentation/devicetree/bindings/media/i2c/ov1063x.yaml
> +F:	drivers/media/i2c/ov1063x.c
> +F:	drivers/media/i2c/ov1063x_regs.h
>  
>  OMNIVISION OV13858 SENSOR DRIVER
>  M:	Sakari Ailus <sakari.ailus@linux.intel.com>
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 878f66ef2719..84a97989775e 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -1050,6 +1050,18 @@ config VIDEO_OV9650
>  	  This is a V4L2 sensor driver for the Omnivision
>  	  OV9650 and OV9652 camera sensors.
>  
> +config VIDEO_OV10633
> +	tristate "OmniVision OV10633/OV10635 sensor support"
> +	depends on I2C && VIDEO_V4L2
> +	depends on GPIOLIB && OF
> +	select MEDIA_CONTROLLER
> +	select REGMAP_I2C
> +	select V4L2_FWNODE
> +	select VIDEO_V4L2_SUBDEV_API
> +	help
> +	  This is a Video4Linux2 driver for the OmniVision
> +	  OV10633 and OV10635 camera sensors.
> +
>  config VIDEO_OV13858
>  	tristate "OmniVision OV13858 sensor support"
>  	depends on I2C && VIDEO_V4L2
> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> index f0a77473979d..6eef97e2423d 100644
> --- a/drivers/media/i2c/Makefile
> +++ b/drivers/media/i2c/Makefile
> @@ -83,6 +83,7 @@ obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
>  obj-$(CONFIG_VIDEO_OV8856) += ov8856.o
>  obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
>  obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
> +obj-$(CONFIG_VIDEO_OV10633) += ov1063x.o
>  obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
>  obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
>  obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
> diff --git a/drivers/media/i2c/ov1063x.c b/drivers/media/i2c/ov1063x.c
> new file mode 100644
> index 000000000000..5b25ed5e766b
> --- /dev/null
> +++ b/drivers/media/i2c/ov1063x.c
> @@ -0,0 +1,1692 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * OmniVision OV10633/OV10635 Camera Driver
> + *
> + * Based on the original driver written by Phil Edworthy.
> + * Copyright (C) 2013 Phil Edworthy
> + * Copyright (C) 2013 Renesas Electronics
> + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
> + * Copyright (C) 2020 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/v4l2-mediabus.h>
> +#include <linux/videodev2.h>
> +
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-fwnode.h>
> +#include <media/v4l2-subdev.h>
> +
> +/* Register definitions */
> +#define OV1063X_REG_8BIT(n)			((1 << 16) | (n))
> +#define OV1063X_REG_16BIT(n)			((2 << 16) | (n))
> +#define OV1063X_REG_24BIT(n)			((3 << 16) | (n))
> +#define OV1063X_REG_32BIT(n)			((4 << 16) | (n))
> +#define OV1063X_REG_SIZE_SHIFT			16
> +#define OV1063X_REG_ADDR_MASK			0xffff
> +
> +#define OV1063X_STREAM_MODE			OV1063X_REG_8BIT(0x0100)
> +#define OV1063X_STREAM_MODE_ON			BIT(0)
> +#define OV1063X_SOFTWARE_RESET			OV1063X_REG_8BIT(0x0103)
> +
> +#define OV1063X_SC_CMMN_PLL_CTRL0		OV1063X_REG_8BIT(0x3003)
> +#define OV1063X_SC_CMMN_PLL_SCLK_CP(n)		((n) << 6)
> +#define OV1063X_SC_CMMN_PLL_SCLK_MULTI(n)	((n) << 0)
> +#define OV1063X_SC_CMMN_PLL_CTRL1		OV1063X_REG_8BIT(0x3004)
> +#define OV1063X_SC_CMMN_PLL_SCLK_BYPASS		BIT(7)
> +#define OV1063X_SC_CMMN_PLL_SCLK_PRE_DIV(n)	((n) << 4)	/* /1, /1.5, /2, /3, /4, /5, /6, /7 */
> +#define OV1063X_SC_CMMN_PLL_SCLK_CP2(n)		((n) << 3)
> +#define OV1063X_SC_CMMN_PLL_SCLK_DIV(n)		((n) << 0)	/* Divider = 2 * (1 + n) */
> +#define OV1063X_SC_CMMN_PLL_CTRL2		OV1063X_REG_8BIT(0x3005)
> +#define OV1063X_SC_CMMN_PLL_PCLK_CP(n)		((n) << 6)
> +#define OV1063X_SC_CMMN_PLL_PCLK_MULTI(n)	((n) << 0)
> +#define OV1063X_SC_CMMN_PLL_CTRL3		OV1063X_REG_8BIT(0x3006)
> +#define OV1063X_SC_CMMN_PLL_PCLK_BYPASS		BIT(7)
> +#define OV1063X_SC_CMMN_PLL_PCLK_PRE_DIV(n)	((n) << 4)	/* /1, /1.5, /2, /3, /4, /5, /6, /7 */
> +#define OV1063X_SC_CMMN_PLL_PCLK_CP2(n)		((n) << 3)
> +#define OV1063X_SC_CMMN_PLL_PCLK_DIV(n)		((n) << 0)	/* Divider = 2 * (1 + n) */
> +#define OV1063X_SC_CMMN_PCLK_DIV_CTRL		OV1063X_REG_8BIT(0x3007)
> +#define OV1063X_PID				OV1063X_REG_16BIT(0x300a)
> +#define OV1063X_SC_CMMN_SCCB_ID			OV1063X_REG_8BIT(0x300c)
> +#define OV1063X_SC_CMMN_SCCB_ID_ADDR(n)		((n) << 1)
> +#define OV1063X_SC_CMMN_SCCB_ID_SEL		BIT(0)
> +#define OV1063X_SC_CMMN_PAD			OV1063X_REG_8BIT(0x3011)
> +#define OV1063X_SC_CMMN_PAD_DRIVE(n)		((n) << 6)
> +#define OV1063X_SC_CMMN_CLKRST0			OV1063X_REG_8BIT(0x301a)
> +#define OV1063X_SC_CMMN_CLKRST0_SCLK		GENMASK(7, 4)
> +#define OV1063X_SC_CMMN_CLKRST0_RST		GENMASK(3, 0)
> +#define OV1063X_SC_CMMN_CLKRST1			OV1063X_REG_8BIT(0x301b)
> +#define OV1063X_SC_CMMN_CLKRST1_SCLK		GENMASK(7, 4)
> +#define OV1063X_SC_CMMN_CLKRST1_RST		GENMASK(3, 0)
> +#define OV1063X_SC_CMMN_CLKRST2			OV1063X_REG_8BIT(0x301c)
> +#define OV1063X_SC_CMMN_CLKRST2_PCLK_DVP	BIT(7)
> +#define OV1063X_SC_CMMN_CLKRST2_SCLK		GENMASK(6, 4)
> +#define OV1063X_SC_CMMN_CLKRST2_RST_DVP		BIT(3)
> +#define OV1063X_SC_CMMN_CLKRST2_RST		GENMASK(2, 0)
> +#define OV1063X_SC_CMMN_CLOCK_SEL		OV1063X_REG_8BIT(0x3020)
> +#define OV1063X_SC_CMMN_MISC_CTRL		OV1063X_REG_8BIT(0x3021)
> +#define OV1063X_SC_CMMN_MISC_CTRL_PCLK_INV	BIT(7)
> +#define OV1063X_SC_CMMN_MISC_CTRL_SCLK_INV	BIT(6)
> +#define OV1063X_SC_CMMN_MISC_CTRL_SCLK2X_INV	BIT(5)
> +#define OV1063X_SC_CMMN_MISC_CTRL_CEN_GLOBAL_O	BIT(0)
> +#define OV1063X_SC_CMMN_CORE_CTRL_1		OV1063X_REG_8BIT(0x3022)
> +#define OV1063X_SC_CMMN_CORE_CTRL_2		OV1063X_REG_8BIT(0x3023)
> +#define OV1063X_SC_CMMN_CORE_CTRL_BIST_EN	BIT(5)
> +#define OV1063X_SC_CMMN_CORE_CTRL_CLK_SWITCH	BIT(4)
> +#define OV1063X_SC_CMMN_CORE_CTRL_3		OV1063X_REG_8BIT(0x3024)
> +#define OV1063X_SC_CMMN_CORE_CTRL_RAW_LONG	(0U << 4)
> +#define OV1063X_SC_CMMN_CORE_CTRL_RAW_SHORT	(1U << 4)
> +#define OV1063X_SC_CMMN_CORE_CTRL_RAW_LONG_SHORT	(2U << 4)
> +#define OV1063X_SC_CMMN_CORE_CTRL_RAW_COMBINED	(0U << 4)
> +#define OV1063X_SC_CMMN_CORE_CTRL_YUV_LONG	(1U << 1)
> +#define OV1063X_SC_CMMN_CORE_CTRL_YUV_SHORT	(2U << 1)
> +#define OV1063X_SC_CMMN_CORE_CTRL_PCLK_SYS	(0U << 0)	/* PCLK from system PLL */
> +#define OV1063X_SC_CMMN_CORE_CTRL_PCLK_SEC	(1U << 0)	/* PCLK from secondary PLL */
> +#define OV1063X_SC_CMMN_CORE_CTRL1		OV1063X_REG_8BIT(0x3025)
> +#define OV1063X_SC_CMMN_PWDN_CTRL2		OV1063X_REG_8BIT(0x302d)
> +#define OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG1	BIT(3)
> +#define OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG2	BIT(2)
> +#define OV1063X_SC_CMMN_PWDN_CTRL2_RST_ISP	BIT(1)
> +#define OV1063X_SC_CMMN_PWDN_CTRL2_SEQUENCE	BIT(0)
> +#define OV1063X_SC_CMMN_SCLK2X_SEL		OV1063X_REG_8BIT(0x3033)
> +#define OV1063X_SC_CMMN_SCLK2X_SEL_DIV2		(1U << 2)
> +#define OV1063X_SC_CMMN_SCLK2X_SEL_DIV4		(2U << 2)
> +#define OV1063X_SC_SOC_CLKRST7			OV1063X_REG_8BIT(0x3042)
> +#define OV1063X_SC_SOC_CLKRST7_SCLK		GENMASK(7, 4)
> +#define OV1063X_SC_SOC_CLKRST7_RST		GENMASK(3, 0)
> +
> +#define OV1063X_AEC_PK_MANUAL			OV1063X_REG_8BIT(0x3503)
> +#define OV1063X_AEC_PK_MANUAL_GAIN_DELAY	BIT(5)
> +#define OV1063X_AEC_PK_MANUAL_DELAY		BIT(4)
> +#define OV1063X_AEC_PK_MAN_DONE			OV1063X_REG_8BIT(0x3504)
> +#define OV1063X_AEC_PK_MAN_DONE_AEC_DONE	BIT(0)
> +
> +#define OV1063X_ANA_ADC1			OV1063X_REG_8BIT(0x3600)
> +#define OV1063X_ANA_ADC2			OV1063X_REG_8BIT(0x3601)
> +#define OV1063X_ANA_ADC3			OV1063X_REG_8BIT(0x3602)
> +#define OV1063X_ANA_ADC4			OV1063X_REG_8BIT(0x3603)
> +#define OV1063X_ANA_ANALOG1			OV1063X_REG_8BIT(0x3610)
> +#define OV1063X_ANA_ANALOG2			OV1063X_REG_8BIT(0x3611)
> +#define OV1063X_ANA_ANALOG3			OV1063X_REG_8BIT(0x3612)
> +#define OV1063X_ANA_ARRAY1			OV1063X_REG_8BIT(0x3621)
> +#define OV1063X_ANA_ARRAY1_FULL			(0 << 3)
> +#define OV1063X_ANA_ARRAY1_CROP_768		(1 << 3)
> +#define OV1063X_ANA_ARRAY1_CROP_656		(2 << 3)
> +#define OV1063X_ANA_ARRAY1_DELAY(n)		((n) << 0)
> +#define OV1063X_ANA_PWC1			OV1063X_REG_8BIT(0x3630)
> +#define OV1063X_ANA_PWC2			OV1063X_REG_8BIT(0x3631)
> +#define OV1063X_ANA_PWC3			OV1063X_REG_8BIT(0x3632)
> +#define OV1063X_ANA_PWC4			OV1063X_REG_8BIT(0x3633)
> +
> +#define OV1063X_SENSOR_RSTGOLOW			OV1063X_REG_8BIT(0x3702)
> +#define OV1063X_SENSOR_HLDWIDTH			OV1063X_REG_8BIT(0x3703)
> +#define OV1063X_SENSOR_TXWIDTH			OV1063X_REG_8BIT(0x3704)
> +#define OV1063X_SENSOR_REG9			OV1063X_REG_8BIT(0x3709)
> +#define OV1063X_SENSOR_REGD			OV1063X_REG_8BIT(0x370d)
> +#define OV1063X_SENSOR_RSTYZ_GOLOW		OV1063X_REG_16BIT(0x3712)
> +#define OV1063X_SENSOR_EQ_GOLOW			OV1063X_REG_8BIT(0x3714)
> +#define OV1063X_SENSOR_REG15			OV1063X_REG_8BIT(0x3715)
> +#define OV1063X_SENSOR_BITSW_GO			OV1063X_REG_16BIT(0x371c)
> +
> +#define OV1063X_TIMING_X_START_ADDR		OV1063X_REG_16BIT(0x3800)
> +#define OV1063X_TIMING_Y_START_ADDR		OV1063X_REG_16BIT(0x3802)
> +#define OV1063X_TIMING_X_END_ADDR		OV1063X_REG_16BIT(0x3804)
> +#define OV1063X_TIMING_Y_END_ADDR		OV1063X_REG_16BIT(0x3806)
> +#define OV1063X_TIMING_X_OUTPUT_SIZE		OV1063X_REG_16BIT(0x3808)
> +#define OV1063X_TIMING_Y_OUTPUT_SIZE		OV1063X_REG_16BIT(0x380a)
> +#define OV1063X_TIMING_HTS			OV1063X_REG_16BIT(0x380c)
> +#define OV1063X_TIMING_VTS			OV1063X_REG_16BIT(0x380e)
> +#define OV1063X_TIMING_ISP_X_WIN		OV1063X_REG_16BIT(0x3810)
> +#define OV1063X_TIMING_ISP_Y_WIN		OV1063X_REG_16BIT(0x3812)
> +#define OV1063X_TIMING_CTRL15			OV1063X_REG_8BIT(0x3815)
> +#define OV1063X_TIMING_CTRL15_BLACK_LINE_HREF	BIT(7)
> +#define OV1063X_TIMING_CTRL15_RIP_SOF		BIT(5)
> +#define OV1063X_TIMING_CTRL15_BLACK_LINES(n)	((n) << 0)
> +#define OV1063X_TIMING_CTRL1C			OV1063X_REG_8BIT(0x381c)
> +#define OV1063X_TIMING_CTRL1C_VFLIP_DIG		BIT(7)
> +#define OV1063X_TIMING_CTRL1C_VFLIP_ARRAY	BIT(6)
> +#define OV1063X_TIMING_CTRL1C_VSUB4		BIT(1)
> +#define OV1063X_TIMING_CTRL1C_VSUB2		BIT(0)
> +#define OV1063X_TIMING_CTRL1D			OV1063X_REG_8BIT(0x381d)
> +#define OV1063X_TIMING_CTRL1D_VFLIP_BLACK_LINE	BIT(7)
> +#define OV1063X_TIMING_CTRL1D_WDR		BIT(6)
> +#define OV1063X_TIMING_CTRL1D_HFLIP_DIG		BIT(1)
> +#define OV1063X_TIMING_CTRL1D_HFLIP_ARRAY	BIT(0)
> +#define OV1063X_VSTART_OFFSET			OV1063X_REG_16BIT(0x381e)
> +
> +#define OV1063X_START_LINE			OV1063X_REG_8BIT(0x4001)
> +#define OV1063X_LINE_NUM			OV1063X_REG_8BIT(0x4004)	/* Black lines */
> +#define OV1063X_BLC_CTRL05			OV1063X_REG_8BIT(0x4005)
> +#define OV1063X_BLC_CTRL05_ONE_LINE_MODE	BIT(5)
> +#define OV1063X_BLC_CTRL05_REMOVE_BLACK_LINE	BIT(4)
> +#define OV1063X_BLC_CTRL05_ONE_MAN_OFFSET_MODE	BIT(3)
> +#define OV1063X_BLC_CTRL05_BL_RBLUE_RVS		BIT(2)
> +#define OV1063X_BLC_CTRL05_BLC_ALWAYS_DO	BIT(1)
> +#define OV1063X_BLC_AVG_CTRL1			OV1063X_REG_8BIT(0x4050)
> +#define OV1063X_BLC_AVG_CTRL2			OV1063X_REG_8BIT(0x4051)
> +#define OV1063X_BLC_OFFSET_TOP_LIMIT		OV1063X_REG_16BIT(0x4056)
> +#define OV1063X_BLC_OFFSET_BOT_LIMIT		OV1063X_REG_16BIT(0x4058)
> +#define OV1063X_BLC_CTRL5A			OV1063X_REG_8BIT(0x405a)
> +
> +#define OV1063X_FC_R2				OV1063X_REG_8BIT(0x4202)
> +
> +#define OV1063X_FORMAT_CTRL00			OV1063X_REG_8BIT(0x4300)
> +#define OV1063X_FORMAT_YUYV			0x38
> +#define OV1063X_FORMAT_YYYU			0x39
> +#define OV1063X_FORMAT_UYVY			0x3a
> +#define OV1063X_FORMAT_VYUY			0x3b
> +#define OV1063X_FORMAT_YMAX			OV1063X_REG_16BIT(0x4302)
> +#define OV1063X_FORMAT_YMIN			OV1063X_REG_16BIT(0x4304)
> +#define OV1063X_FORMAT_UMAX			OV1063X_REG_16BIT(0x4306)
> +#define OV1063X_FORMAT_UMIN			OV1063X_REG_16BIT(0x4308)
> +
> +#define OV1063X_VFIFO_LLEN_FIRS1_SEL		OV1063X_REG_8BIT(0x4605)
> +#define OV1063X_VFIFO_LLEN_FIRS1_SEL_8B_YUV	BIT(3)
> +#define OV1063X_VFIFO_LINE_LENGTH_MAN		OV1063X_REG_16BIT(0x4606)
> +#define OV1063X_VFIFO_READ_START		OV1063X_REG_16BIT(0x4608)
> +#define OV1063X_VFIFO_HSYNC_START_POSITION	OV1063X_REG_16BIT(0x460a)
> +#define OV1063X_VFIFO_HSYNC_CTRL		OV1063X_REG_8BIT(0x460c)
> +#define OV1063X_VFIFO_HSYNC_CTRL_HEADER_WIDTH(n)	((n) << 4)
> +#define OV1063X_VFIFO_HSYNC_CTRL_TRAILER_WIDTH(n)	((n) << 0)
> +#define OV1063X_VFIFO_EMBD_LINE_CTRL		OV1063X_REG_8BIT(0x460e)
> +#define OV1063X_VFIFO_EMBD_LINE_CTRL_SOF_CLR_RAM	BIT(3)
> +#define OV1063X_VFIFO_EMBD_LINE_CTRL_ST_MOD	BIT(2)
> +#define OV1063X_VFIFO_EMBD_LINE_CTRL_EMBD_ROM	BIT(1)
> +#define OV1063X_VFIFO_EMBD_LINE_CTRL_EMBD_EN	BIT(0)
> +#define OV1063X_VFIFO_EMBD_LINE_NUM		OV1063X_REG_8BIT(0x460f)
> +#define OV1063X_ROI_CTRL0			OV1063X_REG_8BIT(0x4620)
> +#define OV1063X_ROI_CTRL0_SYNC_BYP		BIT(7)
> +#define OV1063X_ROI_CTRL0_FR_COMP		BIT(6)
> +#define OV1063X_ROI_CTRL0_FULL_DAT_MOD		BIT(5)
> +#define OV1063X_ROI_CTRL0_EN_3			BIT(3)
> +#define OV1063X_ROI_CTRL0_EN_2			BIT(2)
> +#define OV1063X_ROI_CTRL0_EN_1			BIT(1)
> +#define OV1063X_ROI_CTRL0_FUNC_E		BIT(0)
> +
> +#define OV1063X_DVP_MOD_SEL			OV1063X_REG_8BIT(0x4700)
> +#define OV1063X_DVP_MOD_SEL_CCIR_V		BIT(3)
> +#define OV1063X_DVP_MOD_SEL_CCIR_F		BIT(2)
> +#define OV1063X_DVP_MOD_SEL_CCIR_656		BIT(1)
> +#define OV1063X_DVP_MOD_SEL_HSYNC		BIT(0)
> +#define OV1063X_DVP_VSYNC_WIDTH			OV1063X_REG_8BIT(0x4701)
> +#define OV1063X_DVP_HSYVSY_NEG_WIDTH		OV1063X_REG_16BIT(0x4702)
> +#define OV1063X_DVP_VSYNC_MODE			OV1063X_REG_8BIT(0x4704)
> +#define OV1063X_DVP_VSYNC_MODE_VSYNCOUT_SEL(n)	((n) << 2)
> +#define OV1063X_DVP_VSYNC_MODE_VSYNC3_MOD	BIT(1)
> +#define OV1063X_DVP_VSYNC_MODE_VSYNC2_MOD	BIT(0)
> +#define OV1063X_DVP_EOF_VSYNC_DELAY		OV1063X_REG_24BIT(0x4705)
> +
> +#define OV1063X_ISP_RW00			OV1063X_REG_8BIT(0x5000)
> +#define OV1063X_ISP_RW00_COLOR_MATRIX_EN	BIT(7)
> +#define OV1063X_ISP_RW00_COLOR_INTERP_EN	BIT(6)
> +#define OV1063X_ISP_RW00_DENOISE_EN		BIT(5)
> +#define OV1063X_ISP_RW00_WHITE_DPC_EN		BIT(4)	/* White defect pixel correction enable */
> +#define OV1063X_ISP_RW00_BLACK_DPC_EN		BIT(3)	/* Black defect pixel connection enable */
> +#define OV1063X_ISP_RW00_AWB_STATS_EN		BIT(2)
> +#define OV1063X_ISP_RW00_AWB_GAIN_EN		BIT(1)
> +#define OV1063X_ISP_RW00_LSC_EN			BIT(0)
> +#define OV1063X_ISP_RW01			OV1063X_REG_8BIT(0x5001)
> +#define OV1063X_ISP_RW01_DATA_WEIGHT_SYNC_EN	BIT(7)
> +#define OV1063X_ISP_RW01_BLACK_WHITE_MODE_EN	BIT(6)
> +#define OV1063X_ISP_RW01_DARK_LEVEL_FILTER_EN	BIT(5)
> +#define OV1063X_ISP_RW01_BUFFER_CONTROL_EN	BIT(4)
> +#define OV1063X_ISP_RW01_AEC_EN			BIT(3)
> +#define OV1063X_ISP_RW01_TONE_MAPPING_EN	BIT(2)
> +#define OV1063X_ISP_RW01_NORMALIZE_EN		BIT(1)
> +#define OV1063X_ISP_RW01_LONG_SHORT_COMB_EN	BIT(0)
> +#define OV1063X_ISP_RW02			OV1063X_REG_8BIT(0x5002)
> +#define OV1063X_ISP_RW02_DIGITAL_GAIN_EN	BIT(3)
> +#define OV1063X_ISP_RW02_WINDOW_BORDER_CUT_EN	BIT(2)
> +#define OV1063X_ISP_RW02_DITHERING_EN		BIT(1)
> +#define OV1063X_ISP_RW02_LSLS			(0U << 0)
> +#define OV1063X_ISP_RW02_SLSL			(1U << 0)
> +#define OV1063X_ISP_RW05			OV1063X_REG_8BIT(0x5005)
> +#define OV1063X_ISP_RW05_VERT_SUB_EN		BIT(7)	/* Enable vertical subsampling */
> +#define OV1063X_ISP_RW05_LSC_CENTER_AUTO	BIT(6)	/* Set LSC center automatically based on image window */
> +#define OV1063X_ISP_RW05_SUB_OUT_ROW_2ND	BIT(5)	/* Output 2nd (1) or 1st (0) row when skipping */
> +#define OV1063X_ISP_RW05_SUB_OUT_COL_2ND	BIT(4)	/* Output 2nd (1) or 1st (0) column when skipping */
> +#define OV1063X_ISP_RW05_SUB_AVG		BIT(3)	/* Average (1) or sum (0) when binning */
> +#define OV1063X_ISP_RW05_SUB_G_DROP		BIT(2)	/* Skip (1) or bin (0) Green / Y */
> +#define OV1063X_ISP_RW05_SUB_RB_DROP		BIT(1)	/* Skip (1) or bin (0) Red Blue / UV */
> +#define OV1063X_ISP_RW05_SUB_ENABLE		BIT(0)	/* Enable sub-sampling */
> +#define OV1063X_ISP_RW06			OV1063X_REG_8BIT(0x5006)
> +#define OV1063X_ISP_RW06_RAW_MODE_MAN(n)	((n) << 6)
> +#define OV1063X_ISP_RW06_YUV_MODE_MAN(n)	((n) << 4)
> +#define OV1063X_ISP_RW06_RAW_MODE_MAN_EN	BIT(3)
> +#define OV1063X_ISP_RW06_YUV_MODE_MAN_EN	BIT(2)
> +#define OV1063X_ISP_CTRL3D			OV1063X_REG_8BIT(0x503d)
> +#define OV1063X_ISP_CTRL3D_TEST_PATTERN_EN	BIT(7)
> +#define OV1063X_ISP_CTRL3D_COLOR_BAR(n)		((n) << 4)
> +#define OV1063X_ISP_CTRL3D_ROLLING_BAR_EN	BIT(2)
> +#define OV1063X_ISP_CTRL3E			OV1063X_REG_8BIT(0x503e)
> +#define OV1063X_ISP_CTRL3E_SQUARE_BW		BIT(3)
> +#define OV1063X_ISP_CTRL3E_TRANSPARENT_EN	BIT(2)
> +#define OV1063X_ISP_CTRL3E_PATTERN_BARS		(0U << 0)
> +#define OV1063X_ISP_CTRL3E_PATTERN_RANDOM	(1U << 0)
> +#define OV1063X_ISP_CTRL3E_PATTERN_SQUARES	(2U << 0)
> +
> +#define OV1063X_GAIN_AWB_MAN_GAIN_B_LONG	OV1063X_REG_16BIT(0x5100)
> +#define OV1063X_GAIN_AWB_MAN_GAIN_GB_LONG	OV1063X_REG_16BIT(0x5102)
> +#define OV1063X_GAIN_AWB_MAN_GAIN_GR_LONG	OV1063X_REG_16BIT(0x5104)
> +#define OV1063X_GAIN_AWB_MAN_GAIN_R_LONG	OV1063X_REG_16BIT(0x5106)
> +#define OV1063X_GAIN_AWB_MAN_OFFSET_B_LONG	OV1063X_REG_16BIT(0x5108)
> +#define OV1063X_GAIN_AWB_MAN_OFFSET_GB_LONG	OV1063X_REG_16BIT(0x510a)
> +#define OV1063X_GAIN_AWB_MAN_OFFSET_GR_LONG	OV1063X_REG_16BIT(0x510c)
> +#define OV1063X_GAIN_AWB_MAN_OFFSET_R_LONG	OV1063X_REG_16BIT(0x510e)
> +#define OV1063X_GAIN_AWB_MAN_GAIN_B_SHORT	OV1063X_REG_16BIT(0x5110)
> +#define OV1063X_GAIN_AWB_MAN_GAIN_GB_SHORT	OV1063X_REG_16BIT(0x5112)
> +#define OV1063X_GAIN_AWB_MAN_GAIN_GR_SHORT	OV1063X_REG_16BIT(0x5114)
> +#define OV1063X_GAIN_AWB_MAN_GAIN_R_SHORT	OV1063X_REG_16BIT(0x5116)
> +#define OV1063X_GAIN_AWB_MAN_OFFSET_B_SHORT	OV1063X_REG_16BIT(0x5118)
> +#define OV1063X_GAIN_AWB_MAN_OFFSET_GB_SHORT	OV1063X_REG_16BIT(0x511a)
> +#define OV1063X_GAIN_AWB_MAN_OFFSET_GR_SHORT	OV1063X_REG_16BIT(0x511c)
> +#define OV1063X_GAIN_AWB_MAN_OFFSET_R_SHORT	OV1063X_REG_16BIT(0x511e)
> +#define OV1063X_GAIN_AWB_CTRL32			OV1063X_REG_8BIT(0x5120)
> +#define OV1063X_GAIN_AWB_CTRL32_MANUAL_EN	BIT(0)
> +
> +#define OV1063X_DNS_NOISE_Y_LIST_LONG(n)	OV1063X_REG_8BIT(0x521a + (n))
> +#define OV1063X_DNS_NOISE_UV_LIST_LONG(n)	OV1063X_REG_16BIT(0x5222 + (n) * 2)
> +#define OV1063X_DNS_GBGR_EXTRA_SHORT		OV1063X_REG_8BIT(0x5241)
> +#define OV1063X_DNS_NOISE_Y_LIST_SHORT(n)	OV1063X_REG_8BIT(0x5242 + (n))
> +#define OV1063X_DNS_NOISE_UV_LIST_SHORT(n)	OV1063X_REG_16BIT(0x5249 + (n) * 2)
> +#define OV1063X_CIP_UNSHARPEN_MASK_LONG(n)	OV1063X_REG_8BIT(0x5288 + (n))
> +#define OV1063X_CIP_MAX_SHARPEN_LONG		OV1063X_REG_8BIT(0x528d)
> +#define OV1063X_CIP_SHARPEN_ALPHA_LONG		OV1063X_REG_8BIT(0x5293)
> +#define OV1063X_CIP_UNSHARPEN_MASK_SHORT(n)	OV1063X_REG_8BIT(0x52c8 + (n))
> +#define OV1063X_CIP_MAX_SHARPEN_SHORT		OV1063X_REG_8BIT(0x52cd)
> +#define OV1063X_CIP_SHARPEN_ALPHA_SHORT		OV1063X_REG_8BIT(0x52d3)
> +#define OV1063X_CIP_HFREQ_COEF_SHORT		OV1063X_REG_8BIT(0x52d7)
> +
> +#define OV1063X_LLF_MAX_LOW_LEVEL		OV1063X_REG_16BIT(0x5381)
> +
> +#define OV1063X_AWB_CT_CTRL1			OV1063X_REG_8BIT(0x5581)
> +#define OV1063X_AWB_CT_CTRL1_GAIN_STEP_NORMAL(n)	((n) << 6)
> +#define OV1063X_AWB_CT_CTRL1_GAIN_STEP_FAST(n)	((n) << 4)
> +#define OV1063X_AWB_CT_CTRL1_SCALE_LONG_2X	(0 << 2)
> +#define OV1063X_AWB_CT_CTRL1_SCALE_LONG_4X	(1 << 2)
> +#define OV1063X_AWB_CT_CTRL1_SCALE_LONG_8X	(2 << 2)
> +#define OV1063X_AWB_M_RNG_LONG			OV1063X_REG_8BIT(0x5586)
> +#define OV1063X_AWB_L_XRNG_LONG			OV1063X_REG_8BIT(0x5587)
> +#define OV1063X_AWB_H_YRNG_LONG			OV1063X_REG_8BIT(0x5588)
> +#define OV1063X_AWB_M_X_LONG			OV1063X_REG_8BIT(0x5589)
> +#define OV1063X_AWB_M_Y_LONG			OV1063X_REG_8BIT(0x558a)
> +#define OV1063X_AWB_L_K_LONG			OV1063X_REG_8BIT(0x558b)
> +#define OV1063X_AWB_H_K_LONG			OV1063X_REG_8BIT(0x558c)
> +#define OV1063X_AWB_H_LMT_LONG			OV1063X_REG_8BIT(0x558d)
> +#define OV1063X_AWB_L_LMT_LONG			OV1063X_REG_8BIT(0x558e)
> +#define OV1063X_AWB_DATA_ULMT_LONG		OV1063X_REG_8BIT(0x5591)
> +#define OV1063X_AWB_DATA_LLMT_LONG		OV1063X_REG_8BIT(0x5592)
> +#define OV1063X_AWB_M_RNG_SHORT			OV1063X_REG_8BIT(0x559f)
> +#define OV1063X_AWB_L_XRNG_SHORT		OV1063X_REG_8BIT(0x55a0)
> +#define OV1063X_AWB_H_YRNG_SHORT		OV1063X_REG_8BIT(0x55a1)
> +#define OV1063X_AWB_M_X_SHORT			OV1063X_REG_8BIT(0x55a2)
> +#define OV1063X_AWB_M_Y_SHORT			OV1063X_REG_8BIT(0x55a3)
> +#define OV1063X_AWB_L_K_SHORT			OV1063X_REG_8BIT(0x55a4)
> +#define OV1063X_AWB_H_K_SHORT			OV1063X_REG_8BIT(0x55a5)
> +#define OV1063X_AWB_H_LMT_SHORT			OV1063X_REG_8BIT(0x55a6)
> +#define OV1063X_AWB_L_LMT_SHORT			OV1063X_REG_8BIT(0x55a7)
> +#define OV1063X_AWB_DATA_ULMT_SHORT		OV1063X_REG_8BIT(0x55aa)
> +#define OV1063X_AWB_DATA_LLMT_SHORT		OV1063X_REG_8BIT(0x55ab)
> +
> +#define OV1063X_AEC_CTRL07			OV1063X_REG_16BIT(0x5607)
> +#define OV1063X_AEC_WIN_LEFT_LONG		OV1063X_REG_16BIT(0x5609)
> +#define OV1063X_AEC_WIN_LEFT_SHORT		OV1063X_REG_16BIT(0x560b)
> +#define OV1063X_AEC_WIN_TOP_LONG		OV1063X_REG_16BIT(0x560d)
> +#define OV1063X_AEC_WIN_TOP_SHORT		OV1063X_REG_16BIT(0x560f)
> +#define OV1063X_AEC_WIN_WIDTH_LONG		OV1063X_REG_16BIT(0x5611)
> +#define OV1063X_AEC_WIN_WIDTH_SHORT		OV1063X_REG_16BIT(0x5613)
> +#define OV1063X_AEC_WIN_HEIGHT_LONG		OV1063X_REG_16BIT(0x5615)
> +#define OV1063X_AEC_WIN_HEIGHT_SHORT		OV1063X_REG_16BIT(0x5617)
> +#define OV1063X_AEC_WEIGHT_SHORT(n)		OV1063X_REG_8BIT(0x563b + (n))
> +#define OV1063X_AEC_FINAL_SATURATE_THRESH	OV1063X_REG_16BIT(0x5651)
> +#define OV1063X_AEC_CTRLD0			OV1063X_REG_8BIT(0x56d0)
> +#define OV1063X_AEC_CTRLD0_R_MAN_EN(n)		((n) << 0)
> +#define OV1063X_AEC_CTRLD5			OV1063X_REG_32BIT(0x56d5)	/* r_exp_l_m */
> +#define OV1063X_AEC_CTRLD9			OV1063X_REG_32BIT(0x56d9)	/* r_exp_s_m */
> +#define OV1063X_AEC_CTRLE8			OV1063X_REG_16BIT(0x56e8)	/* r_snrgain_l_m */
> +#define OV1063X_AEC_CTRLEA			OV1063X_REG_16BIT(0x56ea)	/* r_snrgain_s_m */
> +
> +#define OV1063X_TPM_CTRL0			OV1063X_REG_8BIT(0x6706)
> +#define OV1063X_TPM_CTRL0_CLK_DIV(n)		((n) << 0)
> +
> +#define OV1063X_GROUP_WRITER_COMMAND		OV1063X_REG_8BIT(0x6f00)
> +#define OV1063X_GROUP_WRITER_COMMAND_OP(n)	((n) << 6)
> +#define OV1063X_GROUP_WRITER_COMMAND_ID(n)	((n) << 4)
> +#define OV1063X_GROUP_WRITER_COMMAND_EN		(3U << 0)
> +#define OV1063X_PARI_ADDR_MIN			OV1063X_REG_16BIT(0x6f06)
> +#define OV1063X_PARI_ADDR_MAX			OV1063X_REG_16BIT(0x6f0a)
> +
> +#define OV1063X_EMB_LINE_EN			OV1063X_REG_8BIT(0x6800)
> +#define OV1063X_EMB_LINE_EN_ENABLE		BIT(0)
> +#define OV1063X_EMB_SIZE_MANU_EN		OV1063X_REG_8BIT(0x6804)
> +#define OV1063X_EMB_SIZE_EN_ENABLE		BIT(0)
> +#define OV1063X_EMB_SIZE_MANU			OV1063X_REG_16BIT(0x6805)
> +
> +#define OV1063X_HORIZ_COLORCORRECT		OV1063X_REG_8BIT(0x6900)
> +#define OV1063X_HORIZ_COLORCORRECT_ON		BIT(0)
> +
> +#define OV1063X_AEC_TARGET_NUM			OV1063X_REG_8BIT(0xc450)
> +#define OV1063X_AEC_TARGET_NUM_AA_MODE		(1U << 0)
> +#define OV1063X_AEC_TARGET_NUM_AB_MODE		(2U << 0)
> +#define OV1063X_AEC_TARGET_NUM_ABC_MODE		(3U << 0)
> +#define OV1063X_AEC_LS_SENS_RATIO		OV1063X_REG_16BIT(0xc452)
> +#define OV1063X_AEC_NONWDR_EN			OV1063X_REG_8BIT(0xc454)
> +#define OV1063X_AEC_NONWDR_SWITCH		OV1063X_REG_8BIT(0xc455)
> +#define OV1063X_AEC_FIXED_RATIO_EN		OV1063X_REG_8BIT(0xc456)
> +#define OV1063X_AEC_GP_MODE_EN			OV1063X_REG_8BIT(0xc457)
> +#define OV1063X_AEC_NIGHT_MODE_EN		OV1063X_REG_8BIT(0xc458)
> +#define OV1063X_AEC_NIGHT_MODE_CTRL		OV1063X_REG_8BIT(0xc459)
> +#define OV1063X_AEC_NIGHT_MODE_CTRL_INSERT	BIT(0)
> +#define OV1063X_AEC_FRACTAL_EXP_EN		OV1063X_REG_8BIT(0xc45a)
> +#define OV1063X_AEC_NONLINEAR_GAIN_EN		OV1063X_REG_8BIT(0xc45b)
> +#define OV1063X_AEC_MANU_GAMMA_EN		OV1063X_REG_8BIT(0xc45c)
> +#define OV1063X_AEC_HOLD_BAND_EN		OV1063X_REG_8BIT(0xc45d)
> +#define OV1063X_AEC_BAND_FILTER_FLAG		OV1063X_REG_8BIT(0xc45e)
> +#define OV1063X_AEC_BAND_FILTER_FLAG_0HZ	(0U << 0)
> +#define OV1063X_AEC_BAND_FILTER_FLAG_60HZ	(1U << 0)
> +#define OV1063X_AEC_BAND_FILTER_FLAG_50HZ	(2U << 0)
> +#define OV1063X_AEC_BAND_FILTER_EN		OV1063X_REG_8BIT(0xc45f)
> +#define OV1063X_AEC_BAND_FILTER_SHORT		OV1063X_REG_8BIT(0xc460)
> +#define OV1063X_AEC_LESS_1BAND_EN		OV1063X_REG_8BIT(0xc461)
> +#define OV1063X_AEC_LESS_1BAND_SHORT		OV1063X_REG_8BIT(0xc462)
> +#define OV1063X_AEC_WDR_GAIN_LIMIT_EN		OV1063X_REG_8BIT(0xc463)
> +#define OV1063X_AEC_LOG_TARGET(n)		OV1063X_REG_16BIT(0xc464 + (n) * 2)
> +#define OV1063X_AEC_TARGET_LONG(n)		OV1063X_REG_8BIT(0xc46a + (n))
> +#define OV1063X_AEC_TARGET_SHORT(n)		OV1063X_REG_8BIT(0xc46d + (n))
> +#define OV1063X_AEC_MAX_SHORT_LE		OV1063X_REG_32BIT(0xc47c)
> +#define OV1063X_AEC_MAX_GAIN_LONG		OV1063X_REG_16BIT(0xc480)
> +#define OV1063X_AEC_MAX_GAIN_SHORT		OV1063X_REG_16BIT(0xc482)
> +#define OV1063X_AEC_MIN_GAIN_LONG		OV1063X_REG_16BIT(0xc484)
> +#define OV1063X_AEC_MIN_GAIN_SHORT		OV1063X_REG_16BIT(0xc486)
> +#define OV1063X_AEC_MAX_EXP_LONG		OV1063X_REG_16BIT(0xc488)
> +#define OV1063X_AEC_MAX_EXP_SHORT		OV1063X_REG_16BIT(0xc48a)
> +#define OV1063X_AEC_MIN_EXP_LONG		OV1063X_REG_16BIT(0xc48c)
> +#define OV1063X_AEC_MIN_EXP_SHORT		OV1063X_REG_16BIT(0xc48e)
> +#define OV1063X_AEC_FIXED_RATIO			OV1063X_REG_8BIT(0xc490)
> +#define OV1063X_AEC_GP_MODE_RATIO_B2A		OV1063X_REG_8BIT(0xc492)
> +#define OV1063X_AEC_GP_MODE_RATIO_C2A		OV1063X_REG_8BIT(0xc493)
> +#define OV1063X_AEC_MIN_GAMMA_LIST(n)		OV1063X_REG_16BIT(0xc498 + (n) * 2)
> +#define OV1063X_AEC_MAX_GAMMA_LIST(n)		OV1063X_REG_16BIT(0xc49e + (n) * 2)
> +#define OV1063X_AEC_DR_LIST(n)			OV1063X_REG_16BIT(0xc4a4 + (n) * 2)
> +#define OV1063X_AEC_BAND_VALUE_60HZ		OV1063X_REG_16BIT(0xc4aa)
> +#define OV1063X_AEC_BAND_VALUE_50HZ		OV1063X_REG_16BIT(0xc4ac)
> +
> +#define OV1063X_AWB_SIMPLE_MIN_NUM		OV1063X_REG_16BIT(0xc4cc)
> +#define OV1063X_AWB_CT_MIN_NUM			OV1063X_REG_16BIT(0xc4ce)
> +
> +#define OV1063X_VTS_ADDR			OV1063X_REG_16BIT(0xc518)
> +#define OV1063X_HTS_ADDR			OV1063X_REG_16BIT(0xc51a)
> +
> +#include "ov1063x_regs.h"
> +
> +/* IDs */
> +#define OV10633_VERSION_REG			0xa630
> +#define OV10635_VERSION_REG			0xa635
> +
> +enum ov1063x_model {
> +	SENSOR_OV10633,
> +	SENSOR_OV10635,
> +};
> +
> +#define OV1063X_SENSOR_WIDTH			1312
> +#define OV1063X_SENSOR_HEIGHT			814
> +
> +struct ov1063x_priv {
> +	struct device			*dev;
> +
> +	struct regmap			*regmap;
> +	struct clk			*clk;
> +	struct gpio_desc		*reset_gpio;
> +	struct gpio_desc		*pwdn_gpio;
> +
> +	int				model;
> +	const char			*name;
> +	unsigned long			clk_rate;
> +
> +	struct v4l2_subdev		subdev;
> +	struct media_pad		pad;
> +
> +	struct v4l2_ctrl_handler	hdl;
> +
> +	/*
> +	 * The streaming and format fields are protected by the control handler
> +	 * lock.
> +	 */
> +	bool				streaming;
> +	struct v4l2_rect		analog_crop;
> +	struct v4l2_rect		digital_crop;
> +	struct v4l2_mbus_framefmt	format;
> +
> +	unsigned int			fps_numerator;
> +	unsigned int			fps_denominator;
> +};
> +
> +/*
> + * TODO: Expose multiple subdevs to control cropping and subsampling separately
> + * from userspace instead of hardcoding resolutions.
> + *
> + * TODO: Resolutions with an analog crop rectangle width equal to 768 or higher
> + * don't work properly.
> + */
> +static const struct v4l2_area ov1063x_framesizes[] = {
> +	{
> +		.width		= 1280,
> +		.height		= 800,
> +	}, {
> +		.width		= 1280,
> +		.height		= 720,
> +	}, {
> +		.width		= 752,
> +		.height		= 480,
> +	}, {
> +		.width		= 640,
> +		.height		= 480,
> +	}, {
> +		.width		= 600,
> +		.height		= 400,
> +	}, {
> +		.width		= 352,
> +		.height		= 288,
> +	}, {
> +		.width		= 320,
> +		.height		= 240,
> +	},
> +};
> +
> +static const u32 ov1063x_mbus_formats[] = {
> +	MEDIA_BUS_FMT_YUYV8_2X8,
> +	MEDIA_BUS_FMT_UYVY8_2X8,
> +	MEDIA_BUS_FMT_VYUY8_2X8,
> +	MEDIA_BUS_FMT_YVYU8_2X8,
> +};
> +
> +static inline struct ov1063x_priv *to_ov1063x(struct v4l2_subdev *sd)
> +{
> +	return container_of(sd, struct ov1063x_priv, subdev);
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * Read/Write Helpers
> + */
> +
> +static int ov1063x_read(struct ov1063x_priv *priv, u32 reg, u32 *val)
> +{
> +	unsigned int len = (reg >> OV1063X_REG_SIZE_SHIFT) & 3;
> +	u16 addr = reg & OV1063X_REG_ADDR_MASK;
> +	unsigned int i;
> +	int ret;
> +
> +	*val = 0;
> +
> +	for (i = 0; i < len; ++i) {
> +		u32 byte;
> +
> +		ret = regmap_read(priv->regmap, addr, &byte);
> +		if (ret)
> +			return ret;
> +
> +		*val = (*val << 8) | byte;
> +		addr++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ov1063x_write(struct ov1063x_priv *priv, u32 reg, u32 val, int *err)
> +{
> +	unsigned int len = (reg >> OV1063X_REG_SIZE_SHIFT) & 7;
> +	u16 addr = reg & OV1063X_REG_ADDR_MASK;
> +	unsigned int shift = (len - 1) * 8;
> +	unsigned int i;
> +	int ret;
> +
> +	if (err && *err)
> +		return *err;
> +
> +	for (i = 0; i < len; ++i) {
> +		ret = regmap_write(priv->regmap, addr, (val >> shift) & 0xff);
> +		if (ret) {
> +			if (err)
> +				*err = ret;
> +			return ret;
> +		}
> +
> +		shift -= 8;
> +		addr++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ov1063x_write_array(struct ov1063x_priv *priv,
> +			       const struct ov1063x_reg *regs,
> +			       unsigned int nr_regs)
> +{
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < nr_regs; i++) {
> +		ret = ov1063x_write(priv, regs[i].reg, regs[i].val, NULL);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ov1063x_update(struct ov1063x_priv *priv, u32 reg, u32 mask, u32 val,
> +			  int *err)
> +{
> +	unsigned int len = (reg >> OV1063X_REG_SIZE_SHIFT) & 7;
> +	u16 addr = reg & OV1063X_REG_ADDR_MASK;
> +	unsigned int shift = (len - 1) * 8;
> +	unsigned int i;
> +	int ret;
> +
> +	if (err && *err)
> +		return *err;
> +
> +	for (i = 0; i < len; ++i) {
> +		ret = regmap_update_bits(priv->regmap, addr,
> +					 (mask >> shift) & 0xff,
> +					 (val >> shift) & 0xff);
> +		if (ret) {
> +			if (err)
> +				*err = ret;
> +			return ret;
> +		}
> +
> +		shift -= 8;
> +		addr++;
> +	}
> +
> +	return 0;
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * Hardware Configuration
> + */
> +
> +struct ov1063x_pll_config {
> +	unsigned int pre_div;
> +	unsigned int mult;
> +	unsigned int div;
> +	unsigned int clk_out;
> +};
> +
> +static int ov1063x_pll_setup(unsigned int clk_rate,
> +			     unsigned int *htsmin, unsigned int vts,
> +			     unsigned int fps_numerator,
> +			     unsigned int fps_denominator,
> +			     struct ov1063x_pll_config *cfg)
> +{
> +	static const unsigned int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
> +
> +	unsigned int best_pclk = UINT_MAX;
> +	unsigned int best_pre_div;
> +	unsigned int best_mult;
> +	unsigned int best_div;
> +	unsigned int best_hts;
> +	unsigned int max_pre_div;
> +	unsigned int pre_div;
> +	unsigned int hts;
> +
> +	/*
> +	 *  XVCLK --> pre-div -------> mult ----------> div --> output
> +	 * 6-27 MHz           3-27 MHz      200-500 MHz       Max 96 MHz
> +	 *
> +	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7. The
> +	 * pre_divs array stores the pre-dividers multiplied by two, indexed by
> +	 * register values.
> +	 *
> +	 * Valid multiplier values are [1, 63], stored as-is in registers.
> +	 *
> +	 * Valid divider values are 2 to 16 with a step of 2, stored in
> +	 * registers as (div / 2) - 1.
> +	 */
> +
> +	if (clk_rate < 6 * 1000 * 1000 || clk_rate > 27 * 1000 * 1000)
> +		return -EINVAL;
> +
> +	/*
> +	 * We try all valid combinations of settings for the 3 blocks to get
> +	 * the pixel clock, and from that calculate the actual hts/vts to use.
> +	 * The vts is extended so as to achieve the required frame rate.
> +	 */
> +
> +	max_pre_div = max(clk_rate / (3 * 1000 * 1000),
> +			  ARRAY_SIZE(pre_divs) - 1);
> +
> +	for (pre_div = 0; pre_div <= max_pre_div; pre_div++) {
> +		unsigned int clk1 = clk_rate * 2 / pre_divs[pre_div];
> +		unsigned int min_mult;
> +		unsigned int max_mult;
> +		unsigned int mult;
> +
> +		if (clk1 < 3 * 1000 * 1000 || clk1 > 27 * 1000 * 1000)
> +			continue;
> +
> +		min_mult = DIV_ROUND_UP(200 * 1000 * 1000, clk1);
> +		max_mult = min(500 * 1000 * 1000 / clk1, 63U);
> +
> +		for (mult = min_mult; mult <= max_mult; mult++) {
> +			unsigned int clk2 = clk1 * mult;
> +			unsigned int min_div;
> +			unsigned int div;
> +
> +			min_div = DIV_ROUND_UP(clk2, 96 * 1000 * 1000);
> +			min_div = round_up(min_div, 2);
> +
> +			for (div = min_div; div <= 16; div += 2) {
> +				unsigned int pclk = clk2 / div;
> +				unsigned int min_pclk;
> +
> +				/*
> +				 * TODO: HTS calculation should ideally be split
> +				 * from the PLL calculations. This requires
> +				 * figuring out where the pclk / 300000 comes
> +				 * from.
> +				 */
> +				hts = *htsmin + pclk / (300*1000);
> +
> +				/* 2 clock cycles for every YUV422 pixel. */
> +				min_pclk = hts * vts / fps_denominator
> +					 * fps_numerator * 2;
> +				if (pclk < min_pclk)
> +					continue;
> +
> +				if (pclk < best_pclk) {
> +					best_pclk = pclk;
> +					best_hts = hts;
> +					best_pre_div = pre_div;
> +					best_mult = mult;
> +					best_div = div;

Can the requested frame rate exceed the highest possible rate here?

You already control the sensor's PLL and other capabilities such as
analogue cropping directly. You could make these all configurable from the
user space the same way the ccs driver does. What do you think?

> +				}
> +			}
> +		}
> +	}
> +
> +	if (best_pclk == UINT_MAX)
> +		return -EINVAL;
> +
> +	cfg->mult = best_mult;
> +	cfg->pre_div = best_pre_div;
> +	cfg->div = (best_div / 2) - 1;
> +	cfg->clk_out = best_pclk;
> +
> +	*htsmin = best_hts;
> +
> +	return 0;
> +}
> +
> +static int ov1063x_isp_reset(struct ov1063x_priv *priv, bool reset)
> +{
> +	unsigned int i;
> +	int ret = 0;
> +
> +	if (!reset) {
> +		/*
> +		 * Enable ISP blocks. Why OV1063X_SC_SOC_CLKRST7 needs to be
> +		 * written 26 times is unknown.
> +		 */
> +		for (i = 0; i < 26; ++i)
> +			ov1063x_write(priv, OV1063X_SC_SOC_CLKRST7,
> +				      OV1063X_SC_SOC_CLKRST7_SCLK, &ret);
> +
> +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST1,
> +			      OV1063X_SC_CMMN_CLKRST1_SCLK, &ret);
> +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
> +			      OV1063X_SC_CMMN_CLKRST2_PCLK_DVP |
> +			      OV1063X_SC_CMMN_CLKRST2_SCLK, &ret);
> +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST0,
> +			      OV1063X_SC_CMMN_CLKRST0_SCLK, &ret);
> +	} else {
> +		/* Reset the ISP. */
> +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST1,
> +			      OV1063X_SC_CMMN_CLKRST1_SCLK |
> +			      OV1063X_SC_CMMN_CLKRST1_RST, &ret);
> +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
> +			      OV1063X_SC_CMMN_CLKRST2_PCLK_DVP |
> +			      OV1063X_SC_CMMN_CLKRST2_SCLK |
> +			      OV1063X_SC_CMMN_CLKRST2_RST_DVP |
> +			      OV1063X_SC_CMMN_CLKRST2_RST, &ret);
> +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST0,
> +			      OV1063X_SC_CMMN_CLKRST0_SCLK |
> +			      OV1063X_SC_CMMN_CLKRST0_RST, &ret);
> +	}
> +
> +	return ret;
> +}
> +
> +static int ov1063x_configure(struct ov1063x_priv *priv)
> +{
> +	struct ov1063x_pll_config pll_cfg;
> +	unsigned int width_pre_subsample;
> +	unsigned int nr_isp_pixels;
> +	unsigned int hts, vts;
> +	u32 val;
> +	int ret;
> +
> +	/* Minimum values for HTS anv VTS. */
> +	hts = priv->analog_crop.width + 200;
> +	vts = priv->analog_crop.height + 50;
> +
> +	/*
> +	 * Get the best PCLK and adjust HTS accordingly. Adjust VTS to get as
> +	 * close to the desired frame rate as we can.
> +	 */
> +	ret = ov1063x_pll_setup(priv->clk_rate, &hts, vts,
> +				priv->fps_numerator, priv->fps_denominator,
> +				&pll_cfg);
> +	if (ret < 0)
> +		return -EINVAL;
> +
> +	vts = pll_cfg.clk_out
> +	    / (hts * 2 * priv->fps_numerator / priv->fps_denominator);
> +
> +	dev_dbg(priv->dev, "active %ux%u (total %ux%u) %u/%u fps, @%u MP/s\n",
> +		priv->format.width, priv->format.height,
> +		hts, vts, priv->fps_numerator, priv->fps_denominator,
> +		pll_cfg.clk_out);
> +	dev_dbg(priv->dev, "PLL pre-div %u mult %u div %u\n",
> +		pll_cfg.pre_div, pll_cfg.mult, pll_cfg.div);
> +
> +	/* Reset the ISP and configure the PLL. */
> +	ret = ov1063x_isp_reset(priv, true);
> +
> +	ov1063x_write(priv, OV1063X_SC_CMMN_PLL_CTRL0, pll_cfg.mult, &ret);
> +	ov1063x_write(priv, OV1063X_SC_CMMN_PLL_CTRL1,
> +		      (pll_cfg.pre_div << 4) | pll_cfg.div, &ret);
> +
> +	/* Analog array configuration (including horizontal cropping) */
> +	switch (priv->analog_crop.width) {
> +	case OV1063X_SENSOR_WIDTH:
> +	default:
> +		val = 0x60 | OV1063X_ANA_ARRAY1_FULL
> +		    | OV1063X_ANA_ARRAY1_DELAY(3);
> +		break;
> +	case 768:
> +		val = 0x60 | OV1063X_ANA_ARRAY1_CROP_768
> +		    | OV1063X_ANA_ARRAY1_DELAY(3);
> +		break;
> +	case 656:
> +		val = 0x60 | OV1063X_ANA_ARRAY1_CROP_656
> +		    | OV1063X_ANA_ARRAY1_DELAY(3);
> +		break;
> +	}
> +
> +	ov1063x_write(priv, OV1063X_ANA_ARRAY1, val, &ret);
> +
> +	/* Sensor configuration */
> +	ov1063x_write(priv, OV1063X_SENSOR_RSTGOLOW,
> +		      (pll_cfg.clk_out + 1500000) / 3000000, &ret);
> +	ov1063x_write(priv, OV1063X_SENSOR_HLDWIDTH,
> +		      (pll_cfg.clk_out + 666666) / 1333333, &ret);
> +	ov1063x_write(priv, OV1063X_SENSOR_TXWIDTH,
> +		      (pll_cfg.clk_out + 961500) / 1923000, &ret);
> +
> +	/*
> +	 * Timings (including cropping)
> +	 *
> +	 * TODO: The vertical size is set to the height of the analog crop
> +	 * rectangle plus 4 pixels. This margin is probably used by the ISP for
> +	 * CFA interpolation, and should be moved to the crop rectangle height
> +	 * after investigating how the ISP operates.
> +	 */
> +	ov1063x_write(priv, OV1063X_TIMING_Y_START_ADDR,
> +		      priv->analog_crop.top, &ret);
> +	ov1063x_write(priv, OV1063X_TIMING_Y_END_ADDR,
> +		      priv->analog_crop.top + priv->analog_crop.height + 3,
> +		      &ret);
> +	ov1063x_write(priv, OV1063X_TIMING_ISP_X_WIN, priv->digital_crop.left,
> +		      &ret);
> +	ov1063x_write(priv, OV1063X_TIMING_ISP_Y_WIN, priv->digital_crop.top,
> +		      &ret);
> +	ov1063x_write(priv, OV1063X_TIMING_X_OUTPUT_SIZE, priv->format.width,
> +		      &ret);
> +	ov1063x_write(priv, OV1063X_TIMING_Y_OUTPUT_SIZE, priv->format.height,
> +		      &ret);
> +	ov1063x_write(priv, OV1063X_TIMING_HTS, hts, &ret);
> +	ov1063x_write(priv, OV1063X_TIMING_VTS, vts, &ret);
> +
> +	/*
> +	 * Sub-sampling. Horizontal sub-sampling is applied in the ISP, vertical
> +	 * sub-sampling in the pixel array.
> +	 */
> +	if (priv->format.width <= 640) {
> +		ov1063x_write(priv, OV1063X_ISP_RW05, OV1063X_ISP_RW05_SUB_AVG |
> +			      OV1063X_ISP_RW05_SUB_ENABLE, &ret);
> +		ov1063x_write(priv, OV1063X_SC_CMMN_PCLK_DIV_CTRL, 2, &ret);
> +	} else {
> +		ov1063x_write(priv, OV1063X_ISP_RW05, OV1063X_ISP_RW05_SUB_AVG,
> +			      &ret);
> +		ov1063x_write(priv, OV1063X_SC_CMMN_PCLK_DIV_CTRL, 1, &ret);
> +	}
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	if (priv->format.height <= 400)
> +		ret = ov1063x_write_array(priv, ov1063x_regs_vert_sub2,
> +					  ARRAY_SIZE(ov1063x_regs_vert_sub2));
> +	else
> +		ret = ov1063x_write_array(priv, ov1063x_regs_vert_no_sub,
> +					  ARRAY_SIZE(ov1063x_regs_vert_no_sub));
> +
> +	/*
> +	 * AEC & AWB
> +	 *
> +	 * TODO: The number of pixels fed to the ISP is computed using the
> +	 * analog crop width and the vertical output size, to account for the
> +	 * fact that vertical sub-sampling is applied in the pixel array while
> +	 * horizontal sub-sampling is applied in the ISP. The 4 pixels margin
> +	 * seems incorrect when sub-sampling, as the vertical timing start and
> +	 * stop registers are programmed with a 4 pixels margin before
> +	 * sub-sampling, the ISP should thus receive a 2 pixels margin only.
> +	 * This needs to be investigated.
> +	 *
> +	 * TODO: When applying vertical digital crop, the output height is
> +	 * likely the wrong value to compute the total number of pixels fed to
> +	 * the ISP.
> +	 */
> +	val = (vts - 8) * 16;
> +	ov1063x_write(priv, OV1063X_AEC_MAX_EXP_LONG, val, &ret);
> +	ov1063x_write(priv, OV1063X_AEC_MAX_EXP_SHORT, val, &ret);
> +
> +	nr_isp_pixels = priv->analog_crop.width * (priv->format.height + 4);
> +	ov1063x_write(priv, OV1063X_AWB_SIMPLE_MIN_NUM, nr_isp_pixels / 256, &ret);
> +	ov1063x_write(priv, OV1063X_AWB_CT_MIN_NUM, nr_isp_pixels / 256, &ret);
> +	ov1063x_write(priv, OV1063X_REG_16BIT(0xc512), nr_isp_pixels / 16,
> +		      &ret);
> +
> +	ov1063x_write(priv, OV1063X_VTS_ADDR, vts, &ret);
> +	ov1063x_write(priv, OV1063X_HTS_ADDR, hts, &ret);
> +
> +	/* FIFO */
> +	ov1063x_write(priv, OV1063X_VFIFO_LLEN_FIRS1_SEL,
> +		      OV1063X_VFIFO_LLEN_FIRS1_SEL_8B_YUV, &ret);
> +	width_pre_subsample = priv->format.width <= 640
> +			    ? priv->format.width * 2 : priv->format.width;
> +	ov1063x_write(priv, OV1063X_VFIFO_LINE_LENGTH_MAN, 2 * hts, &ret);
> +	ov1063x_write(priv, OV1063X_VFIFO_HSYNC_START_POSITION,
> +		      2 * (hts - width_pre_subsample), &ret);
> +
> +	/* Output interface (DVP). */
> +	switch (priv->format.code) {
> +	case MEDIA_BUS_FMT_UYVY8_2X8:
> +		val = OV1063X_FORMAT_UYVY;
> +		break;
> +	case MEDIA_BUS_FMT_VYUY8_2X8:
> +		val = OV1063X_FORMAT_VYUY;
> +		break;
> +	case MEDIA_BUS_FMT_YUYV8_2X8:
> +		val = OV1063X_FORMAT_YUYV;
> +		break;
> +	case MEDIA_BUS_FMT_YVYU8_2X8:
> +		val = OV1063X_FORMAT_YYYU;
> +		break;
> +	default:
> +		val = OV1063X_FORMAT_UYVY;
> +		break;
> +	}
> +
> +	ov1063x_write(priv, OV1063X_FORMAT_CTRL00, val, &ret);
> +	ov1063x_write(priv, OV1063X_DVP_MOD_SEL, 0, &ret);
> +
> +	if (ret)
> +		return ret;
> +
> +	/* Take the ISP out of reset. */
> +	return ov1063x_isp_reset(priv, false);
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * V4L2 Control Operations
> + */
> +
> +static const char * const ov1063x_test_pattern_menu[] = {
> +	"Disabled",
> +	"Color Bars, Plain",
> +	"Color Bars, Vertical Gradient",
> +	"Color Bars, Horizontal Gradient",
> +	"Color Bars, Repeating",
> +	"Random Data",
> +	"Squares, Color",
> +	"Squares, Black & White",
> +};
> +
> +struct ov1063x_tpg_config {
> +	u8 ctrl3d;
> +	u8 ctrl3e;
> +};
> +
> +static const struct ov1063x_tpg_config
> +ov1063x_tpg_configs[ARRAY_SIZE(ov1063x_test_pattern_menu) - 1] = {
> +	{
> +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
> +			| OV1063X_ISP_CTRL3D_COLOR_BAR(0),
> +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
> +	}, {
> +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
> +			| OV1063X_ISP_CTRL3D_COLOR_BAR(1),
> +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
> +	}, {
> +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
> +			| OV1063X_ISP_CTRL3D_COLOR_BAR(2),
> +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
> +	}, {
> +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
> +			| OV1063X_ISP_CTRL3D_COLOR_BAR(3),
> +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
> +	}, {
> +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN,
> +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_RANDOM,
> +	}, {
> +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN,
> +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_SQUARES,
> +	}, {
> +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN,
> +		.ctrl3e = OV1063X_ISP_CTRL3E_SQUARE_BW
> +			| OV1063X_ISP_CTRL3E_PATTERN_SQUARES,
> +	},
> +};
> +
> +static int ov1063x_tpg_setup(struct ov1063x_priv *priv, struct v4l2_ctrl *ctrl)
> +{
> +	const struct ov1063x_tpg_config *cfg;
> +	int ret = 0;
> +
> +	if (!ctrl->val)
> +		return ov1063x_write_array(priv, ov1063x_regs_colorbar_disable,
> +					   ARRAY_SIZE(ov1063x_regs_colorbar_disable));
> +
> +	if (!ctrl->cur.val) {
> +		/*
> +		 * Only write the full settings when the test pattern was
> +		 * disabled, not when we're just changing the test pattern type.
> +		 */
> +		ret = ov1063x_write_array(priv, ov1063x_regs_colorbar_enable,
> +					  ARRAY_SIZE(ov1063x_regs_colorbar_enable));
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	cfg = &ov1063x_tpg_configs[ctrl->val - 1];
> +
> +	/* TODO: Add support for the moving bar overlay. */
> +	ov1063x_write(priv, OV1063X_ISP_CTRL3D, cfg->ctrl3d, &ret);
> +	ov1063x_write(priv, OV1063X_ISP_CTRL3E, cfg->ctrl3e, &ret);
> +
> +	return ret;
> +}
> +
> +static int ov1063x_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct ov1063x_priv *priv = container_of(ctrl->handler,
> +					struct ov1063x_priv, hdl);
> +	int ret = 0;
> +
> +	if (!priv->streaming)
> +		return 0;
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_VFLIP: {
> +		const u32 vflip = OV1063X_TIMING_CTRL1C_VFLIP_DIG
> +				| OV1063X_TIMING_CTRL1C_VFLIP_ARRAY;
> +
> +		return ov1063x_update(priv, OV1063X_TIMING_CTRL1C, vflip,
> +				      ctrl->val ? vflip : 0, NULL);
> +	}
> +
> +	case V4L2_CID_HFLIP: {
> +		const u32 hflip = OV1063X_TIMING_CTRL1D_HFLIP_DIG
> +				| OV1063X_TIMING_CTRL1D_HFLIP_ARRAY;
> +
> +		ov1063x_update(priv, OV1063X_HORIZ_COLORCORRECT,
> +			       OV1063X_HORIZ_COLORCORRECT_ON,
> +			       ctrl->val ? OV1063X_HORIZ_COLORCORRECT_ON : 0,
> +			       &ret);
> +		ov1063x_update(priv, OV1063X_TIMING_CTRL1D, hflip,
> +			       ctrl->val ? hflip : 0, &ret);
> +		return ret;
> +	}
> +
> +	case V4L2_CID_TEST_PATTERN:
> +		return ov1063x_tpg_setup(priv, ctrl);
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static const struct v4l2_ctrl_ops ov1063x_ctrl_ops = {
> +	.s_ctrl = ov1063x_s_ctrl,
> +};
> +
> +/* -----------------------------------------------------------------------------
> + * V4L2 Subdev Operations
> + */
> +
> +static int ov1063x_s_stream(struct v4l2_subdev *sd, int enable)
> +{
> +	struct ov1063x_priv *priv = to_ov1063x(sd);
> +	int ret = 0;
> +
> +	if (!enable) {
> +		ov1063x_write(priv, OV1063X_STREAM_MODE, 0, &ret);
> +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
> +			      OV1063X_SC_CMMN_CLKRST2_SCLK, &ret);
> +
> +		pm_runtime_mark_last_busy(priv->dev);
> +		pm_runtime_put_autosuspend(priv->dev);
> +
> +		mutex_lock(priv->hdl.lock);
> +		priv->streaming = false;
> +		mutex_unlock(priv->hdl.lock);
> +
> +		return ret;
> +	}
> +
> +	mutex_lock(priv->hdl.lock);
> +
> +	/* Streaming needs to be true for ov1063x_s_ctrl() to proceed. */
> +	priv->streaming = true;
> +
> +	ret = pm_runtime_get_sync(priv->dev);
> +	if (ret < 0)
> +		goto done;
> +
> +	ret = ov1063x_configure(priv);
> +	if (ret < 0)
> +		goto done;
> +
> +	ret = __v4l2_ctrl_handler_setup(&priv->hdl);
> +	if (ret < 0)
> +		goto done;
> +
> +	ret = 0;
> +	ov1063x_write(priv, OV1063X_STREAM_MODE, OV1063X_STREAM_MODE_ON, &ret);
> +	ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
> +		      OV1063X_SC_CMMN_CLKRST2_PCLK_DVP |
> +		      OV1063X_SC_CMMN_CLKRST2_SCLK, &ret);
> +
> +done:
> +	if (ret < 0) {
> +		/*
> +		 * In case of error, turn the power off synchronously as the
> +		 * device likely has no other chance to recover.
> +		 */
> +		pm_runtime_put_sync(priv->dev);
> +		priv->streaming = false;
> +	}
> +
> +	mutex_unlock(priv->hdl.lock);
> +
> +	return ret;
> +}
> +
> +static struct v4l2_mbus_framefmt *
> +__ov1063x_get_pad_format(struct ov1063x_priv *priv,
> +			 struct v4l2_subdev_pad_config *cfg,
> +			 unsigned int pad, u32 which)
> +{
> +	switch (which) {
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +		return v4l2_subdev_get_try_format(&priv->subdev, cfg, pad);
> +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> +		return &priv->format;
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +static int ov1063x_init_cfg(struct v4l2_subdev *sd,
> +			    struct v4l2_subdev_pad_config *cfg)
> +{
> +	u32 which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
> +	struct ov1063x_priv *priv = to_ov1063x(sd);
> +	struct v4l2_mbus_framefmt *format;
> +
> +	format = __ov1063x_get_pad_format(priv, cfg, 0, which);
> +	format->code = ov1063x_mbus_formats[0];
> +	format->width = ov1063x_framesizes[0].width;
> +	format->height = ov1063x_framesizes[0].height;
> +	format->field = V4L2_FIELD_NONE;
> +	format->colorspace = V4L2_COLORSPACE_SMPTE170M;
> +
> +	if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> +		/*
> +		 * This assumes that ov1063x_mbus_formats[0] doesn't
> +		 * sub-sample.
> +		 */
> +		priv->analog_crop.width = OV1063X_SENSOR_WIDTH;
> +		priv->analog_crop.height = format->height;
> +		priv->analog_crop.left = ((OV1063X_SENSOR_WIDTH -
> +					   priv->analog_crop.width) / 2) & ~1;
> +		priv->analog_crop.top = ((OV1063X_SENSOR_HEIGHT -
> +					  priv->analog_crop.height) / 2) & ~1;
> +
> +		priv->digital_crop.width = format->width;
> +		priv->digital_crop.height = format->height;
> +		priv->digital_crop.left = ((priv->analog_crop.width -
> +					    priv->digital_crop.width) / 2) & ~1;
> +		priv->digital_crop.top = 0;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ov1063x_enum_mbus_code(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_pad_config *cfg,
> +				  struct v4l2_subdev_mbus_code_enum *code)
> +{
> +	if (code->index >= ARRAY_SIZE(ov1063x_mbus_formats))
> +		return -EINVAL;
> +
> +	code->code = ov1063x_mbus_formats[code->index];
> +
> +	return 0;
> +}
> +
> +static int ov1063x_enum_frame_sizes(struct v4l2_subdev *sd,
> +				    struct v4l2_subdev_pad_config *cfg,
> +				    struct v4l2_subdev_frame_size_enum *fse)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(ov1063x_mbus_formats); ++i) {
> +		if (ov1063x_mbus_formats[i] == fse->code)
> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(ov1063x_mbus_formats))
> +		return -EINVAL;
> +
> +	if (fse->index >= ARRAY_SIZE(ov1063x_framesizes))
> +		return -EINVAL;
> +
> +	fse->min_width  = ov1063x_framesizes[fse->index].width;
> +	fse->max_width  = fse->min_width;
> +	fse->max_height = ov1063x_framesizes[fse->index].height;
> +	fse->min_height = fse->max_height;
> +
> +	return 0;
> +}
> +
> +static int ov1063x_get_fmt(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_pad_config *cfg,
> +			   struct v4l2_subdev_format *fmt)
> +{
> +	struct ov1063x_priv *priv = to_ov1063x(sd);
> +
> +	fmt->format = *__ov1063x_get_pad_format(priv, cfg, fmt->pad,
> +						fmt->which);
> +
> +	return 0;
> +}
> +
> +static int ov1063x_set_fmt(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_pad_config *cfg,
> +			   struct v4l2_subdev_format *fmt)
> +{
> +	struct ov1063x_priv *priv = to_ov1063x(sd);
> +	struct v4l2_mbus_framefmt *format;
> +	const struct v4l2_area *fsize;
> +	unsigned int i;
> +	u32 code;
> +	int ret = 0;
> +
> +	/*
> +	 * Validate the media bus code, defaulting to the first one if the
> +	 * requested code isn't supported.
> +	 */
> +	for (i = 0; i < ARRAY_SIZE(ov1063x_mbus_formats); ++i) {
> +		if (ov1063x_mbus_formats[i] == fmt->format.code) {
> +			code = fmt->format.code;
> +			break;
> +		}
> +	}
> +
> +	if (i == ARRAY_SIZE(ov1063x_mbus_formats))
> +		code = ov1063x_mbus_formats[0];

You could do this assignment unconditionally in variable initialisation.

> +
> +	/* Find the nearest supported frame size. */
> +	fsize = v4l2_find_nearest_size(ov1063x_framesizes,
> +				       ARRAY_SIZE(ov1063x_framesizes),
> +				       width, height, fmt->format.width,
> +				       fmt->format.height);
> +
> +	/* Update the stored format and return it. */
> +	format = __ov1063x_get_pad_format(priv, cfg, fmt->pad, fmt->which);
> +
> +	mutex_lock(priv->hdl.lock);
> +
> +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming) {
> +		ret = -EBUSY;
> +		goto done;
> +	}
> +
> +	format->code = code;
> +	format->width = fsize->width;
> +	format->height = fsize->height;
> +
> +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> +		unsigned int hsub;
> +		unsigned int vsub;
> +
> +		/*
> +		 * Enable horizontal or vertical sub-sampling automatically when
> +		 * the width or height are smaller than half the maximum
> +		 * resolution.
> +		 */
> +		hsub = format->width <= 640 ? 2 : 1;
> +		vsub = format->height <= 400 ? 2 : 1;
> +
> +		/*
> +		 * The analog horizontal crop is restricted to the full sensor
> +		 * width (1312 pixels), 768 or 656 pixels. Additional cropping
> +		 * will be applied in the digital domain.
> +		 */
> +		priv->analog_crop.width = format->width * hsub;
> +		priv->analog_crop.height = format->height * vsub;
> +
> +		if (priv->analog_crop.width > 768)
> +			priv->analog_crop.width = OV1063X_SENSOR_WIDTH;
> +		else if (priv->analog_crop.width > 656)
> +			priv->analog_crop.width = 768;
> +		else
> +			priv->analog_crop.width = 656;
> +
> +		/*
> +		 * The digital crop is applied at the ISP input, before
> +		 * horizontal sub-sampling but after vertical sub-sampling as
> +		 * the latter is applied in the pixel array.
> +		 */
> +		priv->digital_crop.width = format->width * hsub;
> +		priv->digital_crop.height = format->height;
> +
> +		/*
> +		 * Center the crop rectangles, rounding coordinates to a
> +		 * multiple of 2 to avoid changing the Bayer pattern.
> +		 */
> +		priv->analog_crop.left = ((OV1063X_SENSOR_WIDTH -
> +					   priv->analog_crop.width) / 2) & ~1;
> +		priv->analog_crop.top = ((OV1063X_SENSOR_HEIGHT -
> +					  priv->analog_crop.height) / 2) & ~1;
> +		priv->digital_crop.left = ((priv->analog_crop.width -
> +					    priv->digital_crop.width) / 2) & ~1;
> +		priv->analog_crop.top = 0;
> +	}
> +
> +	fmt->format = *format;
> +
> +done:
> +	mutex_unlock(priv->hdl.lock);
> +
> +	return ret;
> +}
> +
> +static const struct v4l2_subdev_core_ops ov1063x_subdev_core_ops = {
> +	.log_status		= v4l2_ctrl_subdev_log_status,
> +	.subscribe_event	= v4l2_ctrl_subdev_subscribe_event,
> +	.unsubscribe_event	= v4l2_event_subdev_unsubscribe,
> +};
> +
> +static const struct v4l2_subdev_video_ops ov1063x_subdev_video_ops = {
> +	.s_stream	= ov1063x_s_stream,
> +};
> +
> +static const struct v4l2_subdev_pad_ops ov1063x_subdev_pad_ops = {
> +	.init_cfg		= ov1063x_init_cfg,
> +	.enum_mbus_code		= ov1063x_enum_mbus_code,
> +	.enum_frame_size	= ov1063x_enum_frame_sizes,
> +	.get_fmt		= ov1063x_get_fmt,
> +	.set_fmt		= ov1063x_set_fmt,
> +};
> +
> +static const struct v4l2_subdev_ops ov1063x_subdev_ops = {
> +	.core	= &ov1063x_subdev_core_ops,
> +	.video	= &ov1063x_subdev_video_ops,
> +	.pad	= &ov1063x_subdev_pad_ops,
> +};
> +
> +/* -----------------------------------------------------------------------------
> + * Power Management
> + */
> +
> +static int ov1063x_power_on_init(struct ov1063x_priv *priv)
> +{
> +	struct i2c_client *client = to_i2c_client(priv->dev);
> +	unsigned int i;
> +	int ret;
> +
> +	ret = ov1063x_write(priv, OV1063X_SOFTWARE_RESET, 0x01, NULL);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ov1063x_isp_reset(priv, true);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * Why the I2C address has to be written 23 times (or, actually, at
> +	 * all) is unknown. This may not be required.
> +	 */
> +	for (i = 0; i < 23; ++i) {
> +		ret = ov1063x_write(priv, OV1063X_SC_CMMN_SCCB_ID,
> +				    OV1063X_SC_CMMN_SCCB_ID_ADDR(client->addr) |
> +				    OV1063X_SC_CMMN_SCCB_ID_SEL, NULL);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	ret = ov1063x_write_array(priv, ov1063x_regs_default,
> +				  ARRAY_SIZE(ov1063x_regs_default));
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ov1063x_isp_reset(priv, false);
> +	if (ret < 0)
> +		return ret;
> +
> +	usleep_range(500, 510);
> +	return 0;
> +}
> +
> +static int ov1063x_power_on(struct ov1063x_priv *priv)
> +{
> +	int ret;
> +
> +	ret = clk_prepare_enable(priv->clk);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (priv->pwdn_gpio) {
> +		gpiod_set_value_cansleep(priv->pwdn_gpio, 0);
> +		usleep_range(1000, 1200);
> +	}
> +
> +	if (priv->reset_gpio) {
> +		gpiod_set_value_cansleep(priv->reset_gpio, 0);
> +		usleep_range(250000, 260000);
> +	}
> +
> +	return 0;
> +}
> +
> +static void ov1063x_power_off(struct ov1063x_priv *priv)
> +{
> +	gpiod_set_value_cansleep(priv->pwdn_gpio, 1);
> +	gpiod_set_value_cansleep(priv->reset_gpio, 1);
> +
> +	clk_disable_unprepare(priv->clk);
> +}
> +
> +static int ov1063x_runtime_resume(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
> +	struct ov1063x_priv *priv = to_ov1063x(subdev);
> +	int ret;
> +
> +	ret = ov1063x_power_on(priv);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ov1063x_power_on_init(priv);
> +	if (ret < 0) {
> +		ov1063x_power_off(priv);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ov1063x_runtime_suspend(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
> +	struct ov1063x_priv *priv = to_ov1063x(subdev);
> +
> +	ov1063x_power_off(priv);
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops ov1063x_pm_ops = {
> +	SET_RUNTIME_PM_OPS(ov1063x_runtime_suspend, ov1063x_runtime_resume, NULL)
> +};
> +
> +/* -----------------------------------------------------------------------------
> + * I2C Driver, Probe & Remove
> + */
> +
> +static int ov1063x_detect(struct ov1063x_priv *priv)
> +{
> +	u32 pid;
> +	int ret;
> +
> +	/* Read and check the product ID. */
> +	ret = ov1063x_read(priv, OV1063X_PID, &pid);
> +	if (ret)
> +		return ret;
> +
> +	switch (pid) {
> +	case OV10633_VERSION_REG:
> +		priv->model = SENSOR_OV10633;
> +		priv->name = "ov10633";
> +		break;
> +	case OV10635_VERSION_REG:
> +		priv->model = SENSOR_OV10635;
> +		priv->name = "ov10635";
> +		break;
> +	default:
> +		dev_err(priv->dev, "Unknown product ID %04x\n", pid);
> +		return -ENODEV;
> +	}
> +
> +	dev_dbg(priv->dev, "%s detected\n", priv->name);

You print the name of the sensor at the end of probe already.

> +
> +	return 0;
> +}
> +
> +static const struct regmap_config ov1063x_regmap_config = {
> +	.reg_bits = 16,
> +	.val_bits = 8,
> +};
> +
> +static int ov1063x_probe(struct i2c_client *client)
> +{
> +	struct ov1063x_priv *priv;
> +	struct v4l2_subdev *sd;
> +	int ret;
> +
> +	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = &client->dev;
> +
> +	/* Acquire resources: regmap, GPIOs and clock. The GPIOs are optional. */
> +	priv->regmap = devm_regmap_init_i2c(client, &ov1063x_regmap_config);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +
> +	priv->pwdn_gpio = devm_gpiod_get_optional(priv->dev, "powerdown",
> +						  GPIOD_OUT_HIGH);
> +	if (IS_ERR(priv->pwdn_gpio))
> +		return PTR_ERR(priv->pwdn_gpio);
> +
> +	priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
> +						   GPIOD_OUT_HIGH);
> +	if (IS_ERR(priv->reset_gpio))
> +		return PTR_ERR(priv->reset_gpio);
> +	priv->clk = devm_clk_get(priv->dev, "xvclk");
> +	if (IS_ERR(priv->clk)) {
> +		ret = PTR_ERR(priv->clk);
> +		dev_err(priv->dev, "Failed to get xvclk clock: %d\n", ret);
> +		return ret;
> +	}
> +
> +	priv->clk_rate = clk_get_rate(priv->clk);
> +	dev_dbg(priv->dev, "xvclk rate: %lu Hz\n", priv->clk_rate);
> +
> +	if (priv->clk_rate < 6000000 || priv->clk_rate > 27000000)
> +		return -EINVAL;
> +
> +	/*
> +	 * Enable power and detect the device.
> +	 *
> +	 * The driver supports runtime PM, but needs to work when runtime PM is
> +	 * disabled in the kernel. To that end, power it on manually here.
> +	 */
> +	ret = ov1063x_power_on(priv);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ov1063x_detect(priv);
> +	if (ret)
> +		goto err_power;
> +
> +	/* Initialize the subdev and its controls. */
> +	sd = &priv->subdev;
> +	v4l2_i2c_subdev_init(sd, client, &ov1063x_subdev_ops);
> +	v4l2_i2c_subdev_set_name(sd, client, priv->name, NULL);
> +
> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
> +		     V4L2_SUBDEV_FL_HAS_EVENTS;
> +
> +	v4l2_ctrl_handler_init(&priv->hdl, 3);
> +	v4l2_ctrl_new_std(&priv->hdl, &ov1063x_ctrl_ops,
> +			  V4L2_CID_VFLIP, 0, 1, 1, 0);
> +	v4l2_ctrl_new_std(&priv->hdl, &ov1063x_ctrl_ops,
> +			  V4L2_CID_HFLIP, 0, 1, 1, 0);
> +	v4l2_ctrl_new_std_menu_items(&priv->hdl, &ov1063x_ctrl_ops,
> +				     V4L2_CID_TEST_PATTERN,
> +				     ARRAY_SIZE(ov1063x_test_pattern_menu) - 1,
> +				     0, 0, ov1063x_test_pattern_menu);
> +
> +	if (priv->hdl.error) {
> +		ret = priv->hdl.error;
> +		goto err_power;
> +	}
> +
> +	sd->ctrl_handler = &priv->hdl;
> +
> +	/* Default framerate */
> +	priv->fps_numerator = 30;
> +	priv->fps_denominator = 1;
> +	ov1063x_init_cfg(&priv->subdev, NULL);
> +
> +	/* Initialize the media entity. */
> +	priv->pad.flags = MEDIA_PAD_FL_SOURCE;
> +	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
> +	ret = media_entity_pads_init(&sd->entity, 1, &priv->pad);
> +	if (ret < 0)
> +		goto err_ctrls;
> +
> +	/*
> +	 * Enable runtime PM. As the device has been powered manually, mark it
> +	 * as active, and increase the usage count without resuming the device.
> +	 */
> +	pm_runtime_set_active(priv->dev);
> +	pm_runtime_get_noresume(priv->dev);
> +	pm_runtime_enable(priv->dev);
> +
> +	/*
> +	 * Enable autosuspend as it can help avoiding costly power transitions
> +	 * when reconfiguring the sensor.
> +	 */
> +	pm_runtime_set_autosuspend_delay(priv->dev, 1000);
> +	pm_runtime_use_autosuspend(priv->dev);
> +
> +	/*
> +	 * At this point the device is powered on and active from a runtime PM
> +	 * point of view, but hasn't gone through the full initialization
> +	 * performed by the runtime resume operation. Suspend it synchronously
> +	 * to turn the power off, ensuring proper initialization will take
> +	 * place before the first usage.
> +	 */
> +	pm_runtime_put_sync(priv->dev);
> +
> +	/*
> +	 * In case runtime PM is disabled in the kernel, the device remains
> +	 * active and needs to be fully initialized at this point.
> +	 */
> +	if (!pm_runtime_status_suspended(priv->dev)) {
> +		ret = ov1063x_power_on_init(priv);
> +		if (ret < 0)
> +			goto err_pm;
> +	}
> +
> +	/* Finally, register the subdev. */
> +	ret = v4l2_async_register_subdev(sd);
> +	if (ret < 0)
> +		goto err_pm;
> +
> +	dev_info(priv->dev, "%s probed\n", priv->name);
> +
> +	return 0;
> +
> +err_pm:
> +	pm_runtime_disable(priv->dev);
> +	media_entity_cleanup(&priv->subdev.entity);
> +err_ctrls:
> +	v4l2_ctrl_handler_free(&priv->hdl);
> +err_power:
> +	if (!pm_runtime_status_suspended(priv->dev))
> +		ov1063x_power_off(priv);
> +	return ret;
> +}
> +
> +static int ov1063x_remove(struct i2c_client *client)
> +{
> +	struct ov1063x_priv *priv = i2c_get_clientdata(client);
> +
> +	v4l2_ctrl_handler_free(&priv->hdl);
> +	v4l2_async_unregister_subdev(&priv->subdev);
> +	media_entity_cleanup(&priv->subdev.entity);
> +
> +	/*
> +	 * Disable runtime PM. In case runtime PM is disabled in the kernel,
> +	 * make sure to turn power off manually.
> +	 */
> +	pm_runtime_disable(priv->dev);
> +	if (!pm_runtime_status_suspended(priv->dev))
> +		ov1063x_power_off(priv);
> +	pm_runtime_set_suspended(priv->dev);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id ov1063x_dt_id[] = {
> +	{ .compatible = "ovti,ov10635" },
> +	{ .compatible = "ovti,ov10633" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, ov1063x_dt_id);
> +
> +static struct i2c_driver ov1063x_i2c_driver = {
> +	.driver = {
> +		.name = "ov1063x",
> +		.of_match_table = of_match_ptr(ov1063x_dt_id),
> +		.pm = &ov1063x_pm_ops,
> +	},
> +	.probe_new = ov1063x_probe,
> +	.remove = ov1063x_remove,
> +};
> +
> +module_i2c_driver(ov1063x_i2c_driver);
> +
> +MODULE_DESCRIPTION("Camera Sensor Driver for OmniVision OV10633/OV10635");
> +MODULE_AUTHOR("Texas Instruments Inc.");
> +MODULE_LICENSE("GPL v2");

"GPL"

> diff --git a/drivers/media/i2c/ov1063x_regs.h b/drivers/media/i2c/ov1063x_regs.h
> new file mode 100644
> index 000000000000..43a0ca1d1367
> --- /dev/null
> +++ b/drivers/media/i2c/ov1063x_regs.h
> @@ -0,0 +1,626 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * OmniVision OV1063x Camera Driver
> + *
> + * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
> + * Copyright (C) 2020 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + */
> +
> +struct ov1063x_reg {
> +	u32	reg;
> +	u32	val;
> +};
> +
> +static const struct ov1063x_reg ov1063x_regs_default[] = {
> +	/* Register configuration for full resolution : 1280x720 */
> +	{ OV1063X_SC_CMMN_MISC_CTRL, 0x02 |
> +				     OV1063X_SC_CMMN_MISC_CTRL_CEN_GLOBAL_O },
> +	{ OV1063X_SC_CMMN_PAD, 0x02 },
> +	{ OV1063X_HORIZ_COLORCORRECT, 0x0c },
> +	{ OV1063X_REG_8BIT(0x6901), 0x01 },
> +	{ OV1063X_SC_CMMN_SCLK2X_SEL, OV1063X_SC_CMMN_SCLK2X_SEL_DIV4 },
> +	{ OV1063X_AEC_PK_MANUAL, OV1063X_AEC_PK_MANUAL_DELAY },
> +	{ OV1063X_SC_CMMN_PWDN_CTRL2, 0x20 |
> +				      OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG1 |
> +				      OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG2 |
> +				      OV1063X_SC_CMMN_PWDN_CTRL2_RST_ISP |
> +				      OV1063X_SC_CMMN_PWDN_CTRL2_SEQUENCE },
> +	{ OV1063X_SC_CMMN_CORE_CTRL1, 0x03 },
> +	/*
> +	 * For 15fps
> +	 *
> +	 * XVCLK: 9MHz
> +	 * Pre divider: 1
> +	 * Multiplier: 32
> +	 * Divider: 8
> +	 * SCLK: 36MHz
> +	 */
> +	{ OV1063X_SC_CMMN_PLL_CTRL0, OV1063X_SC_CMMN_PLL_SCLK_CP(0) |
> +				     OV1063X_SC_CMMN_PLL_SCLK_MULTI(32) },
> +	{ OV1063X_SC_CMMN_PLL_CTRL1, OV1063X_SC_CMMN_PLL_SCLK_PRE_DIV(0) |
> +				     OV1063X_SC_CMMN_PLL_SCLK_CP2(0) |
> +				     OV1063X_SC_CMMN_PLL_SCLK_DIV(3) },
> +	{ OV1063X_SC_CMMN_PLL_CTRL2, OV1063X_SC_CMMN_PLL_SCLK_CP(0) |
> +				     OV1063X_SC_CMMN_PLL_SCLK_MULTI(32) },
> +	{ OV1063X_SC_CMMN_PLL_CTRL3, OV1063X_SC_CMMN_PLL_PCLK_BYPASS |
> +				     OV1063X_SC_CMMN_PLL_SCLK_PRE_DIV(1) |
> +				     OV1063X_SC_CMMN_PLL_SCLK_CP2(0) |
> +				     OV1063X_SC_CMMN_PLL_SCLK_DIV(1) },
> +	{ OV1063X_ANA_ADC1, 0x74 },
> +	{ OV1063X_ANA_ADC2, 0x2b },
> +	{ OV1063X_ANA_ANALOG3, 0x00 },
> +	{ OV1063X_ANA_ANALOG2, 0x67 },
> +	{ OV1063X_ANA_PWC4, 0xba },
> +	{ OV1063X_ANA_ADC3, 0x2f },
> +	{ OV1063X_ANA_ADC4, 0x00 },
> +	{ OV1063X_ANA_PWC1, 0xa8 },
> +	{ OV1063X_ANA_PWC2, 0x16 },
> +	{ OV1063X_SENSOR_EQ_GOLOW, 0x10 },
> +	{ OV1063X_SENSOR_BITSW_GO, 0x0001 },
> +	{ OV1063X_FORMAT_CTRL00, OV1063X_FORMAT_UYVY },
> +	{ OV1063X_SC_CMMN_PCLK_DIV_CTRL, 1 },
> +	{ OV1063X_SC_CMMN_CORE_CTRL_3, OV1063X_SC_CMMN_CORE_CTRL_PCLK_SEC },
> +	{ OV1063X_SC_CMMN_CLOCK_SEL, 0x0b },
> +	{ OV1063X_SENSOR_RSTGOLOW, 0x0d },
> +	{ OV1063X_SENSOR_HLDWIDTH, 0x20 },
> +	{ OV1063X_SENSOR_TXWIDTH, 0x15 },
> +	{ OV1063X_SENSOR_REG9, 0x28 },
> +	{ OV1063X_SENSOR_REGD, 0x00 },
> +	{ OV1063X_SENSOR_RSTYZ_GOLOW, 32 },
> +	{ OV1063X_SENSOR_REG15, 0x04 },
> +	{ OV1063X_TIMING_CTRL1D, OV1063X_TIMING_CTRL1D_WDR },
> +	{ OV1063X_TIMING_CTRL1C, 0 },
> +	{ OV1063X_REG_8BIT(0x3824), 0x10 },
> +	{ OV1063X_TIMING_CTRL15, OV1063X_TIMING_CTRL15_BLACK_LINE_HREF |
> +				 OV1063X_TIMING_CTRL15_BLACK_LINES(12) },
> +	{ OV1063X_TIMING_X_END_ADDR, 1311 },
> +	{ OV1063X_TIMING_X_START_ADDR, 0 },
> +	{ OV1063X_TIMING_Y_END_ADDR, 769 },
> +	{ OV1063X_TIMING_Y_START_ADDR, 46 },
> +	{ OV1063X_TIMING_X_OUTPUT_SIZE, 1280 },
> +	{ OV1063X_TIMING_Y_OUTPUT_SIZE, 720 },
> +	{ OV1063X_TIMING_HTS, 1782 },
> +	{ OV1063X_TIMING_VTS, 748 },
> +	{ OV1063X_TIMING_ISP_X_WIN, 8 },
> +	{ OV1063X_VSTART_OFFSET, 12 },
> +	{ OV1063X_ANA_ARRAY1, 0x60 |
> +			      OV1063X_ANA_ARRAY1_FULL |
> +			      OV1063X_ANA_ARRAY1_DELAY(3) },
> +	{ OV1063X_ISP_RW05, OV1063X_ISP_RW05_SUB_AVG },
> +	{ OV1063X_AEC_CTRLD5, 8 * 1024 * 1024 },
> +	{ OV1063X_AEC_CTRLD9, 8 * 1024 * 1024 },
> +	{ OV1063X_AEC_CTRLE8, 127 },
> +	{ OV1063X_AEC_CTRLEA, 127 },
> +	{ OV1063X_GAIN_AWB_MAN_GAIN_B_LONG, 128 },
> +	{ OV1063X_GAIN_AWB_MAN_GAIN_GB_LONG, 128 },
> +	{ OV1063X_GAIN_AWB_MAN_GAIN_GR_LONG, 128 },
> +	{ OV1063X_GAIN_AWB_MAN_GAIN_R_LONG, 128 },
> +	{ OV1063X_GAIN_AWB_MAN_OFFSET_B_LONG, 0 },
> +	{ OV1063X_GAIN_AWB_MAN_OFFSET_GB_LONG, 0 },
> +	{ OV1063X_GAIN_AWB_MAN_OFFSET_GR_LONG, 0 },
> +	{ OV1063X_GAIN_AWB_MAN_OFFSET_R_LONG, 0 },
> +	{ OV1063X_GAIN_AWB_MAN_GAIN_B_SHORT, 128 },
> +	{ OV1063X_GAIN_AWB_MAN_GAIN_GB_SHORT, 128 },
> +	{ OV1063X_GAIN_AWB_MAN_GAIN_GR_SHORT, 128 },
> +	{ OV1063X_GAIN_AWB_MAN_GAIN_R_SHORT, 128 },
> +	{ OV1063X_GAIN_AWB_MAN_OFFSET_B_SHORT, 0 },
> +	{ OV1063X_GAIN_AWB_MAN_OFFSET_GB_SHORT, 0 },
> +	{ OV1063X_GAIN_AWB_MAN_OFFSET_GR_SHORT, 0 },
> +	{ OV1063X_GAIN_AWB_MAN_OFFSET_R_SHORT, 0 },
> +	{ OV1063X_AEC_CTRLD0, OV1063X_AEC_CTRLD0_R_MAN_EN(0) },
> +	{ OV1063X_ISP_RW06, OV1063X_ISP_RW06_YUV_MODE_MAN(2) |
> +			    OV1063X_ISP_RW06_YUV_MODE_MAN_EN },
> +	{ OV1063X_AEC_CTRL07, 0 },
> +	{ OV1063X_CIP_HFREQ_COEF_SHORT, 0x06 },
> +	{ OV1063X_CIP_MAX_SHARPEN_LONG, 0x08 },
> +	{ OV1063X_CIP_SHARPEN_ALPHA_LONG, 0x12 },
> +	{ OV1063X_CIP_SHARPEN_ALPHA_SHORT, 0x12 },
> +	{ OV1063X_CIP_UNSHARPEN_MASK_LONG(0), 0x06 },
> +	{ OV1063X_CIP_UNSHARPEN_MASK_LONG(1), 0x20 },
> +	{ OV1063X_CIP_UNSHARPEN_MASK_SHORT(0), 0x06 },
> +	{ OV1063X_CIP_UNSHARPEN_MASK_SHORT(1), 0x20 },
> +	{ OV1063X_CIP_MAX_SHARPEN_SHORT, 0x04 },
> +	{ OV1063X_LLF_MAX_LOW_LEVEL, 255 },
> +	{ OV1063X_AWB_M_X_LONG, 0x76 },
> +	{ OV1063X_AWB_M_Y_LONG, 0x47 },
> +	{ OV1063X_AWB_L_K_LONG, 0xef },
> +	{ OV1063X_AWB_H_K_LONG, 0xc9 },
> +	{ OV1063X_AWB_H_LMT_LONG, 0x49 },
> +	{ OV1063X_AWB_L_LMT_LONG, 0x30 },
> +	{ OV1063X_REG_8BIT(0x558f), 0x67 },
> +	{ OV1063X_REG_8BIT(0x5590), 0x3f },
> +	{ OV1063X_AWB_DATA_ULMT_LONG, 0xf0 },
> +	{ OV1063X_AWB_DATA_LLMT_LONG, 0x10 },
> +	{ OV1063X_AWB_M_X_SHORT, 0x6d },
> +	{ OV1063X_AWB_M_Y_SHORT, 0x55 },
> +	{ OV1063X_AWB_L_K_SHORT, 0xc3 },
> +	{ OV1063X_AWB_H_K_SHORT, 0xb5 },
> +	{ OV1063X_AWB_H_LMT_SHORT, 0x43 },
> +	{ OV1063X_AWB_L_LMT_SHORT, 0x38 },
> +	{ OV1063X_REG_8BIT(0x55a8), 0x5f },
> +	{ OV1063X_REG_8BIT(0x55a9), 0x4b },
> +	{ OV1063X_AWB_DATA_ULMT_SHORT, 0xf0 },
> +	{ OV1063X_AWB_DATA_LLMT_SHORT, 0x10 },
> +	{ OV1063X_AWB_CT_CTRL1, OV1063X_AWB_CT_CTRL1_GAIN_STEP_NORMAL(1) |
> +				OV1063X_AWB_CT_CTRL1_GAIN_STEP_FAST(1) |
> +				OV1063X_AWB_CT_CTRL1_SCALE_LONG_2X |
> +				0x02 },
> +	{ OV1063X_REG_8BIT(0x5300), 0x01 },
> +	{ OV1063X_REG_8BIT(0x5301), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5302), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5303), 0x0e },
> +	{ OV1063X_REG_8BIT(0x5304), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5305), 0x0e },
> +	{ OV1063X_REG_8BIT(0x5306), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5307), 0x36 },
> +	{ OV1063X_REG_8BIT(0x5308), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5309), 0xd9 },
> +	{ OV1063X_REG_8BIT(0x530a), 0x00 },
> +	{ OV1063X_REG_8BIT(0x530b), 0x0f },
> +	{ OV1063X_REG_8BIT(0x530c), 0x00 },
> +	{ OV1063X_REG_8BIT(0x530d), 0x2c },
> +	{ OV1063X_REG_8BIT(0x530e), 0x00 },
> +	{ OV1063X_REG_8BIT(0x530f), 0x59 },
> +	{ OV1063X_REG_8BIT(0x5310), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5311), 0x7b },
> +	{ OV1063X_REG_8BIT(0x5312), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5313), 0x22 },
> +	{ OV1063X_REG_8BIT(0x5314), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5315), 0xd5 },
> +	{ OV1063X_REG_8BIT(0x5316), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5317), 0x13 },
> +	{ OV1063X_REG_8BIT(0x5318), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5319), 0x18 },
> +	{ OV1063X_REG_8BIT(0x531a), 0x00 },
> +	{ OV1063X_REG_8BIT(0x531b), 0x26 },
> +	{ OV1063X_REG_8BIT(0x531c), 0x00 },
> +	{ OV1063X_REG_8BIT(0x531d), 0xdc },
> +	{ OV1063X_REG_8BIT(0x531e), 0x00 },
> +	{ OV1063X_REG_8BIT(0x531f), 0x02 },
> +	{ OV1063X_REG_8BIT(0x5320), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5321), 0x24 },
> +	{ OV1063X_REG_8BIT(0x5322), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5323), 0x56 },
> +	{ OV1063X_REG_8BIT(0x5324), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5325), 0x85 },
> +	{ OV1063X_REG_8BIT(0x5326), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5327), 0x20 },
> +	{ OV1063X_AEC_WIN_LEFT_LONG, 320 },
> +	{ OV1063X_AEC_WIN_LEFT_SHORT, 320 },
> +	{ OV1063X_AEC_WIN_TOP_LONG, 250 },
> +	{ OV1063X_AEC_WIN_TOP_SHORT, 250 },
> +	{ OV1063X_AEC_WIN_WIDTH_LONG, 640 },
> +	{ OV1063X_AEC_WIN_WIDTH_SHORT, 640 },
> +	{ OV1063X_AEC_WIN_HEIGHT_LONG, 300 },
> +	{ OV1063X_AEC_WIN_HEIGHT_SHORT, 300 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(0), 1 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(1), 1 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(2), 1 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(3), 1 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(4), 3 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(5), 3 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(6), 3 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(7), 5 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(8), 9 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(9), 5 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(10), 5 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(11), 5 },
> +	{ OV1063X_AEC_WEIGHT_SHORT(12), 5 },
> +	{ OV1063X_AEC_FINAL_SATURATE_THRESH, 128 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(0), 1 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(1), 3 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(2), 6 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(3), 10 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(4), 14 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(5), 18 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(6), 22 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(0), 2 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(1), 4 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(2), 8 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(3), 12 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(4), 18 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(5), 24 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(6), 30 },
> +	{ OV1063X_DNS_GBGR_EXTRA_SHORT, 4 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(0), 1 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(1), 3 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(2), 6 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(3), 10 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(4), 14 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(5), 18 },
> +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(6), 22 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(0), 3 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(1), 4 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(2), 8 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(3), 12 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(4), 18 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(5), 24 },
> +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(6), 30 },
> +	{ OV1063X_VFIFO_LLEN_FIRS1_SEL, 0x00 }, /* 8-bit YUV mode */
> +	{ OV1063X_VFIFO_LINE_LENGTH_MAN, 1905 },
> +	{ OV1063X_VFIFO_HSYNC_START_POSITION, 624 },
> +	{ OV1063X_VFIFO_HSYNC_CTRL, OV1063X_VFIFO_HSYNC_CTRL_HEADER_WIDTH(0) |
> +				    OV1063X_VFIFO_HSYNC_CTRL_TRAILER_WIDTH(0) },
> +	{ OV1063X_ROI_CTRL0, OV1063X_ROI_CTRL0_EN_3 |
> +			     OV1063X_ROI_CTRL0_EN_2 |
> +			     OV1063X_ROI_CTRL0_EN_1 },
> +	{ OV1063X_DVP_MOD_SEL, OV1063X_DVP_MOD_SEL_CCIR_F },
> +	{ OV1063X_DVP_VSYNC_WIDTH, 1 },
> +	{ OV1063X_DVP_HSYVSY_NEG_WIDTH, 0 },
> +	{ OV1063X_DVP_VSYNC_MODE, OV1063X_DVP_VSYNC_MODE_VSYNCOUT_SEL(0) },
> +	/*
> +	 * Non-overlapping HSYNC-VSYNC.
> +	 * Therefore do not set the VSYNC delay registers.
> +	 */
> +	{ OV1063X_DVP_EOF_VSYNC_DELAY, 0 },
> +	{ OV1063X_LINE_NUM, 8 },
> +	{ OV1063X_BLC_CTRL05, OV1063X_BLC_CTRL05_REMOVE_BLACK_LINE |
> +			      OV1063X_BLC_CTRL05_ONE_MAN_OFFSET_MODE },
> +	{ OV1063X_START_LINE, 4 },
> +	{ OV1063X_BLC_AVG_CTRL1, 0x20 },
> +	{ OV1063X_BLC_AVG_CTRL2, 0x22 },
> +	{ OV1063X_BLC_OFFSET_TOP_LIMIT, 1948 },
> +	{ OV1063X_BLC_CTRL5A, 0x00 },
> +	{ OV1063X_FC_R2, 2 },
> +	{ OV1063X_SC_CMMN_CORE_CTRL_2, OV1063X_SC_CMMN_CORE_CTRL_CLK_SWITCH },
> +	{ OV1063X_STREAM_MODE, OV1063X_STREAM_MODE_ON },
> +	{ OV1063X_STREAM_MODE, OV1063X_STREAM_MODE_ON },
> +	{ OV1063X_REG_8BIT(0x6f0e), 0x00 },
> +	{ OV1063X_REG_8BIT(0x6f0f), 0x00 },
> +	{ OV1063X_VFIFO_EMBD_LINE_CTRL, OV1063X_VFIFO_EMBD_LINE_CTRL_SOF_CLR_RAM },
> +	{ OV1063X_VFIFO_EMBD_LINE_NUM, 1 },
> +	{ OV1063X_REG_8BIT(0x4610), 0x00 },
> +	{ OV1063X_REG_8BIT(0x4611), 0x01 },
> +	{ OV1063X_REG_8BIT(0x4612), 0x00 },
> +	{ OV1063X_REG_8BIT(0x4613), 0x01 },
> +	{ OV1063X_VFIFO_LLEN_FIRS1_SEL, 0x00 },
> +	{ OV1063X_VFIFO_READ_START, 8 },
> +	{ OV1063X_EMB_SIZE_MANU_EN, 0 },
> +	{ OV1063X_EMB_SIZE_MANU, 1536 },
> +	{ OV1063X_GAIN_AWB_CTRL32, 0 },
> +	{ OV1063X_REG_8BIT(0x3510), 0x00 },
> +	{ OV1063X_AEC_PK_MAN_DONE, 0 },
> +	{ OV1063X_EMB_LINE_EN, 0 },
> +	{ OV1063X_REG_8BIT(0x6f0d), 0x00 },
> +	{ OV1063X_ISP_RW00, OV1063X_ISP_RW00_COLOR_MATRIX_EN |
> +			    OV1063X_ISP_RW00_COLOR_INTERP_EN |
> +			    OV1063X_ISP_RW00_DENOISE_EN |
> +			    OV1063X_ISP_RW00_WHITE_DPC_EN |
> +			    OV1063X_ISP_RW00_BLACK_DPC_EN |
> +			    OV1063X_ISP_RW00_AWB_STATS_EN |
> +			    OV1063X_ISP_RW00_AWB_GAIN_EN |
> +			    OV1063X_ISP_RW00_LSC_EN },
> +	{ OV1063X_ISP_RW01, OV1063X_ISP_RW01_DATA_WEIGHT_SYNC_EN |
> +			    OV1063X_ISP_RW01_DARK_LEVEL_FILTER_EN |
> +			    OV1063X_ISP_RW01_BUFFER_CONTROL_EN |
> +			    OV1063X_ISP_RW01_AEC_EN |
> +			    OV1063X_ISP_RW01_TONE_MAPPING_EN |
> +			    OV1063X_ISP_RW01_NORMALIZE_EN |
> +			    OV1063X_ISP_RW01_LONG_SHORT_COMB_EN },
> +	{ OV1063X_ISP_RW02, 0xf0 |
> +			    OV1063X_ISP_RW02_DIGITAL_GAIN_EN |
> +			    OV1063X_ISP_RW02_WINDOW_BORDER_CUT_EN |
> +			    OV1063X_ISP_RW02_DITHERING_EN },
> +	{ OV1063X_ISP_CTRL3D, 0 },
> +	{ OV1063X_AEC_TARGET_NUM, OV1063X_AEC_TARGET_NUM_AA_MODE },
> +	{ OV1063X_AEC_LS_SENS_RATIO, 1024 },
> +	{ OV1063X_AEC_NONWDR_EN, 0 },
> +	{ OV1063X_AEC_NONWDR_SWITCH, 0 },
> +	{ OV1063X_AEC_FIXED_RATIO_EN, 0 },
> +	{ OV1063X_AEC_GP_MODE_EN, 0 },
> +	{ OV1063X_AEC_NIGHT_MODE_EN, 0 },
> +	{ OV1063X_AEC_NIGHT_MODE_CTRL, 0 },
> +	{ OV1063X_AEC_NONLINEAR_GAIN_EN, 0 },
> +	{ OV1063X_AEC_MANU_GAMMA_EN, 0 },
> +	{ OV1063X_AEC_HOLD_BAND_EN, 0 },
> +	{ OV1063X_AEC_BAND_FILTER_FLAG, OV1063X_AEC_BAND_FILTER_FLAG_0HZ },
> +	{ OV1063X_AEC_BAND_FILTER_EN, 0 },
> +	{ OV1063X_AEC_BAND_FILTER_SHORT, 0 },
> +	{ OV1063X_AEC_LESS_1BAND_EN, 1 },
> +	{ OV1063X_AEC_LESS_1BAND_SHORT, 1 },
> +	{ OV1063X_AEC_LOG_TARGET(0), 0x8800 },
> +	{ OV1063X_AEC_LOG_TARGET(1), 0x8a00 },
> +	{ OV1063X_AEC_LOG_TARGET(2), 0x8600 },
> +	{ OV1063X_AEC_TARGET_LONG(0), 0x40 },
> +	{ OV1063X_AEC_TARGET_LONG(1), 0x50 },
> +	{ OV1063X_AEC_TARGET_LONG(2), 0x30 },
> +	{ OV1063X_AEC_TARGET_SHORT(0), 0x28 },
> +	{ OV1063X_AEC_TARGET_SHORT(1), 0x60 },
> +	{ OV1063X_AEC_TARGET_SHORT(2), 0x40 },
> +	{ OV1063X_AEC_MAX_SHORT_LE, 0x01380000 },
> +	{ OV1063X_AEC_MAX_GAIN_LONG, 255 },
> +	{ OV1063X_AEC_MAX_GAIN_SHORT, 64 },
> +	{ OV1063X_AEC_MIN_GAIN_LONG, 24 },
> +	{ OV1063X_AEC_MIN_GAIN_SHORT, 24 },
> +	{ OV1063X_AEC_MAX_EXP_LONG, 11904 },
> +	{ OV1063X_AEC_MAX_EXP_SHORT, 11904 },
> +	{ OV1063X_AEC_MIN_EXP_LONG, 4 },
> +	{ OV1063X_AEC_MIN_EXP_SHORT, 4 },
> +	{ OV1063X_AEC_FIXED_RATIO, 0x07 },
> +	{ OV1063X_AEC_GP_MODE_RATIO_B2A, 0x20 },
> +	{ OV1063X_AEC_GP_MODE_RATIO_C2A, 0x08 },
> +	{ OV1063X_AEC_MIN_GAMMA_LIST(0), 512 },
> +	{ OV1063X_AEC_MIN_GAMMA_LIST(1), 512 },
> +	{ OV1063X_AEC_MIN_GAMMA_LIST(2), 512 },
> +	{ OV1063X_AEC_MAX_GAMMA_LIST(0), 308 },
> +	{ OV1063X_AEC_MAX_GAMMA_LIST(1), 1024 },
> +	{ OV1063X_AEC_MAX_GAMMA_LIST(2), 1536 },
> +	{ OV1063X_AEC_DR_LIST(0), 16 },
> +	{ OV1063X_AEC_DR_LIST(1), 64 },
> +	{ OV1063X_AEC_DR_LIST(2), 128 },
> +	{ OV1063X_AEC_BAND_VALUE_60HZ, 3328 },
> +	{ OV1063X_AEC_BAND_VALUE_50HZ, 4032 },
> +	{ OV1063X_REG_8BIT(0xc4b4), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc4b5), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc4b6), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc4b7), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc4b8), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc4b9), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc4ba), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc4bb), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc4be), 0x02 },
> +	{ OV1063X_REG_8BIT(0xc4bf), 0x33 },
> +	{ OV1063X_REG_8BIT(0xc4c8), 0x03 },
> +	{ OV1063X_REG_8BIT(0xc4c9), 0xd0 },
> +	{ OV1063X_REG_8BIT(0xc4ca), 0x0e },
> +	{ OV1063X_REG_8BIT(0xc4cb), 0x00 },
> +	{ OV1063X_AWB_SIMPLE_MIN_NUM, 3665 },
> +	{ OV1063X_AWB_CT_MIN_NUM, 3665 },
> +	{ OV1063X_REG_8BIT(0xc4d0), 0x04 },
> +	{ OV1063X_REG_8BIT(0xc4d1), 0x80 },
> +	{ OV1063X_REG_8BIT(0xc4e0), 0x04 },
> +	{ OV1063X_REG_8BIT(0xc4e1), 0x02 },
> +	{ OV1063X_REG_8BIT(0xc4e2), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc4e4), 0x10 },
> +	{ OV1063X_REG_8BIT(0xc4e5), 0x20 },
> +	{ OV1063X_REG_8BIT(0xc4e6), 0x30 },
> +	{ OV1063X_REG_8BIT(0xc4e7), 0x40 },
> +	{ OV1063X_REG_8BIT(0xc4e8), 0x50 },
> +	{ OV1063X_REG_8BIT(0xc4e9), 0x60 },
> +	{ OV1063X_REG_8BIT(0xc4ea), 0x70 },
> +	{ OV1063X_REG_8BIT(0xc4eb), 0x80 },
> +	{ OV1063X_REG_8BIT(0xc4ec), 0x90 },
> +	{ OV1063X_REG_8BIT(0xc4ed), 0xa0 },
> +	{ OV1063X_REG_8BIT(0xc4ee), 0xb0 },
> +	{ OV1063X_REG_8BIT(0xc4ef), 0xc0 },
> +	{ OV1063X_REG_8BIT(0xc4f0), 0xd0 },
> +	{ OV1063X_REG_8BIT(0xc4f1), 0xe0 },
> +	{ OV1063X_REG_8BIT(0xc4f2), 0xf0 },
> +	{ OV1063X_REG_8BIT(0xc4f3), 0x80 },
> +	{ OV1063X_REG_8BIT(0xc4f4), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc4f5), 0x20 },
> +	{ OV1063X_REG_8BIT(0xc4f6), 0x02 },
> +	{ OV1063X_REG_8BIT(0xc4f7), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc4f8), 0x04 },
> +	{ OV1063X_REG_8BIT(0xc4f9), 0x0b },
> +	{ OV1063X_REG_8BIT(0xc4fa), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc4fb), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc4fc), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc4fd), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc4fe), 0x04 },
> +	{ OV1063X_REG_8BIT(0xc4ff), 0x02 },
> +	{ OV1063X_REG_8BIT(0xc500), 0x68 },
> +	{ OV1063X_REG_8BIT(0xc501), 0x74 },
> +	{ OV1063X_REG_8BIT(0xc502), 0x70 },
> +	{ OV1063X_REG_8BIT(0xc503), 0x80 },
> +	{ OV1063X_REG_8BIT(0xc504), 0x05 },
> +	{ OV1063X_REG_8BIT(0xc505), 0x80 },
> +	{ OV1063X_REG_8BIT(0xc506), 0x03 },
> +	{ OV1063X_REG_8BIT(0xc507), 0x80 },
> +	{ OV1063X_REG_8BIT(0xc508), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc509), 0xc0 },
> +	{ OV1063X_REG_8BIT(0xc50a), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc50b), 0xa0 },
> +	{ OV1063X_REG_8BIT(0xc50c), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc50d), 0x2c },
> +	{ OV1063X_REG_8BIT(0xc50e), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc50f), 0x0a },
> +	{ OV1063X_REG_8BIT(0xc510), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc511), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc512), 0xe5 },
> +	{ OV1063X_REG_8BIT(0xc513), 0x14 },
> +	{ OV1063X_REG_8BIT(0xc514), 0x04 },
> +	{ OV1063X_REG_8BIT(0xc515), 0x00 },
> +	{ OV1063X_VTS_ADDR, 840 },
> +	{ OV1063X_HTS_ADDR, 1904 },
> +	{ OV1063X_REG_8BIT(0xc2e0), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc2e1), 0x51 },
> +	{ OV1063X_REG_8BIT(0xc2e2), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc2e3), 0xd6 },
> +	{ OV1063X_REG_8BIT(0xc2e4), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc2e5), 0x5e },
> +	{ OV1063X_REG_8BIT(0xc2e9), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc2ea), 0x7a },
> +	{ OV1063X_REG_8BIT(0xc2eb), 0x90 },
> +	{ OV1063X_REG_8BIT(0xc2ed), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc2ee), 0x7a },
> +	{ OV1063X_REG_8BIT(0xc2ef), 0x64 },
> +	{ OV1063X_REG_8BIT(0xc308), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc309), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc30a), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc30c), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc30d), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc30e), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc30f), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc310), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc311), 0x60 },
> +	{ OV1063X_REG_8BIT(0xc312), 0xff },
> +	{ OV1063X_REG_8BIT(0xc313), 0x08 },
> +	{ OV1063X_REG_8BIT(0xc314), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc315), 0x7f },
> +	{ OV1063X_REG_8BIT(0xc316), 0xff },
> +	{ OV1063X_REG_8BIT(0xc317), 0x0b },
> +	{ OV1063X_REG_8BIT(0xc318), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc319), 0x0c },
> +	{ OV1063X_REG_8BIT(0xc31a), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc31b), 0xe0 },
> +	{ OV1063X_REG_8BIT(0xc31c), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc31d), 0x14 },
> +	{ OV1063X_REG_8BIT(0xc31e), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc31f), 0xc5 },
> +	{ OV1063X_REG_8BIT(0xc320), 0xff },
> +	{ OV1063X_REG_8BIT(0xc321), 0x4b },
> +	{ OV1063X_REG_8BIT(0xc322), 0xff },
> +	{ OV1063X_REG_8BIT(0xc323), 0xf0 },
> +	{ OV1063X_REG_8BIT(0xc324), 0xff },
> +	{ OV1063X_REG_8BIT(0xc325), 0xe8 },
> +	{ OV1063X_REG_8BIT(0xc326), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc327), 0x46 },
> +	{ OV1063X_REG_8BIT(0xc328), 0xff },
> +	{ OV1063X_REG_8BIT(0xc329), 0xd2 },
> +	{ OV1063X_REG_8BIT(0xc32a), 0xff },
> +	{ OV1063X_REG_8BIT(0xc32b), 0xe4 },
> +	{ OV1063X_REG_8BIT(0xc32c), 0xff },
> +	{ OV1063X_REG_8BIT(0xc32d), 0xbb },
> +	{ OV1063X_REG_8BIT(0xc32e), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc32f), 0x61 },
> +	{ OV1063X_REG_8BIT(0xc330), 0xff },
> +	{ OV1063X_REG_8BIT(0xc331), 0xf9 },
> +	{ OV1063X_REG_8BIT(0xc332), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc333), 0xd9 },
> +	{ OV1063X_REG_8BIT(0xc334), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc335), 0x2e },
> +	{ OV1063X_REG_8BIT(0xc336), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc337), 0xb1 },
> +	{ OV1063X_REG_8BIT(0xc338), 0xff },
> +	{ OV1063X_REG_8BIT(0xc339), 0x64 },
> +	{ OV1063X_REG_8BIT(0xc33a), 0xff },
> +	{ OV1063X_REG_8BIT(0xc33b), 0xeb },
> +	{ OV1063X_REG_8BIT(0xc33c), 0xff },
> +	{ OV1063X_REG_8BIT(0xc33d), 0xe8 },
> +	{ OV1063X_REG_8BIT(0xc33e), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc33f), 0x48 },
> +	{ OV1063X_REG_8BIT(0xc340), 0xff },
> +	{ OV1063X_REG_8BIT(0xc341), 0xd0 },
> +	{ OV1063X_REG_8BIT(0xc342), 0xff },
> +	{ OV1063X_REG_8BIT(0xc343), 0xed },
> +	{ OV1063X_REG_8BIT(0xc344), 0xff },
> +	{ OV1063X_REG_8BIT(0xc345), 0xad },
> +	{ OV1063X_REG_8BIT(0xc346), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc347), 0x66 },
> +	{ OV1063X_REG_8BIT(0xc348), 0x01 },
> +	{ OV1063X_REG_8BIT(0xc349), 0x00 },
> +	{ OV1063X_REG_8BIT(0x6700), 0x04 },
> +	{ OV1063X_REG_8BIT(0x6701), 0x7b },
> +	{ OV1063X_REG_8BIT(0x6702), 0xfd },
> +	{ OV1063X_REG_8BIT(0x6703), 0xf9 },
> +	{ OV1063X_REG_8BIT(0x6704), 0x3d },
> +	{ OV1063X_REG_8BIT(0x6705), 0x71 },
> +	{ OV1063X_TPM_CTRL0, 0x70 | OV1063X_TPM_CTRL0_CLK_DIV(1) },
> +	{ OV1063X_REG_8BIT(0x6708), 0x05 },
> +	{ OV1063X_REG_8BIT(0x3822), 0x50 },
> +	{ OV1063X_PARI_ADDR_MIN, 0x6f00 },
> +	{ OV1063X_PARI_ADDR_MAX, 0x6f00 },
> +	{ OV1063X_GROUP_WRITER_COMMAND, OV1063X_GROUP_WRITER_COMMAND_EN },
> +};
> +
> +static const struct ov1063x_reg ov1063x_regs_bt656[] = {
> +	{ OV1063X_DVP_MOD_SEL, OV1063X_DVP_MOD_SEL_CCIR_656 },
> +	{ OV1063X_FORMAT_YMAX, 1016 },
> +	{ OV1063X_FORMAT_YMIN, 8 },
> +	{ OV1063X_FORMAT_UMAX, 1016 },
> +	{ OV1063X_FORMAT_UMIN, 8 },
> +};
> +
> +static const struct ov1063x_reg ov1063x_regs_bt656_10bit[] = {
> +	{ OV1063X_DVP_MOD_SEL, OV1063X_DVP_MOD_SEL_CCIR_656 },
> +	{ OV1063X_FORMAT_YMAX, 1022 },
> +	{ OV1063X_FORMAT_YMIN, 2 },
> +	{ OV1063X_FORMAT_UMAX, 1022 },
> +	{ OV1063X_FORMAT_UMIN, 2 },
> +};
> +
> +static const struct ov1063x_reg ov1063x_regs_vert_no_sub[] = {
> +	{ OV1063X_TIMING_CTRL1C, 0 },
> +	{ OV1063X_VSTART_OFFSET, 12 },
> +	{ OV1063X_START_LINE, 4 },
> +	{ OV1063X_LINE_NUM, 8 },
> +	{ OV1063X_BLC_AVG_CTRL1, 0x20 },
> +	{ OV1063X_BLC_AVG_CTRL2, 0x22 },
> +	{ OV1063X_REG_8BIT(0x6e47), 0x0c },
> +	{ OV1063X_REG_8BIT(0x4610), 0x05 },
> +	{ OV1063X_REG_8BIT(0x4613), 0x10 },
> +};
> +
> +static const struct ov1063x_reg ov1063x_regs_vert_sub2[] = {
> +	{ OV1063X_TIMING_CTRL1C, OV1063X_TIMING_CTRL1C_VSUB2 },
> +	{ OV1063X_VSTART_OFFSET, 6 },
> +	{ OV1063X_START_LINE, 2 },
> +	{ OV1063X_LINE_NUM, 2 },
> +	{ OV1063X_BLC_AVG_CTRL1, 0x10 },
> +	{ OV1063X_BLC_AVG_CTRL2, 0x11 },
> +	{ OV1063X_REG_8BIT(0x6e47), 0x06 },
> +	{ OV1063X_REG_8BIT(0x4610), 0x03 },
> +	{ OV1063X_REG_8BIT(0x4613), 0x0a },
> +};
> +
> +/*
> + * Datasheet highlight the following sequence to enable and disable
> + * Test Pattern mode i.e. colobar
> + */
> +static const struct ov1063x_reg ov1063x_regs_colorbar_enable[] = {
> +	{ OV1063X_GAIN_AWB_CTRL32, OV1063X_GAIN_AWB_CTRL32_MANUAL_EN },
> +	{ OV1063X_AEC_CTRLD0, OV1063X_AEC_CTRLD0_R_MAN_EN(1) },
> +	{ OV1063X_REG_8BIT(0x5300), 0x01 }, { OV1063X_REG_8BIT(0x5301), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5302), 0x00 }, { OV1063X_REG_8BIT(0x5303), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5304), 0x00 }, { OV1063X_REG_8BIT(0x5305), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5306), 0x00 }, { OV1063X_REG_8BIT(0x5307), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5308), 0x01 }, { OV1063X_REG_8BIT(0x5309), 0x00 },
> +	{ OV1063X_REG_8BIT(0x530a), 0x00 }, { OV1063X_REG_8BIT(0x530b), 0x00 },
> +	{ OV1063X_REG_8BIT(0x530c), 0x00 }, { OV1063X_REG_8BIT(0x530d), 0x00 },
> +	{ OV1063X_REG_8BIT(0x530e), 0x00 }, { OV1063X_REG_8BIT(0x530f), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5310), 0x01 }, { OV1063X_REG_8BIT(0x5311), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5312), 0x00 }, { OV1063X_REG_8BIT(0x5313), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5314), 0x01 }, { OV1063X_REG_8BIT(0x5315), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5316), 0x00 }, { OV1063X_REG_8BIT(0x5317), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5318), 0x00 }, { OV1063X_REG_8BIT(0x5319), 0x00 },
> +	{ OV1063X_REG_8BIT(0x531a), 0x00 }, { OV1063X_REG_8BIT(0x531b), 0x00 },
> +	{ OV1063X_REG_8BIT(0x531c), 0x01 }, { OV1063X_REG_8BIT(0x531d), 0x00 },
> +	{ OV1063X_REG_8BIT(0x531e), 0x00 }, { OV1063X_REG_8BIT(0x531f), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5320), 0x00 }, { OV1063X_REG_8BIT(0x5321), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5322), 0x00 }, { OV1063X_REG_8BIT(0x5323), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5324), 0x01 }, { OV1063X_REG_8BIT(0x5325), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5326), 0x00 }, { OV1063X_REG_8BIT(0x5327), 0x00 },
> +	{ OV1063X_REG_8BIT(0xc2ea), 0x80 }, { OV1063X_REG_8BIT(0xc2eb), 0x80 },
> +	{ OV1063X_ISP_RW00, OV1063X_ISP_RW00_COLOR_INTERP_EN |
> +			    OV1063X_ISP_RW00_DENOISE_EN |
> +			    OV1063X_ISP_RW00_WHITE_DPC_EN |
> +			    OV1063X_ISP_RW00_BLACK_DPC_EN |
> +			    OV1063X_ISP_RW00_LSC_EN },
> +};
> +
> +static const struct ov1063x_reg ov1063x_regs_colorbar_disable[] = {
> +	{ OV1063X_ISP_CTRL3D, 0 },
> +	{ OV1063X_ISP_CTRL3E, 0 },
> +	{ OV1063X_GAIN_AWB_CTRL32, 0 },
> +	{ OV1063X_AEC_CTRLD0, OV1063X_AEC_CTRLD0_R_MAN_EN(0) },
> +	{ OV1063X_REG_8BIT(0x5300), 0x01 }, { OV1063X_REG_8BIT(0x5301), 0x00 },
> +	{ OV1063X_REG_8BIT(0x5302), 0x00 }, { OV1063X_REG_8BIT(0x5303), 0x0e },
> +	{ OV1063X_REG_8BIT(0x5304), 0x00 }, { OV1063X_REG_8BIT(0x5305), 0x0e },
> +	{ OV1063X_REG_8BIT(0x5306), 0x00 }, { OV1063X_REG_8BIT(0x5307), 0x36 },
> +	{ OV1063X_REG_8BIT(0x5308), 0x00 }, { OV1063X_REG_8BIT(0x5309), 0xd9 },
> +	{ OV1063X_REG_8BIT(0x530a), 0x00 }, { OV1063X_REG_8BIT(0x530b), 0x0f },
> +	{ OV1063X_REG_8BIT(0x530c), 0x00 }, { OV1063X_REG_8BIT(0x530d), 0x2c },
> +	{ OV1063X_REG_8BIT(0x530e), 0x00 }, { OV1063X_REG_8BIT(0x530f), 0x59 },
> +	{ OV1063X_REG_8BIT(0x5310), 0x00 }, { OV1063X_REG_8BIT(0x5311), 0x7b },
> +	{ OV1063X_REG_8BIT(0x5312), 0x00 }, { OV1063X_REG_8BIT(0x5313), 0x22 },
> +	{ OV1063X_REG_8BIT(0x5314), 0x00 }, { OV1063X_REG_8BIT(0x5315), 0xd5 },
> +	{ OV1063X_REG_8BIT(0x5316), 0x00 }, { OV1063X_REG_8BIT(0x5317), 0x13 },
> +	{ OV1063X_REG_8BIT(0x5318), 0x00 }, { OV1063X_REG_8BIT(0x5319), 0x18 },
> +	{ OV1063X_REG_8BIT(0x531a), 0x00 }, { OV1063X_REG_8BIT(0x531b), 0x26 },
> +	{ OV1063X_REG_8BIT(0x531c), 0x00 }, { OV1063X_REG_8BIT(0x531d), 0xdc },
> +	{ OV1063X_REG_8BIT(0x531e), 0x00 }, { OV1063X_REG_8BIT(0x531f), 0x02 },
> +	{ OV1063X_REG_8BIT(0x5320), 0x00 }, { OV1063X_REG_8BIT(0x5321), 0x24 },
> +	{ OV1063X_REG_8BIT(0x5322), 0x00 }, { OV1063X_REG_8BIT(0x5323), 0x56 },
> +	{ OV1063X_REG_8BIT(0x5324), 0x00 }, { OV1063X_REG_8BIT(0x5325), 0x85 },
> +	{ OV1063X_REG_8BIT(0x5326), 0x00 }, { OV1063X_REG_8BIT(0x5327), 0x20 },
> +	{ OV1063X_REG_8BIT(0xc2ea), 0x7a }, { OV1063X_REG_8BIT(0xc2eb), 0x90 },
> +	{ OV1063X_ISP_RW00, OV1063X_ISP_RW00_COLOR_MATRIX_EN |
> +			    OV1063X_ISP_RW00_COLOR_INTERP_EN |
> +			    OV1063X_ISP_RW00_DENOISE_EN |
> +			    OV1063X_ISP_RW00_WHITE_DPC_EN |
> +			    OV1063X_ISP_RW00_BLACK_DPC_EN |
> +			    OV1063X_ISP_RW00_AWB_STATS_EN |
> +			    OV1063X_ISP_RW00_AWB_GAIN_EN |
> +			    OV1063X_ISP_RW00_LSC_EN },
> +};
Sakari Ailus Jan. 4, 2021, 12:47 p.m. UTC | #2
Hi Laurent,

On Mon, Jan 04, 2021 at 07:39:45AM +0200, Laurent Pinchart wrote:
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 878f66ef2719..84a97989775e 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -1050,6 +1050,18 @@ config VIDEO_OV9650
>  	  This is a V4L2 sensor driver for the Omnivision
>  	  OV9650 and OV9652 camera sensors.
>  
> +config VIDEO_OV10633
> +	tristate "OmniVision OV10633/OV10635 sensor support"
> +	depends on I2C && VIDEO_V4L2
> +	depends on GPIOLIB && OF
> +	select MEDIA_CONTROLLER
> +	select REGMAP_I2C

Should this be SCCB instead?

Likewise for the driver.
Laurent Pinchart Jan. 4, 2021, 1:05 p.m. UTC | #3
Hi Sakari,

On Mon, Jan 04, 2021 at 02:47:00PM +0200, Sakari Ailus wrote:
> Hi Laurent,
> 
> On Mon, Jan 04, 2021 at 07:39:45AM +0200, Laurent Pinchart wrote:
> > diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> > index 878f66ef2719..84a97989775e 100644
> > --- a/drivers/media/i2c/Kconfig
> > +++ b/drivers/media/i2c/Kconfig
> > @@ -1050,6 +1050,18 @@ config VIDEO_OV9650
> >  	  This is a V4L2 sensor driver for the Omnivision
> >  	  OV9650 and OV9652 camera sensors.
> >  
> > +config VIDEO_OV10633
> > +	tristate "OmniVision OV10633/OV10635 sensor support"
> > +	depends on I2C && VIDEO_V4L2
> > +	depends on GPIOLIB && OF
> > +	select MEDIA_CONTROLLER
> > +	select REGMAP_I2C
> 
> Should this be SCCB instead?
> 
> Likewise for the driver.

The OV1063x has 16-bit register addresses, and, unless I'm mistaken,
regmap_sccb assumes register addresses to be 8-bit long.
Sakari Ailus Jan. 4, 2021, 1:55 p.m. UTC | #4
On Mon, Jan 04, 2021 at 03:05:05PM +0200, Laurent Pinchart wrote:
> Hi Sakari,
> 
> On Mon, Jan 04, 2021 at 02:47:00PM +0200, Sakari Ailus wrote:
> > Hi Laurent,
> > 
> > On Mon, Jan 04, 2021 at 07:39:45AM +0200, Laurent Pinchart wrote:
> > > diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> > > index 878f66ef2719..84a97989775e 100644
> > > --- a/drivers/media/i2c/Kconfig
> > > +++ b/drivers/media/i2c/Kconfig
> > > @@ -1050,6 +1050,18 @@ config VIDEO_OV9650
> > >  	  This is a V4L2 sensor driver for the Omnivision
> > >  	  OV9650 and OV9652 camera sensors.
> > >  
> > > +config VIDEO_OV10633
> > > +	tristate "OmniVision OV10633/OV10635 sensor support"
> > > +	depends on I2C && VIDEO_V4L2
> > > +	depends on GPIOLIB && OF
> > > +	select MEDIA_CONTROLLER
> > > +	select REGMAP_I2C
> > 
> > Should this be SCCB instead?
> > 
> > Likewise for the driver.
> 
> The OV1063x has 16-bit register addresses, and, unless I'm mistaken,
> regmap_sccb assumes register addresses to be 8-bit long.

It seems so. I wonder what's the meaning of SCCB in this case. A number of
drivers (three) require REGMAP_SCCB instead of REGMAP_I2C. Could it just be
someone needed those drivers on controllers with just SMBUS functionality?

I guess this is fine then.
Laurent Pinchart Jan. 4, 2021, 1:56 p.m. UTC | #5
Hi Sakari,

On Mon, Jan 04, 2021 at 01:41:15PM +0200, Sakari Ailus wrote:
> Hi Laurent,
> 
> Thanks for the patchset.
> 
> On Mon, Jan 04, 2021 at 07:39:45AM +0200, Laurent Pinchart wrote:
> > Add a new V4L2 subdev driver for the OmniVision OV10633 and OV10635
> > camera sensors. The work is based on the driver from the TI BSP, itself
> > based on original work by Phil Edworthy posted to the linux-media
> > mailing list ([1]). This version of the code is a large rewrite of many
> > parts.
> 
> The driver seems generally quite nice. It doesn't check known-good link
> frequencies are not defined in bindings nor checked by the driver. Could
> you add them?

Good point.

> Same or the assigned-clock-rates in bindings.
> 
> Please see more comments below.
> 
> > [1] http://www.spinics.net/lists/linux-media/msg64347.html
> > 
> > Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
> > Signed-off-by: Benoit Parrot <bparrot@ti.com>
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  MAINTAINERS                      |    2 +
> >  drivers/media/i2c/Kconfig        |   12 +
> >  drivers/media/i2c/Makefile       |    1 +
> >  drivers/media/i2c/ov1063x.c      | 1692 ++++++++++++++++++++++++++++++
> >  drivers/media/i2c/ov1063x_regs.h |  626 +++++++++++
> >  5 files changed, 2333 insertions(+)
> >  create mode 100644 drivers/media/i2c/ov1063x.c
> >  create mode 100644 drivers/media/i2c/ov1063x_regs.h
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 9dc3a7d75460..4b94061130cf 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -12873,6 +12873,8 @@ L:	linux-media@vger.kernel.org
> >  S:	Maintained
> >  T:	git git://linuxtv.org/media_tree.git
> >  F:	Documentation/devicetree/bindings/media/i2c/ov1063x.yaml
> > +F:	drivers/media/i2c/ov1063x.c
> > +F:	drivers/media/i2c/ov1063x_regs.h
> >  
> >  OMNIVISION OV13858 SENSOR DRIVER
> >  M:	Sakari Ailus <sakari.ailus@linux.intel.com>
> > diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> > index 878f66ef2719..84a97989775e 100644
> > --- a/drivers/media/i2c/Kconfig
> > +++ b/drivers/media/i2c/Kconfig
> > @@ -1050,6 +1050,18 @@ config VIDEO_OV9650
> >  	  This is a V4L2 sensor driver for the Omnivision
> >  	  OV9650 and OV9652 camera sensors.
> >  
> > +config VIDEO_OV10633
> > +	tristate "OmniVision OV10633/OV10635 sensor support"
> > +	depends on I2C && VIDEO_V4L2
> > +	depends on GPIOLIB && OF
> > +	select MEDIA_CONTROLLER
> > +	select REGMAP_I2C
> > +	select V4L2_FWNODE
> > +	select VIDEO_V4L2_SUBDEV_API
> > +	help
> > +	  This is a Video4Linux2 driver for the OmniVision
> > +	  OV10633 and OV10635 camera sensors.
> > +
> >  config VIDEO_OV13858
> >  	tristate "OmniVision OV13858 sensor support"
> >  	depends on I2C && VIDEO_V4L2
> > diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> > index f0a77473979d..6eef97e2423d 100644
> > --- a/drivers/media/i2c/Makefile
> > +++ b/drivers/media/i2c/Makefile
> > @@ -83,6 +83,7 @@ obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
> >  obj-$(CONFIG_VIDEO_OV8856) += ov8856.o
> >  obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
> >  obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
> > +obj-$(CONFIG_VIDEO_OV10633) += ov1063x.o
> >  obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
> >  obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
> >  obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
> > diff --git a/drivers/media/i2c/ov1063x.c b/drivers/media/i2c/ov1063x.c
> > new file mode 100644
> > index 000000000000..5b25ed5e766b
> > --- /dev/null
> > +++ b/drivers/media/i2c/ov1063x.c
> > @@ -0,0 +1,1692 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * OmniVision OV10633/OV10635 Camera Driver
> > + *
> > + * Based on the original driver written by Phil Edworthy.
> > + * Copyright (C) 2013 Phil Edworthy
> > + * Copyright (C) 2013 Renesas Electronics
> > + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
> > + * Copyright (C) 2020 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/i2c.h>
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/regmap.h>
> > +#include <linux/slab.h>
> > +#include <linux/v4l2-mediabus.h>
> > +#include <linux/videodev2.h>
> > +
> > +#include <media/v4l2-common.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/v4l2-event.h>
> > +#include <media/v4l2-fwnode.h>
> > +#include <media/v4l2-subdev.h>
> > +
> > +/* Register definitions */
> > +#define OV1063X_REG_8BIT(n)			((1 << 16) | (n))
> > +#define OV1063X_REG_16BIT(n)			((2 << 16) | (n))
> > +#define OV1063X_REG_24BIT(n)			((3 << 16) | (n))
> > +#define OV1063X_REG_32BIT(n)			((4 << 16) | (n))
> > +#define OV1063X_REG_SIZE_SHIFT			16
> > +#define OV1063X_REG_ADDR_MASK			0xffff
> > +
> > +#define OV1063X_STREAM_MODE			OV1063X_REG_8BIT(0x0100)
> > +#define OV1063X_STREAM_MODE_ON			BIT(0)
> > +#define OV1063X_SOFTWARE_RESET			OV1063X_REG_8BIT(0x0103)
> > +
> > +#define OV1063X_SC_CMMN_PLL_CTRL0		OV1063X_REG_8BIT(0x3003)
> > +#define OV1063X_SC_CMMN_PLL_SCLK_CP(n)		((n) << 6)
> > +#define OV1063X_SC_CMMN_PLL_SCLK_MULTI(n)	((n) << 0)
> > +#define OV1063X_SC_CMMN_PLL_CTRL1		OV1063X_REG_8BIT(0x3004)
> > +#define OV1063X_SC_CMMN_PLL_SCLK_BYPASS		BIT(7)
> > +#define OV1063X_SC_CMMN_PLL_SCLK_PRE_DIV(n)	((n) << 4)	/* /1, /1.5, /2, /3, /4, /5, /6, /7 */
> > +#define OV1063X_SC_CMMN_PLL_SCLK_CP2(n)		((n) << 3)
> > +#define OV1063X_SC_CMMN_PLL_SCLK_DIV(n)		((n) << 0)	/* Divider = 2 * (1 + n) */
> > +#define OV1063X_SC_CMMN_PLL_CTRL2		OV1063X_REG_8BIT(0x3005)
> > +#define OV1063X_SC_CMMN_PLL_PCLK_CP(n)		((n) << 6)
> > +#define OV1063X_SC_CMMN_PLL_PCLK_MULTI(n)	((n) << 0)
> > +#define OV1063X_SC_CMMN_PLL_CTRL3		OV1063X_REG_8BIT(0x3006)
> > +#define OV1063X_SC_CMMN_PLL_PCLK_BYPASS		BIT(7)
> > +#define OV1063X_SC_CMMN_PLL_PCLK_PRE_DIV(n)	((n) << 4)	/* /1, /1.5, /2, /3, /4, /5, /6, /7 */
> > +#define OV1063X_SC_CMMN_PLL_PCLK_CP2(n)		((n) << 3)
> > +#define OV1063X_SC_CMMN_PLL_PCLK_DIV(n)		((n) << 0)	/* Divider = 2 * (1 + n) */
> > +#define OV1063X_SC_CMMN_PCLK_DIV_CTRL		OV1063X_REG_8BIT(0x3007)
> > +#define OV1063X_PID				OV1063X_REG_16BIT(0x300a)
> > +#define OV1063X_SC_CMMN_SCCB_ID			OV1063X_REG_8BIT(0x300c)
> > +#define OV1063X_SC_CMMN_SCCB_ID_ADDR(n)		((n) << 1)
> > +#define OV1063X_SC_CMMN_SCCB_ID_SEL		BIT(0)
> > +#define OV1063X_SC_CMMN_PAD			OV1063X_REG_8BIT(0x3011)
> > +#define OV1063X_SC_CMMN_PAD_DRIVE(n)		((n) << 6)
> > +#define OV1063X_SC_CMMN_CLKRST0			OV1063X_REG_8BIT(0x301a)
> > +#define OV1063X_SC_CMMN_CLKRST0_SCLK		GENMASK(7, 4)
> > +#define OV1063X_SC_CMMN_CLKRST0_RST		GENMASK(3, 0)
> > +#define OV1063X_SC_CMMN_CLKRST1			OV1063X_REG_8BIT(0x301b)
> > +#define OV1063X_SC_CMMN_CLKRST1_SCLK		GENMASK(7, 4)
> > +#define OV1063X_SC_CMMN_CLKRST1_RST		GENMASK(3, 0)
> > +#define OV1063X_SC_CMMN_CLKRST2			OV1063X_REG_8BIT(0x301c)
> > +#define OV1063X_SC_CMMN_CLKRST2_PCLK_DVP	BIT(7)
> > +#define OV1063X_SC_CMMN_CLKRST2_SCLK		GENMASK(6, 4)
> > +#define OV1063X_SC_CMMN_CLKRST2_RST_DVP		BIT(3)
> > +#define OV1063X_SC_CMMN_CLKRST2_RST		GENMASK(2, 0)
> > +#define OV1063X_SC_CMMN_CLOCK_SEL		OV1063X_REG_8BIT(0x3020)
> > +#define OV1063X_SC_CMMN_MISC_CTRL		OV1063X_REG_8BIT(0x3021)
> > +#define OV1063X_SC_CMMN_MISC_CTRL_PCLK_INV	BIT(7)
> > +#define OV1063X_SC_CMMN_MISC_CTRL_SCLK_INV	BIT(6)
> > +#define OV1063X_SC_CMMN_MISC_CTRL_SCLK2X_INV	BIT(5)
> > +#define OV1063X_SC_CMMN_MISC_CTRL_CEN_GLOBAL_O	BIT(0)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_1		OV1063X_REG_8BIT(0x3022)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_2		OV1063X_REG_8BIT(0x3023)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_BIST_EN	BIT(5)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_CLK_SWITCH	BIT(4)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_3		OV1063X_REG_8BIT(0x3024)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_RAW_LONG	(0U << 4)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_RAW_SHORT	(1U << 4)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_RAW_LONG_SHORT	(2U << 4)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_RAW_COMBINED	(0U << 4)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_YUV_LONG	(1U << 1)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_YUV_SHORT	(2U << 1)
> > +#define OV1063X_SC_CMMN_CORE_CTRL_PCLK_SYS	(0U << 0)	/* PCLK from system PLL */
> > +#define OV1063X_SC_CMMN_CORE_CTRL_PCLK_SEC	(1U << 0)	/* PCLK from secondary PLL */
> > +#define OV1063X_SC_CMMN_CORE_CTRL1		OV1063X_REG_8BIT(0x3025)
> > +#define OV1063X_SC_CMMN_PWDN_CTRL2		OV1063X_REG_8BIT(0x302d)
> > +#define OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG1	BIT(3)
> > +#define OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG2	BIT(2)
> > +#define OV1063X_SC_CMMN_PWDN_CTRL2_RST_ISP	BIT(1)
> > +#define OV1063X_SC_CMMN_PWDN_CTRL2_SEQUENCE	BIT(0)
> > +#define OV1063X_SC_CMMN_SCLK2X_SEL		OV1063X_REG_8BIT(0x3033)
> > +#define OV1063X_SC_CMMN_SCLK2X_SEL_DIV2		(1U << 2)
> > +#define OV1063X_SC_CMMN_SCLK2X_SEL_DIV4		(2U << 2)
> > +#define OV1063X_SC_SOC_CLKRST7			OV1063X_REG_8BIT(0x3042)
> > +#define OV1063X_SC_SOC_CLKRST7_SCLK		GENMASK(7, 4)
> > +#define OV1063X_SC_SOC_CLKRST7_RST		GENMASK(3, 0)
> > +
> > +#define OV1063X_AEC_PK_MANUAL			OV1063X_REG_8BIT(0x3503)
> > +#define OV1063X_AEC_PK_MANUAL_GAIN_DELAY	BIT(5)
> > +#define OV1063X_AEC_PK_MANUAL_DELAY		BIT(4)
> > +#define OV1063X_AEC_PK_MAN_DONE			OV1063X_REG_8BIT(0x3504)
> > +#define OV1063X_AEC_PK_MAN_DONE_AEC_DONE	BIT(0)
> > +
> > +#define OV1063X_ANA_ADC1			OV1063X_REG_8BIT(0x3600)
> > +#define OV1063X_ANA_ADC2			OV1063X_REG_8BIT(0x3601)
> > +#define OV1063X_ANA_ADC3			OV1063X_REG_8BIT(0x3602)
> > +#define OV1063X_ANA_ADC4			OV1063X_REG_8BIT(0x3603)
> > +#define OV1063X_ANA_ANALOG1			OV1063X_REG_8BIT(0x3610)
> > +#define OV1063X_ANA_ANALOG2			OV1063X_REG_8BIT(0x3611)
> > +#define OV1063X_ANA_ANALOG3			OV1063X_REG_8BIT(0x3612)
> > +#define OV1063X_ANA_ARRAY1			OV1063X_REG_8BIT(0x3621)
> > +#define OV1063X_ANA_ARRAY1_FULL			(0 << 3)
> > +#define OV1063X_ANA_ARRAY1_CROP_768		(1 << 3)
> > +#define OV1063X_ANA_ARRAY1_CROP_656		(2 << 3)
> > +#define OV1063X_ANA_ARRAY1_DELAY(n)		((n) << 0)
> > +#define OV1063X_ANA_PWC1			OV1063X_REG_8BIT(0x3630)
> > +#define OV1063X_ANA_PWC2			OV1063X_REG_8BIT(0x3631)
> > +#define OV1063X_ANA_PWC3			OV1063X_REG_8BIT(0x3632)
> > +#define OV1063X_ANA_PWC4			OV1063X_REG_8BIT(0x3633)
> > +
> > +#define OV1063X_SENSOR_RSTGOLOW			OV1063X_REG_8BIT(0x3702)
> > +#define OV1063X_SENSOR_HLDWIDTH			OV1063X_REG_8BIT(0x3703)
> > +#define OV1063X_SENSOR_TXWIDTH			OV1063X_REG_8BIT(0x3704)
> > +#define OV1063X_SENSOR_REG9			OV1063X_REG_8BIT(0x3709)
> > +#define OV1063X_SENSOR_REGD			OV1063X_REG_8BIT(0x370d)
> > +#define OV1063X_SENSOR_RSTYZ_GOLOW		OV1063X_REG_16BIT(0x3712)
> > +#define OV1063X_SENSOR_EQ_GOLOW			OV1063X_REG_8BIT(0x3714)
> > +#define OV1063X_SENSOR_REG15			OV1063X_REG_8BIT(0x3715)
> > +#define OV1063X_SENSOR_BITSW_GO			OV1063X_REG_16BIT(0x371c)
> > +
> > +#define OV1063X_TIMING_X_START_ADDR		OV1063X_REG_16BIT(0x3800)
> > +#define OV1063X_TIMING_Y_START_ADDR		OV1063X_REG_16BIT(0x3802)
> > +#define OV1063X_TIMING_X_END_ADDR		OV1063X_REG_16BIT(0x3804)
> > +#define OV1063X_TIMING_Y_END_ADDR		OV1063X_REG_16BIT(0x3806)
> > +#define OV1063X_TIMING_X_OUTPUT_SIZE		OV1063X_REG_16BIT(0x3808)
> > +#define OV1063X_TIMING_Y_OUTPUT_SIZE		OV1063X_REG_16BIT(0x380a)
> > +#define OV1063X_TIMING_HTS			OV1063X_REG_16BIT(0x380c)
> > +#define OV1063X_TIMING_VTS			OV1063X_REG_16BIT(0x380e)
> > +#define OV1063X_TIMING_ISP_X_WIN		OV1063X_REG_16BIT(0x3810)
> > +#define OV1063X_TIMING_ISP_Y_WIN		OV1063X_REG_16BIT(0x3812)
> > +#define OV1063X_TIMING_CTRL15			OV1063X_REG_8BIT(0x3815)
> > +#define OV1063X_TIMING_CTRL15_BLACK_LINE_HREF	BIT(7)
> > +#define OV1063X_TIMING_CTRL15_RIP_SOF		BIT(5)
> > +#define OV1063X_TIMING_CTRL15_BLACK_LINES(n)	((n) << 0)
> > +#define OV1063X_TIMING_CTRL1C			OV1063X_REG_8BIT(0x381c)
> > +#define OV1063X_TIMING_CTRL1C_VFLIP_DIG		BIT(7)
> > +#define OV1063X_TIMING_CTRL1C_VFLIP_ARRAY	BIT(6)
> > +#define OV1063X_TIMING_CTRL1C_VSUB4		BIT(1)
> > +#define OV1063X_TIMING_CTRL1C_VSUB2		BIT(0)
> > +#define OV1063X_TIMING_CTRL1D			OV1063X_REG_8BIT(0x381d)
> > +#define OV1063X_TIMING_CTRL1D_VFLIP_BLACK_LINE	BIT(7)
> > +#define OV1063X_TIMING_CTRL1D_WDR		BIT(6)
> > +#define OV1063X_TIMING_CTRL1D_HFLIP_DIG		BIT(1)
> > +#define OV1063X_TIMING_CTRL1D_HFLIP_ARRAY	BIT(0)
> > +#define OV1063X_VSTART_OFFSET			OV1063X_REG_16BIT(0x381e)
> > +
> > +#define OV1063X_START_LINE			OV1063X_REG_8BIT(0x4001)
> > +#define OV1063X_LINE_NUM			OV1063X_REG_8BIT(0x4004)	/* Black lines */
> > +#define OV1063X_BLC_CTRL05			OV1063X_REG_8BIT(0x4005)
> > +#define OV1063X_BLC_CTRL05_ONE_LINE_MODE	BIT(5)
> > +#define OV1063X_BLC_CTRL05_REMOVE_BLACK_LINE	BIT(4)
> > +#define OV1063X_BLC_CTRL05_ONE_MAN_OFFSET_MODE	BIT(3)
> > +#define OV1063X_BLC_CTRL05_BL_RBLUE_RVS		BIT(2)
> > +#define OV1063X_BLC_CTRL05_BLC_ALWAYS_DO	BIT(1)
> > +#define OV1063X_BLC_AVG_CTRL1			OV1063X_REG_8BIT(0x4050)
> > +#define OV1063X_BLC_AVG_CTRL2			OV1063X_REG_8BIT(0x4051)
> > +#define OV1063X_BLC_OFFSET_TOP_LIMIT		OV1063X_REG_16BIT(0x4056)
> > +#define OV1063X_BLC_OFFSET_BOT_LIMIT		OV1063X_REG_16BIT(0x4058)
> > +#define OV1063X_BLC_CTRL5A			OV1063X_REG_8BIT(0x405a)
> > +
> > +#define OV1063X_FC_R2				OV1063X_REG_8BIT(0x4202)
> > +
> > +#define OV1063X_FORMAT_CTRL00			OV1063X_REG_8BIT(0x4300)
> > +#define OV1063X_FORMAT_YUYV			0x38
> > +#define OV1063X_FORMAT_YYYU			0x39
> > +#define OV1063X_FORMAT_UYVY			0x3a
> > +#define OV1063X_FORMAT_VYUY			0x3b
> > +#define OV1063X_FORMAT_YMAX			OV1063X_REG_16BIT(0x4302)
> > +#define OV1063X_FORMAT_YMIN			OV1063X_REG_16BIT(0x4304)
> > +#define OV1063X_FORMAT_UMAX			OV1063X_REG_16BIT(0x4306)
> > +#define OV1063X_FORMAT_UMIN			OV1063X_REG_16BIT(0x4308)
> > +
> > +#define OV1063X_VFIFO_LLEN_FIRS1_SEL		OV1063X_REG_8BIT(0x4605)
> > +#define OV1063X_VFIFO_LLEN_FIRS1_SEL_8B_YUV	BIT(3)
> > +#define OV1063X_VFIFO_LINE_LENGTH_MAN		OV1063X_REG_16BIT(0x4606)
> > +#define OV1063X_VFIFO_READ_START		OV1063X_REG_16BIT(0x4608)
> > +#define OV1063X_VFIFO_HSYNC_START_POSITION	OV1063X_REG_16BIT(0x460a)
> > +#define OV1063X_VFIFO_HSYNC_CTRL		OV1063X_REG_8BIT(0x460c)
> > +#define OV1063X_VFIFO_HSYNC_CTRL_HEADER_WIDTH(n)	((n) << 4)
> > +#define OV1063X_VFIFO_HSYNC_CTRL_TRAILER_WIDTH(n)	((n) << 0)
> > +#define OV1063X_VFIFO_EMBD_LINE_CTRL		OV1063X_REG_8BIT(0x460e)
> > +#define OV1063X_VFIFO_EMBD_LINE_CTRL_SOF_CLR_RAM	BIT(3)
> > +#define OV1063X_VFIFO_EMBD_LINE_CTRL_ST_MOD	BIT(2)
> > +#define OV1063X_VFIFO_EMBD_LINE_CTRL_EMBD_ROM	BIT(1)
> > +#define OV1063X_VFIFO_EMBD_LINE_CTRL_EMBD_EN	BIT(0)
> > +#define OV1063X_VFIFO_EMBD_LINE_NUM		OV1063X_REG_8BIT(0x460f)
> > +#define OV1063X_ROI_CTRL0			OV1063X_REG_8BIT(0x4620)
> > +#define OV1063X_ROI_CTRL0_SYNC_BYP		BIT(7)
> > +#define OV1063X_ROI_CTRL0_FR_COMP		BIT(6)
> > +#define OV1063X_ROI_CTRL0_FULL_DAT_MOD		BIT(5)
> > +#define OV1063X_ROI_CTRL0_EN_3			BIT(3)
> > +#define OV1063X_ROI_CTRL0_EN_2			BIT(2)
> > +#define OV1063X_ROI_CTRL0_EN_1			BIT(1)
> > +#define OV1063X_ROI_CTRL0_FUNC_E		BIT(0)
> > +
> > +#define OV1063X_DVP_MOD_SEL			OV1063X_REG_8BIT(0x4700)
> > +#define OV1063X_DVP_MOD_SEL_CCIR_V		BIT(3)
> > +#define OV1063X_DVP_MOD_SEL_CCIR_F		BIT(2)
> > +#define OV1063X_DVP_MOD_SEL_CCIR_656		BIT(1)
> > +#define OV1063X_DVP_MOD_SEL_HSYNC		BIT(0)
> > +#define OV1063X_DVP_VSYNC_WIDTH			OV1063X_REG_8BIT(0x4701)
> > +#define OV1063X_DVP_HSYVSY_NEG_WIDTH		OV1063X_REG_16BIT(0x4702)
> > +#define OV1063X_DVP_VSYNC_MODE			OV1063X_REG_8BIT(0x4704)
> > +#define OV1063X_DVP_VSYNC_MODE_VSYNCOUT_SEL(n)	((n) << 2)
> > +#define OV1063X_DVP_VSYNC_MODE_VSYNC3_MOD	BIT(1)
> > +#define OV1063X_DVP_VSYNC_MODE_VSYNC2_MOD	BIT(0)
> > +#define OV1063X_DVP_EOF_VSYNC_DELAY		OV1063X_REG_24BIT(0x4705)
> > +
> > +#define OV1063X_ISP_RW00			OV1063X_REG_8BIT(0x5000)
> > +#define OV1063X_ISP_RW00_COLOR_MATRIX_EN	BIT(7)
> > +#define OV1063X_ISP_RW00_COLOR_INTERP_EN	BIT(6)
> > +#define OV1063X_ISP_RW00_DENOISE_EN		BIT(5)
> > +#define OV1063X_ISP_RW00_WHITE_DPC_EN		BIT(4)	/* White defect pixel correction enable */
> > +#define OV1063X_ISP_RW00_BLACK_DPC_EN		BIT(3)	/* Black defect pixel connection enable */
> > +#define OV1063X_ISP_RW00_AWB_STATS_EN		BIT(2)
> > +#define OV1063X_ISP_RW00_AWB_GAIN_EN		BIT(1)
> > +#define OV1063X_ISP_RW00_LSC_EN			BIT(0)
> > +#define OV1063X_ISP_RW01			OV1063X_REG_8BIT(0x5001)
> > +#define OV1063X_ISP_RW01_DATA_WEIGHT_SYNC_EN	BIT(7)
> > +#define OV1063X_ISP_RW01_BLACK_WHITE_MODE_EN	BIT(6)
> > +#define OV1063X_ISP_RW01_DARK_LEVEL_FILTER_EN	BIT(5)
> > +#define OV1063X_ISP_RW01_BUFFER_CONTROL_EN	BIT(4)
> > +#define OV1063X_ISP_RW01_AEC_EN			BIT(3)
> > +#define OV1063X_ISP_RW01_TONE_MAPPING_EN	BIT(2)
> > +#define OV1063X_ISP_RW01_NORMALIZE_EN		BIT(1)
> > +#define OV1063X_ISP_RW01_LONG_SHORT_COMB_EN	BIT(0)
> > +#define OV1063X_ISP_RW02			OV1063X_REG_8BIT(0x5002)
> > +#define OV1063X_ISP_RW02_DIGITAL_GAIN_EN	BIT(3)
> > +#define OV1063X_ISP_RW02_WINDOW_BORDER_CUT_EN	BIT(2)
> > +#define OV1063X_ISP_RW02_DITHERING_EN		BIT(1)
> > +#define OV1063X_ISP_RW02_LSLS			(0U << 0)
> > +#define OV1063X_ISP_RW02_SLSL			(1U << 0)
> > +#define OV1063X_ISP_RW05			OV1063X_REG_8BIT(0x5005)
> > +#define OV1063X_ISP_RW05_VERT_SUB_EN		BIT(7)	/* Enable vertical subsampling */
> > +#define OV1063X_ISP_RW05_LSC_CENTER_AUTO	BIT(6)	/* Set LSC center automatically based on image window */
> > +#define OV1063X_ISP_RW05_SUB_OUT_ROW_2ND	BIT(5)	/* Output 2nd (1) or 1st (0) row when skipping */
> > +#define OV1063X_ISP_RW05_SUB_OUT_COL_2ND	BIT(4)	/* Output 2nd (1) or 1st (0) column when skipping */
> > +#define OV1063X_ISP_RW05_SUB_AVG		BIT(3)	/* Average (1) or sum (0) when binning */
> > +#define OV1063X_ISP_RW05_SUB_G_DROP		BIT(2)	/* Skip (1) or bin (0) Green / Y */
> > +#define OV1063X_ISP_RW05_SUB_RB_DROP		BIT(1)	/* Skip (1) or bin (0) Red Blue / UV */
> > +#define OV1063X_ISP_RW05_SUB_ENABLE		BIT(0)	/* Enable sub-sampling */
> > +#define OV1063X_ISP_RW06			OV1063X_REG_8BIT(0x5006)
> > +#define OV1063X_ISP_RW06_RAW_MODE_MAN(n)	((n) << 6)
> > +#define OV1063X_ISP_RW06_YUV_MODE_MAN(n)	((n) << 4)
> > +#define OV1063X_ISP_RW06_RAW_MODE_MAN_EN	BIT(3)
> > +#define OV1063X_ISP_RW06_YUV_MODE_MAN_EN	BIT(2)
> > +#define OV1063X_ISP_CTRL3D			OV1063X_REG_8BIT(0x503d)
> > +#define OV1063X_ISP_CTRL3D_TEST_PATTERN_EN	BIT(7)
> > +#define OV1063X_ISP_CTRL3D_COLOR_BAR(n)		((n) << 4)
> > +#define OV1063X_ISP_CTRL3D_ROLLING_BAR_EN	BIT(2)
> > +#define OV1063X_ISP_CTRL3E			OV1063X_REG_8BIT(0x503e)
> > +#define OV1063X_ISP_CTRL3E_SQUARE_BW		BIT(3)
> > +#define OV1063X_ISP_CTRL3E_TRANSPARENT_EN	BIT(2)
> > +#define OV1063X_ISP_CTRL3E_PATTERN_BARS		(0U << 0)
> > +#define OV1063X_ISP_CTRL3E_PATTERN_RANDOM	(1U << 0)
> > +#define OV1063X_ISP_CTRL3E_PATTERN_SQUARES	(2U << 0)
> > +
> > +#define OV1063X_GAIN_AWB_MAN_GAIN_B_LONG	OV1063X_REG_16BIT(0x5100)
> > +#define OV1063X_GAIN_AWB_MAN_GAIN_GB_LONG	OV1063X_REG_16BIT(0x5102)
> > +#define OV1063X_GAIN_AWB_MAN_GAIN_GR_LONG	OV1063X_REG_16BIT(0x5104)
> > +#define OV1063X_GAIN_AWB_MAN_GAIN_R_LONG	OV1063X_REG_16BIT(0x5106)
> > +#define OV1063X_GAIN_AWB_MAN_OFFSET_B_LONG	OV1063X_REG_16BIT(0x5108)
> > +#define OV1063X_GAIN_AWB_MAN_OFFSET_GB_LONG	OV1063X_REG_16BIT(0x510a)
> > +#define OV1063X_GAIN_AWB_MAN_OFFSET_GR_LONG	OV1063X_REG_16BIT(0x510c)
> > +#define OV1063X_GAIN_AWB_MAN_OFFSET_R_LONG	OV1063X_REG_16BIT(0x510e)
> > +#define OV1063X_GAIN_AWB_MAN_GAIN_B_SHORT	OV1063X_REG_16BIT(0x5110)
> > +#define OV1063X_GAIN_AWB_MAN_GAIN_GB_SHORT	OV1063X_REG_16BIT(0x5112)
> > +#define OV1063X_GAIN_AWB_MAN_GAIN_GR_SHORT	OV1063X_REG_16BIT(0x5114)
> > +#define OV1063X_GAIN_AWB_MAN_GAIN_R_SHORT	OV1063X_REG_16BIT(0x5116)
> > +#define OV1063X_GAIN_AWB_MAN_OFFSET_B_SHORT	OV1063X_REG_16BIT(0x5118)
> > +#define OV1063X_GAIN_AWB_MAN_OFFSET_GB_SHORT	OV1063X_REG_16BIT(0x511a)
> > +#define OV1063X_GAIN_AWB_MAN_OFFSET_GR_SHORT	OV1063X_REG_16BIT(0x511c)
> > +#define OV1063X_GAIN_AWB_MAN_OFFSET_R_SHORT	OV1063X_REG_16BIT(0x511e)
> > +#define OV1063X_GAIN_AWB_CTRL32			OV1063X_REG_8BIT(0x5120)
> > +#define OV1063X_GAIN_AWB_CTRL32_MANUAL_EN	BIT(0)
> > +
> > +#define OV1063X_DNS_NOISE_Y_LIST_LONG(n)	OV1063X_REG_8BIT(0x521a + (n))
> > +#define OV1063X_DNS_NOISE_UV_LIST_LONG(n)	OV1063X_REG_16BIT(0x5222 + (n) * 2)
> > +#define OV1063X_DNS_GBGR_EXTRA_SHORT		OV1063X_REG_8BIT(0x5241)
> > +#define OV1063X_DNS_NOISE_Y_LIST_SHORT(n)	OV1063X_REG_8BIT(0x5242 + (n))
> > +#define OV1063X_DNS_NOISE_UV_LIST_SHORT(n)	OV1063X_REG_16BIT(0x5249 + (n) * 2)
> > +#define OV1063X_CIP_UNSHARPEN_MASK_LONG(n)	OV1063X_REG_8BIT(0x5288 + (n))
> > +#define OV1063X_CIP_MAX_SHARPEN_LONG		OV1063X_REG_8BIT(0x528d)
> > +#define OV1063X_CIP_SHARPEN_ALPHA_LONG		OV1063X_REG_8BIT(0x5293)
> > +#define OV1063X_CIP_UNSHARPEN_MASK_SHORT(n)	OV1063X_REG_8BIT(0x52c8 + (n))
> > +#define OV1063X_CIP_MAX_SHARPEN_SHORT		OV1063X_REG_8BIT(0x52cd)
> > +#define OV1063X_CIP_SHARPEN_ALPHA_SHORT		OV1063X_REG_8BIT(0x52d3)
> > +#define OV1063X_CIP_HFREQ_COEF_SHORT		OV1063X_REG_8BIT(0x52d7)
> > +
> > +#define OV1063X_LLF_MAX_LOW_LEVEL		OV1063X_REG_16BIT(0x5381)
> > +
> > +#define OV1063X_AWB_CT_CTRL1			OV1063X_REG_8BIT(0x5581)
> > +#define OV1063X_AWB_CT_CTRL1_GAIN_STEP_NORMAL(n)	((n) << 6)
> > +#define OV1063X_AWB_CT_CTRL1_GAIN_STEP_FAST(n)	((n) << 4)
> > +#define OV1063X_AWB_CT_CTRL1_SCALE_LONG_2X	(0 << 2)
> > +#define OV1063X_AWB_CT_CTRL1_SCALE_LONG_4X	(1 << 2)
> > +#define OV1063X_AWB_CT_CTRL1_SCALE_LONG_8X	(2 << 2)
> > +#define OV1063X_AWB_M_RNG_LONG			OV1063X_REG_8BIT(0x5586)
> > +#define OV1063X_AWB_L_XRNG_LONG			OV1063X_REG_8BIT(0x5587)
> > +#define OV1063X_AWB_H_YRNG_LONG			OV1063X_REG_8BIT(0x5588)
> > +#define OV1063X_AWB_M_X_LONG			OV1063X_REG_8BIT(0x5589)
> > +#define OV1063X_AWB_M_Y_LONG			OV1063X_REG_8BIT(0x558a)
> > +#define OV1063X_AWB_L_K_LONG			OV1063X_REG_8BIT(0x558b)
> > +#define OV1063X_AWB_H_K_LONG			OV1063X_REG_8BIT(0x558c)
> > +#define OV1063X_AWB_H_LMT_LONG			OV1063X_REG_8BIT(0x558d)
> > +#define OV1063X_AWB_L_LMT_LONG			OV1063X_REG_8BIT(0x558e)
> > +#define OV1063X_AWB_DATA_ULMT_LONG		OV1063X_REG_8BIT(0x5591)
> > +#define OV1063X_AWB_DATA_LLMT_LONG		OV1063X_REG_8BIT(0x5592)
> > +#define OV1063X_AWB_M_RNG_SHORT			OV1063X_REG_8BIT(0x559f)
> > +#define OV1063X_AWB_L_XRNG_SHORT		OV1063X_REG_8BIT(0x55a0)
> > +#define OV1063X_AWB_H_YRNG_SHORT		OV1063X_REG_8BIT(0x55a1)
> > +#define OV1063X_AWB_M_X_SHORT			OV1063X_REG_8BIT(0x55a2)
> > +#define OV1063X_AWB_M_Y_SHORT			OV1063X_REG_8BIT(0x55a3)
> > +#define OV1063X_AWB_L_K_SHORT			OV1063X_REG_8BIT(0x55a4)
> > +#define OV1063X_AWB_H_K_SHORT			OV1063X_REG_8BIT(0x55a5)
> > +#define OV1063X_AWB_H_LMT_SHORT			OV1063X_REG_8BIT(0x55a6)
> > +#define OV1063X_AWB_L_LMT_SHORT			OV1063X_REG_8BIT(0x55a7)
> > +#define OV1063X_AWB_DATA_ULMT_SHORT		OV1063X_REG_8BIT(0x55aa)
> > +#define OV1063X_AWB_DATA_LLMT_SHORT		OV1063X_REG_8BIT(0x55ab)
> > +
> > +#define OV1063X_AEC_CTRL07			OV1063X_REG_16BIT(0x5607)
> > +#define OV1063X_AEC_WIN_LEFT_LONG		OV1063X_REG_16BIT(0x5609)
> > +#define OV1063X_AEC_WIN_LEFT_SHORT		OV1063X_REG_16BIT(0x560b)
> > +#define OV1063X_AEC_WIN_TOP_LONG		OV1063X_REG_16BIT(0x560d)
> > +#define OV1063X_AEC_WIN_TOP_SHORT		OV1063X_REG_16BIT(0x560f)
> > +#define OV1063X_AEC_WIN_WIDTH_LONG		OV1063X_REG_16BIT(0x5611)
> > +#define OV1063X_AEC_WIN_WIDTH_SHORT		OV1063X_REG_16BIT(0x5613)
> > +#define OV1063X_AEC_WIN_HEIGHT_LONG		OV1063X_REG_16BIT(0x5615)
> > +#define OV1063X_AEC_WIN_HEIGHT_SHORT		OV1063X_REG_16BIT(0x5617)
> > +#define OV1063X_AEC_WEIGHT_SHORT(n)		OV1063X_REG_8BIT(0x563b + (n))
> > +#define OV1063X_AEC_FINAL_SATURATE_THRESH	OV1063X_REG_16BIT(0x5651)
> > +#define OV1063X_AEC_CTRLD0			OV1063X_REG_8BIT(0x56d0)
> > +#define OV1063X_AEC_CTRLD0_R_MAN_EN(n)		((n) << 0)
> > +#define OV1063X_AEC_CTRLD5			OV1063X_REG_32BIT(0x56d5)	/* r_exp_l_m */
> > +#define OV1063X_AEC_CTRLD9			OV1063X_REG_32BIT(0x56d9)	/* r_exp_s_m */
> > +#define OV1063X_AEC_CTRLE8			OV1063X_REG_16BIT(0x56e8)	/* r_snrgain_l_m */
> > +#define OV1063X_AEC_CTRLEA			OV1063X_REG_16BIT(0x56ea)	/* r_snrgain_s_m */
> > +
> > +#define OV1063X_TPM_CTRL0			OV1063X_REG_8BIT(0x6706)
> > +#define OV1063X_TPM_CTRL0_CLK_DIV(n)		((n) << 0)
> > +
> > +#define OV1063X_GROUP_WRITER_COMMAND		OV1063X_REG_8BIT(0x6f00)
> > +#define OV1063X_GROUP_WRITER_COMMAND_OP(n)	((n) << 6)
> > +#define OV1063X_GROUP_WRITER_COMMAND_ID(n)	((n) << 4)
> > +#define OV1063X_GROUP_WRITER_COMMAND_EN		(3U << 0)
> > +#define OV1063X_PARI_ADDR_MIN			OV1063X_REG_16BIT(0x6f06)
> > +#define OV1063X_PARI_ADDR_MAX			OV1063X_REG_16BIT(0x6f0a)
> > +
> > +#define OV1063X_EMB_LINE_EN			OV1063X_REG_8BIT(0x6800)
> > +#define OV1063X_EMB_LINE_EN_ENABLE		BIT(0)
> > +#define OV1063X_EMB_SIZE_MANU_EN		OV1063X_REG_8BIT(0x6804)
> > +#define OV1063X_EMB_SIZE_EN_ENABLE		BIT(0)
> > +#define OV1063X_EMB_SIZE_MANU			OV1063X_REG_16BIT(0x6805)
> > +
> > +#define OV1063X_HORIZ_COLORCORRECT		OV1063X_REG_8BIT(0x6900)
> > +#define OV1063X_HORIZ_COLORCORRECT_ON		BIT(0)
> > +
> > +#define OV1063X_AEC_TARGET_NUM			OV1063X_REG_8BIT(0xc450)
> > +#define OV1063X_AEC_TARGET_NUM_AA_MODE		(1U << 0)
> > +#define OV1063X_AEC_TARGET_NUM_AB_MODE		(2U << 0)
> > +#define OV1063X_AEC_TARGET_NUM_ABC_MODE		(3U << 0)
> > +#define OV1063X_AEC_LS_SENS_RATIO		OV1063X_REG_16BIT(0xc452)
> > +#define OV1063X_AEC_NONWDR_EN			OV1063X_REG_8BIT(0xc454)
> > +#define OV1063X_AEC_NONWDR_SWITCH		OV1063X_REG_8BIT(0xc455)
> > +#define OV1063X_AEC_FIXED_RATIO_EN		OV1063X_REG_8BIT(0xc456)
> > +#define OV1063X_AEC_GP_MODE_EN			OV1063X_REG_8BIT(0xc457)
> > +#define OV1063X_AEC_NIGHT_MODE_EN		OV1063X_REG_8BIT(0xc458)
> > +#define OV1063X_AEC_NIGHT_MODE_CTRL		OV1063X_REG_8BIT(0xc459)
> > +#define OV1063X_AEC_NIGHT_MODE_CTRL_INSERT	BIT(0)
> > +#define OV1063X_AEC_FRACTAL_EXP_EN		OV1063X_REG_8BIT(0xc45a)
> > +#define OV1063X_AEC_NONLINEAR_GAIN_EN		OV1063X_REG_8BIT(0xc45b)
> > +#define OV1063X_AEC_MANU_GAMMA_EN		OV1063X_REG_8BIT(0xc45c)
> > +#define OV1063X_AEC_HOLD_BAND_EN		OV1063X_REG_8BIT(0xc45d)
> > +#define OV1063X_AEC_BAND_FILTER_FLAG		OV1063X_REG_8BIT(0xc45e)
> > +#define OV1063X_AEC_BAND_FILTER_FLAG_0HZ	(0U << 0)
> > +#define OV1063X_AEC_BAND_FILTER_FLAG_60HZ	(1U << 0)
> > +#define OV1063X_AEC_BAND_FILTER_FLAG_50HZ	(2U << 0)
> > +#define OV1063X_AEC_BAND_FILTER_EN		OV1063X_REG_8BIT(0xc45f)
> > +#define OV1063X_AEC_BAND_FILTER_SHORT		OV1063X_REG_8BIT(0xc460)
> > +#define OV1063X_AEC_LESS_1BAND_EN		OV1063X_REG_8BIT(0xc461)
> > +#define OV1063X_AEC_LESS_1BAND_SHORT		OV1063X_REG_8BIT(0xc462)
> > +#define OV1063X_AEC_WDR_GAIN_LIMIT_EN		OV1063X_REG_8BIT(0xc463)
> > +#define OV1063X_AEC_LOG_TARGET(n)		OV1063X_REG_16BIT(0xc464 + (n) * 2)
> > +#define OV1063X_AEC_TARGET_LONG(n)		OV1063X_REG_8BIT(0xc46a + (n))
> > +#define OV1063X_AEC_TARGET_SHORT(n)		OV1063X_REG_8BIT(0xc46d + (n))
> > +#define OV1063X_AEC_MAX_SHORT_LE		OV1063X_REG_32BIT(0xc47c)
> > +#define OV1063X_AEC_MAX_GAIN_LONG		OV1063X_REG_16BIT(0xc480)
> > +#define OV1063X_AEC_MAX_GAIN_SHORT		OV1063X_REG_16BIT(0xc482)
> > +#define OV1063X_AEC_MIN_GAIN_LONG		OV1063X_REG_16BIT(0xc484)
> > +#define OV1063X_AEC_MIN_GAIN_SHORT		OV1063X_REG_16BIT(0xc486)
> > +#define OV1063X_AEC_MAX_EXP_LONG		OV1063X_REG_16BIT(0xc488)
> > +#define OV1063X_AEC_MAX_EXP_SHORT		OV1063X_REG_16BIT(0xc48a)
> > +#define OV1063X_AEC_MIN_EXP_LONG		OV1063X_REG_16BIT(0xc48c)
> > +#define OV1063X_AEC_MIN_EXP_SHORT		OV1063X_REG_16BIT(0xc48e)
> > +#define OV1063X_AEC_FIXED_RATIO			OV1063X_REG_8BIT(0xc490)
> > +#define OV1063X_AEC_GP_MODE_RATIO_B2A		OV1063X_REG_8BIT(0xc492)
> > +#define OV1063X_AEC_GP_MODE_RATIO_C2A		OV1063X_REG_8BIT(0xc493)
> > +#define OV1063X_AEC_MIN_GAMMA_LIST(n)		OV1063X_REG_16BIT(0xc498 + (n) * 2)
> > +#define OV1063X_AEC_MAX_GAMMA_LIST(n)		OV1063X_REG_16BIT(0xc49e + (n) * 2)
> > +#define OV1063X_AEC_DR_LIST(n)			OV1063X_REG_16BIT(0xc4a4 + (n) * 2)
> > +#define OV1063X_AEC_BAND_VALUE_60HZ		OV1063X_REG_16BIT(0xc4aa)
> > +#define OV1063X_AEC_BAND_VALUE_50HZ		OV1063X_REG_16BIT(0xc4ac)
> > +
> > +#define OV1063X_AWB_SIMPLE_MIN_NUM		OV1063X_REG_16BIT(0xc4cc)
> > +#define OV1063X_AWB_CT_MIN_NUM			OV1063X_REG_16BIT(0xc4ce)
> > +
> > +#define OV1063X_VTS_ADDR			OV1063X_REG_16BIT(0xc518)
> > +#define OV1063X_HTS_ADDR			OV1063X_REG_16BIT(0xc51a)
> > +
> > +#include "ov1063x_regs.h"
> > +
> > +/* IDs */
> > +#define OV10633_VERSION_REG			0xa630
> > +#define OV10635_VERSION_REG			0xa635
> > +
> > +enum ov1063x_model {
> > +	SENSOR_OV10633,
> > +	SENSOR_OV10635,
> > +};
> > +
> > +#define OV1063X_SENSOR_WIDTH			1312
> > +#define OV1063X_SENSOR_HEIGHT			814
> > +
> > +struct ov1063x_priv {
> > +	struct device			*dev;
> > +
> > +	struct regmap			*regmap;
> > +	struct clk			*clk;
> > +	struct gpio_desc		*reset_gpio;
> > +	struct gpio_desc		*pwdn_gpio;
> > +
> > +	int				model;
> > +	const char			*name;
> > +	unsigned long			clk_rate;
> > +
> > +	struct v4l2_subdev		subdev;
> > +	struct media_pad		pad;
> > +
> > +	struct v4l2_ctrl_handler	hdl;
> > +
> > +	/*
> > +	 * The streaming and format fields are protected by the control handler
> > +	 * lock.
> > +	 */
> > +	bool				streaming;
> > +	struct v4l2_rect		analog_crop;
> > +	struct v4l2_rect		digital_crop;
> > +	struct v4l2_mbus_framefmt	format;
> > +
> > +	unsigned int			fps_numerator;
> > +	unsigned int			fps_denominator;
> > +};
> > +
> > +/*
> > + * TODO: Expose multiple subdevs to control cropping and subsampling separately
> > + * from userspace instead of hardcoding resolutions.
> > + *
> > + * TODO: Resolutions with an analog crop rectangle width equal to 768 or higher
> > + * don't work properly.
> > + */
> > +static const struct v4l2_area ov1063x_framesizes[] = {
> > +	{
> > +		.width		= 1280,
> > +		.height		= 800,
> > +	}, {
> > +		.width		= 1280,
> > +		.height		= 720,
> > +	}, {
> > +		.width		= 752,
> > +		.height		= 480,
> > +	}, {
> > +		.width		= 640,
> > +		.height		= 480,
> > +	}, {
> > +		.width		= 600,
> > +		.height		= 400,
> > +	}, {
> > +		.width		= 352,
> > +		.height		= 288,
> > +	}, {
> > +		.width		= 320,
> > +		.height		= 240,
> > +	},
> > +};
> > +
> > +static const u32 ov1063x_mbus_formats[] = {
> > +	MEDIA_BUS_FMT_YUYV8_2X8,
> > +	MEDIA_BUS_FMT_UYVY8_2X8,
> > +	MEDIA_BUS_FMT_VYUY8_2X8,
> > +	MEDIA_BUS_FMT_YVYU8_2X8,
> > +};
> > +
> > +static inline struct ov1063x_priv *to_ov1063x(struct v4l2_subdev *sd)
> > +{
> > +	return container_of(sd, struct ov1063x_priv, subdev);
> > +}
> > +
> > +/* -----------------------------------------------------------------------------
> > + * Read/Write Helpers
> > + */
> > +
> > +static int ov1063x_read(struct ov1063x_priv *priv, u32 reg, u32 *val)
> > +{
> > +	unsigned int len = (reg >> OV1063X_REG_SIZE_SHIFT) & 3;
> > +	u16 addr = reg & OV1063X_REG_ADDR_MASK;
> > +	unsigned int i;
> > +	int ret;
> > +
> > +	*val = 0;
> > +
> > +	for (i = 0; i < len; ++i) {
> > +		u32 byte;
> > +
> > +		ret = regmap_read(priv->regmap, addr, &byte);
> > +		if (ret)
> > +			return ret;
> > +
> > +		*val = (*val << 8) | byte;
> > +		addr++;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_write(struct ov1063x_priv *priv, u32 reg, u32 val, int *err)
> > +{
> > +	unsigned int len = (reg >> OV1063X_REG_SIZE_SHIFT) & 7;
> > +	u16 addr = reg & OV1063X_REG_ADDR_MASK;
> > +	unsigned int shift = (len - 1) * 8;
> > +	unsigned int i;
> > +	int ret;
> > +
> > +	if (err && *err)
> > +		return *err;
> > +
> > +	for (i = 0; i < len; ++i) {
> > +		ret = regmap_write(priv->regmap, addr, (val >> shift) & 0xff);
> > +		if (ret) {
> > +			if (err)
> > +				*err = ret;
> > +			return ret;
> > +		}
> > +
> > +		shift -= 8;
> > +		addr++;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_write_array(struct ov1063x_priv *priv,
> > +			       const struct ov1063x_reg *regs,
> > +			       unsigned int nr_regs)
> > +{
> > +	unsigned int i;
> > +	int ret;
> > +
> > +	for (i = 0; i < nr_regs; i++) {
> > +		ret = ov1063x_write(priv, regs[i].reg, regs[i].val, NULL);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_update(struct ov1063x_priv *priv, u32 reg, u32 mask, u32 val,
> > +			  int *err)
> > +{
> > +	unsigned int len = (reg >> OV1063X_REG_SIZE_SHIFT) & 7;
> > +	u16 addr = reg & OV1063X_REG_ADDR_MASK;
> > +	unsigned int shift = (len - 1) * 8;
> > +	unsigned int i;
> > +	int ret;
> > +
> > +	if (err && *err)
> > +		return *err;
> > +
> > +	for (i = 0; i < len; ++i) {
> > +		ret = regmap_update_bits(priv->regmap, addr,
> > +					 (mask >> shift) & 0xff,
> > +					 (val >> shift) & 0xff);
> > +		if (ret) {
> > +			if (err)
> > +				*err = ret;
> > +			return ret;
> > +		}
> > +
> > +		shift -= 8;
> > +		addr++;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/* -----------------------------------------------------------------------------
> > + * Hardware Configuration
> > + */
> > +
> > +struct ov1063x_pll_config {
> > +	unsigned int pre_div;
> > +	unsigned int mult;
> > +	unsigned int div;
> > +	unsigned int clk_out;
> > +};
> > +
> > +static int ov1063x_pll_setup(unsigned int clk_rate,
> > +			     unsigned int *htsmin, unsigned int vts,
> > +			     unsigned int fps_numerator,
> > +			     unsigned int fps_denominator,
> > +			     struct ov1063x_pll_config *cfg)
> > +{
> > +	static const unsigned int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
> > +
> > +	unsigned int best_pclk = UINT_MAX;
> > +	unsigned int best_pre_div;
> > +	unsigned int best_mult;
> > +	unsigned int best_div;
> > +	unsigned int best_hts;
> > +	unsigned int max_pre_div;
> > +	unsigned int pre_div;
> > +	unsigned int hts;
> > +
> > +	/*
> > +	 *  XVCLK --> pre-div -------> mult ----------> div --> output
> > +	 * 6-27 MHz           3-27 MHz      200-500 MHz       Max 96 MHz
> > +	 *
> > +	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7. The
> > +	 * pre_divs array stores the pre-dividers multiplied by two, indexed by
> > +	 * register values.
> > +	 *
> > +	 * Valid multiplier values are [1, 63], stored as-is in registers.
> > +	 *
> > +	 * Valid divider values are 2 to 16 with a step of 2, stored in
> > +	 * registers as (div / 2) - 1.
> > +	 */
> > +
> > +	if (clk_rate < 6 * 1000 * 1000 || clk_rate > 27 * 1000 * 1000)
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * We try all valid combinations of settings for the 3 blocks to get
> > +	 * the pixel clock, and from that calculate the actual hts/vts to use.
> > +	 * The vts is extended so as to achieve the required frame rate.
> > +	 */
> > +
> > +	max_pre_div = max(clk_rate / (3 * 1000 * 1000),
> > +			  ARRAY_SIZE(pre_divs) - 1);
> > +
> > +	for (pre_div = 0; pre_div <= max_pre_div; pre_div++) {
> > +		unsigned int clk1 = clk_rate * 2 / pre_divs[pre_div];
> > +		unsigned int min_mult;
> > +		unsigned int max_mult;
> > +		unsigned int mult;
> > +
> > +		if (clk1 < 3 * 1000 * 1000 || clk1 > 27 * 1000 * 1000)
> > +			continue;
> > +
> > +		min_mult = DIV_ROUND_UP(200 * 1000 * 1000, clk1);
> > +		max_mult = min(500 * 1000 * 1000 / clk1, 63U);
> > +
> > +		for (mult = min_mult; mult <= max_mult; mult++) {
> > +			unsigned int clk2 = clk1 * mult;
> > +			unsigned int min_div;
> > +			unsigned int div;
> > +
> > +			min_div = DIV_ROUND_UP(clk2, 96 * 1000 * 1000);
> > +			min_div = round_up(min_div, 2);
> > +
> > +			for (div = min_div; div <= 16; div += 2) {
> > +				unsigned int pclk = clk2 / div;
> > +				unsigned int min_pclk;
> > +
> > +				/*
> > +				 * TODO: HTS calculation should ideally be split
> > +				 * from the PLL calculations. This requires
> > +				 * figuring out where the pclk / 300000 comes
> > +				 * from.
> > +				 */
> > +				hts = *htsmin + pclk / (300*1000);
> > +
> > +				/* 2 clock cycles for every YUV422 pixel. */
> > +				min_pclk = hts * vts / fps_denominator
> > +					 * fps_numerator * 2;
> > +				if (pclk < min_pclk)
> > +					continue;
> > +
> > +				if (pclk < best_pclk) {
> > +					best_pclk = pclk;
> > +					best_hts = hts;
> > +					best_pre_div = pre_div;
> > +					best_mult = mult;
> > +					best_div = div;
> 
> Can the requested frame rate exceed the highest possible rate here?

The frame rate is hardcoded to 30fps. It's a leftover of the old driver,
it shouldn't be taken into account at all in this function. Ideally it
should be configured from userspace through hts/vts. I however wonder
what pclk frequency the driver should select in that case.

> You already control the sensor's PLL and other capabilities such as
> analogue cropping directly. You could make these all configurable from the
> user space the same way the ccs driver does. What do you think?

Please see the cover letter :-) I'd appreciate advices on how to solve
the problem mentioned there.

> > +				}
> > +			}
> > +		}
> > +	}
> > +
> > +	if (best_pclk == UINT_MAX)
> > +		return -EINVAL;
> > +
> > +	cfg->mult = best_mult;
> > +	cfg->pre_div = best_pre_div;
> > +	cfg->div = (best_div / 2) - 1;
> > +	cfg->clk_out = best_pclk;
> > +
> > +	*htsmin = best_hts;
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_isp_reset(struct ov1063x_priv *priv, bool reset)
> > +{
> > +	unsigned int i;
> > +	int ret = 0;
> > +
> > +	if (!reset) {
> > +		/*
> > +		 * Enable ISP blocks. Why OV1063X_SC_SOC_CLKRST7 needs to be
> > +		 * written 26 times is unknown.
> > +		 */
> > +		for (i = 0; i < 26; ++i)
> > +			ov1063x_write(priv, OV1063X_SC_SOC_CLKRST7,
> > +				      OV1063X_SC_SOC_CLKRST7_SCLK, &ret);
> > +
> > +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST1,
> > +			      OV1063X_SC_CMMN_CLKRST1_SCLK, &ret);
> > +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
> > +			      OV1063X_SC_CMMN_CLKRST2_PCLK_DVP |
> > +			      OV1063X_SC_CMMN_CLKRST2_SCLK, &ret);
> > +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST0,
> > +			      OV1063X_SC_CMMN_CLKRST0_SCLK, &ret);
> > +	} else {
> > +		/* Reset the ISP. */
> > +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST1,
> > +			      OV1063X_SC_CMMN_CLKRST1_SCLK |
> > +			      OV1063X_SC_CMMN_CLKRST1_RST, &ret);
> > +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
> > +			      OV1063X_SC_CMMN_CLKRST2_PCLK_DVP |
> > +			      OV1063X_SC_CMMN_CLKRST2_SCLK |
> > +			      OV1063X_SC_CMMN_CLKRST2_RST_DVP |
> > +			      OV1063X_SC_CMMN_CLKRST2_RST, &ret);
> > +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST0,
> > +			      OV1063X_SC_CMMN_CLKRST0_SCLK |
> > +			      OV1063X_SC_CMMN_CLKRST0_RST, &ret);
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +static int ov1063x_configure(struct ov1063x_priv *priv)
> > +{
> > +	struct ov1063x_pll_config pll_cfg;
> > +	unsigned int width_pre_subsample;
> > +	unsigned int nr_isp_pixels;
> > +	unsigned int hts, vts;
> > +	u32 val;
> > +	int ret;
> > +
> > +	/* Minimum values for HTS anv VTS. */
> > +	hts = priv->analog_crop.width + 200;
> > +	vts = priv->analog_crop.height + 50;
> > +
> > +	/*
> > +	 * Get the best PCLK and adjust HTS accordingly. Adjust VTS to get as
> > +	 * close to the desired frame rate as we can.
> > +	 */
> > +	ret = ov1063x_pll_setup(priv->clk_rate, &hts, vts,
> > +				priv->fps_numerator, priv->fps_denominator,
> > +				&pll_cfg);
> > +	if (ret < 0)
> > +		return -EINVAL;
> > +
> > +	vts = pll_cfg.clk_out
> > +	    / (hts * 2 * priv->fps_numerator / priv->fps_denominator);
> > +
> > +	dev_dbg(priv->dev, "active %ux%u (total %ux%u) %u/%u fps, @%u MP/s\n",
> > +		priv->format.width, priv->format.height,
> > +		hts, vts, priv->fps_numerator, priv->fps_denominator,
> > +		pll_cfg.clk_out);
> > +	dev_dbg(priv->dev, "PLL pre-div %u mult %u div %u\n",
> > +		pll_cfg.pre_div, pll_cfg.mult, pll_cfg.div);
> > +
> > +	/* Reset the ISP and configure the PLL. */
> > +	ret = ov1063x_isp_reset(priv, true);
> > +
> > +	ov1063x_write(priv, OV1063X_SC_CMMN_PLL_CTRL0, pll_cfg.mult, &ret);
> > +	ov1063x_write(priv, OV1063X_SC_CMMN_PLL_CTRL1,
> > +		      (pll_cfg.pre_div << 4) | pll_cfg.div, &ret);
> > +
> > +	/* Analog array configuration (including horizontal cropping) */
> > +	switch (priv->analog_crop.width) {
> > +	case OV1063X_SENSOR_WIDTH:
> > +	default:
> > +		val = 0x60 | OV1063X_ANA_ARRAY1_FULL
> > +		    | OV1063X_ANA_ARRAY1_DELAY(3);
> > +		break;
> > +	case 768:
> > +		val = 0x60 | OV1063X_ANA_ARRAY1_CROP_768
> > +		    | OV1063X_ANA_ARRAY1_DELAY(3);
> > +		break;
> > +	case 656:
> > +		val = 0x60 | OV1063X_ANA_ARRAY1_CROP_656
> > +		    | OV1063X_ANA_ARRAY1_DELAY(3);
> > +		break;
> > +	}
> > +
> > +	ov1063x_write(priv, OV1063X_ANA_ARRAY1, val, &ret);
> > +
> > +	/* Sensor configuration */
> > +	ov1063x_write(priv, OV1063X_SENSOR_RSTGOLOW,
> > +		      (pll_cfg.clk_out + 1500000) / 3000000, &ret);
> > +	ov1063x_write(priv, OV1063X_SENSOR_HLDWIDTH,
> > +		      (pll_cfg.clk_out + 666666) / 1333333, &ret);
> > +	ov1063x_write(priv, OV1063X_SENSOR_TXWIDTH,
> > +		      (pll_cfg.clk_out + 961500) / 1923000, &ret);
> > +
> > +	/*
> > +	 * Timings (including cropping)
> > +	 *
> > +	 * TODO: The vertical size is set to the height of the analog crop
> > +	 * rectangle plus 4 pixels. This margin is probably used by the ISP for
> > +	 * CFA interpolation, and should be moved to the crop rectangle height
> > +	 * after investigating how the ISP operates.
> > +	 */
> > +	ov1063x_write(priv, OV1063X_TIMING_Y_START_ADDR,
> > +		      priv->analog_crop.top, &ret);
> > +	ov1063x_write(priv, OV1063X_TIMING_Y_END_ADDR,
> > +		      priv->analog_crop.top + priv->analog_crop.height + 3,
> > +		      &ret);
> > +	ov1063x_write(priv, OV1063X_TIMING_ISP_X_WIN, priv->digital_crop.left,
> > +		      &ret);
> > +	ov1063x_write(priv, OV1063X_TIMING_ISP_Y_WIN, priv->digital_crop.top,
> > +		      &ret);
> > +	ov1063x_write(priv, OV1063X_TIMING_X_OUTPUT_SIZE, priv->format.width,
> > +		      &ret);
> > +	ov1063x_write(priv, OV1063X_TIMING_Y_OUTPUT_SIZE, priv->format.height,
> > +		      &ret);
> > +	ov1063x_write(priv, OV1063X_TIMING_HTS, hts, &ret);
> > +	ov1063x_write(priv, OV1063X_TIMING_VTS, vts, &ret);
> > +
> > +	/*
> > +	 * Sub-sampling. Horizontal sub-sampling is applied in the ISP, vertical
> > +	 * sub-sampling in the pixel array.
> > +	 */
> > +	if (priv->format.width <= 640) {
> > +		ov1063x_write(priv, OV1063X_ISP_RW05, OV1063X_ISP_RW05_SUB_AVG |
> > +			      OV1063X_ISP_RW05_SUB_ENABLE, &ret);
> > +		ov1063x_write(priv, OV1063X_SC_CMMN_PCLK_DIV_CTRL, 2, &ret);
> > +	} else {
> > +		ov1063x_write(priv, OV1063X_ISP_RW05, OV1063X_ISP_RW05_SUB_AVG,
> > +			      &ret);
> > +		ov1063x_write(priv, OV1063X_SC_CMMN_PCLK_DIV_CTRL, 1, &ret);
> > +	}
> > +
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (priv->format.height <= 400)
> > +		ret = ov1063x_write_array(priv, ov1063x_regs_vert_sub2,
> > +					  ARRAY_SIZE(ov1063x_regs_vert_sub2));
> > +	else
> > +		ret = ov1063x_write_array(priv, ov1063x_regs_vert_no_sub,
> > +					  ARRAY_SIZE(ov1063x_regs_vert_no_sub));
> > +
> > +	/*
> > +	 * AEC & AWB
> > +	 *
> > +	 * TODO: The number of pixels fed to the ISP is computed using the
> > +	 * analog crop width and the vertical output size, to account for the
> > +	 * fact that vertical sub-sampling is applied in the pixel array while
> > +	 * horizontal sub-sampling is applied in the ISP. The 4 pixels margin
> > +	 * seems incorrect when sub-sampling, as the vertical timing start and
> > +	 * stop registers are programmed with a 4 pixels margin before
> > +	 * sub-sampling, the ISP should thus receive a 2 pixels margin only.
> > +	 * This needs to be investigated.
> > +	 *
> > +	 * TODO: When applying vertical digital crop, the output height is
> > +	 * likely the wrong value to compute the total number of pixels fed to
> > +	 * the ISP.
> > +	 */
> > +	val = (vts - 8) * 16;
> > +	ov1063x_write(priv, OV1063X_AEC_MAX_EXP_LONG, val, &ret);
> > +	ov1063x_write(priv, OV1063X_AEC_MAX_EXP_SHORT, val, &ret);
> > +
> > +	nr_isp_pixels = priv->analog_crop.width * (priv->format.height + 4);
> > +	ov1063x_write(priv, OV1063X_AWB_SIMPLE_MIN_NUM, nr_isp_pixels / 256, &ret);
> > +	ov1063x_write(priv, OV1063X_AWB_CT_MIN_NUM, nr_isp_pixels / 256, &ret);
> > +	ov1063x_write(priv, OV1063X_REG_16BIT(0xc512), nr_isp_pixels / 16,
> > +		      &ret);
> > +
> > +	ov1063x_write(priv, OV1063X_VTS_ADDR, vts, &ret);
> > +	ov1063x_write(priv, OV1063X_HTS_ADDR, hts, &ret);
> > +
> > +	/* FIFO */
> > +	ov1063x_write(priv, OV1063X_VFIFO_LLEN_FIRS1_SEL,
> > +		      OV1063X_VFIFO_LLEN_FIRS1_SEL_8B_YUV, &ret);
> > +	width_pre_subsample = priv->format.width <= 640
> > +			    ? priv->format.width * 2 : priv->format.width;
> > +	ov1063x_write(priv, OV1063X_VFIFO_LINE_LENGTH_MAN, 2 * hts, &ret);
> > +	ov1063x_write(priv, OV1063X_VFIFO_HSYNC_START_POSITION,
> > +		      2 * (hts - width_pre_subsample), &ret);
> > +
> > +	/* Output interface (DVP). */
> > +	switch (priv->format.code) {
> > +	case MEDIA_BUS_FMT_UYVY8_2X8:
> > +		val = OV1063X_FORMAT_UYVY;
> > +		break;
> > +	case MEDIA_BUS_FMT_VYUY8_2X8:
> > +		val = OV1063X_FORMAT_VYUY;
> > +		break;
> > +	case MEDIA_BUS_FMT_YUYV8_2X8:
> > +		val = OV1063X_FORMAT_YUYV;
> > +		break;
> > +	case MEDIA_BUS_FMT_YVYU8_2X8:
> > +		val = OV1063X_FORMAT_YYYU;
> > +		break;
> > +	default:
> > +		val = OV1063X_FORMAT_UYVY;
> > +		break;
> > +	}
> > +
> > +	ov1063x_write(priv, OV1063X_FORMAT_CTRL00, val, &ret);
> > +	ov1063x_write(priv, OV1063X_DVP_MOD_SEL, 0, &ret);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* Take the ISP out of reset. */
> > +	return ov1063x_isp_reset(priv, false);
> > +}
> > +
> > +/* -----------------------------------------------------------------------------
> > + * V4L2 Control Operations
> > + */
> > +
> > +static const char * const ov1063x_test_pattern_menu[] = {
> > +	"Disabled",
> > +	"Color Bars, Plain",
> > +	"Color Bars, Vertical Gradient",
> > +	"Color Bars, Horizontal Gradient",
> > +	"Color Bars, Repeating",
> > +	"Random Data",
> > +	"Squares, Color",
> > +	"Squares, Black & White",
> > +};
> > +
> > +struct ov1063x_tpg_config {
> > +	u8 ctrl3d;
> > +	u8 ctrl3e;
> > +};
> > +
> > +static const struct ov1063x_tpg_config
> > +ov1063x_tpg_configs[ARRAY_SIZE(ov1063x_test_pattern_menu) - 1] = {
> > +	{
> > +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
> > +			| OV1063X_ISP_CTRL3D_COLOR_BAR(0),
> > +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
> > +	}, {
> > +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
> > +			| OV1063X_ISP_CTRL3D_COLOR_BAR(1),
> > +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
> > +	}, {
> > +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
> > +			| OV1063X_ISP_CTRL3D_COLOR_BAR(2),
> > +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
> > +	}, {
> > +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
> > +			| OV1063X_ISP_CTRL3D_COLOR_BAR(3),
> > +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
> > +	}, {
> > +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN,
> > +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_RANDOM,
> > +	}, {
> > +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN,
> > +		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_SQUARES,
> > +	}, {
> > +		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN,
> > +		.ctrl3e = OV1063X_ISP_CTRL3E_SQUARE_BW
> > +			| OV1063X_ISP_CTRL3E_PATTERN_SQUARES,
> > +	},
> > +};
> > +
> > +static int ov1063x_tpg_setup(struct ov1063x_priv *priv, struct v4l2_ctrl *ctrl)
> > +{
> > +	const struct ov1063x_tpg_config *cfg;
> > +	int ret = 0;
> > +
> > +	if (!ctrl->val)
> > +		return ov1063x_write_array(priv, ov1063x_regs_colorbar_disable,
> > +					   ARRAY_SIZE(ov1063x_regs_colorbar_disable));
> > +
> > +	if (!ctrl->cur.val) {
> > +		/*
> > +		 * Only write the full settings when the test pattern was
> > +		 * disabled, not when we're just changing the test pattern type.
> > +		 */
> > +		ret = ov1063x_write_array(priv, ov1063x_regs_colorbar_enable,
> > +					  ARRAY_SIZE(ov1063x_regs_colorbar_enable));
> > +		if (ret < 0)
> > +			return ret;
> > +	}
> > +
> > +	cfg = &ov1063x_tpg_configs[ctrl->val - 1];
> > +
> > +	/* TODO: Add support for the moving bar overlay. */
> > +	ov1063x_write(priv, OV1063X_ISP_CTRL3D, cfg->ctrl3d, &ret);
> > +	ov1063x_write(priv, OV1063X_ISP_CTRL3E, cfg->ctrl3e, &ret);
> > +
> > +	return ret;
> > +}
> > +
> > +static int ov1063x_s_ctrl(struct v4l2_ctrl *ctrl)
> > +{
> > +	struct ov1063x_priv *priv = container_of(ctrl->handler,
> > +					struct ov1063x_priv, hdl);
> > +	int ret = 0;
> > +
> > +	if (!priv->streaming)
> > +		return 0;
> > +
> > +	switch (ctrl->id) {
> > +	case V4L2_CID_VFLIP: {
> > +		const u32 vflip = OV1063X_TIMING_CTRL1C_VFLIP_DIG
> > +				| OV1063X_TIMING_CTRL1C_VFLIP_ARRAY;
> > +
> > +		return ov1063x_update(priv, OV1063X_TIMING_CTRL1C, vflip,
> > +				      ctrl->val ? vflip : 0, NULL);
> > +	}
> > +
> > +	case V4L2_CID_HFLIP: {
> > +		const u32 hflip = OV1063X_TIMING_CTRL1D_HFLIP_DIG
> > +				| OV1063X_TIMING_CTRL1D_HFLIP_ARRAY;
> > +
> > +		ov1063x_update(priv, OV1063X_HORIZ_COLORCORRECT,
> > +			       OV1063X_HORIZ_COLORCORRECT_ON,
> > +			       ctrl->val ? OV1063X_HORIZ_COLORCORRECT_ON : 0,
> > +			       &ret);
> > +		ov1063x_update(priv, OV1063X_TIMING_CTRL1D, hflip,
> > +			       ctrl->val ? hflip : 0, &ret);
> > +		return ret;
> > +	}
> > +
> > +	case V4L2_CID_TEST_PATTERN:
> > +		return ov1063x_tpg_setup(priv, ctrl);
> > +	}
> > +
> > +	return -EINVAL;
> > +}
> > +
> > +static const struct v4l2_ctrl_ops ov1063x_ctrl_ops = {
> > +	.s_ctrl = ov1063x_s_ctrl,
> > +};
> > +
> > +/* -----------------------------------------------------------------------------
> > + * V4L2 Subdev Operations
> > + */
> > +
> > +static int ov1063x_s_stream(struct v4l2_subdev *sd, int enable)
> > +{
> > +	struct ov1063x_priv *priv = to_ov1063x(sd);
> > +	int ret = 0;
> > +
> > +	if (!enable) {
> > +		ov1063x_write(priv, OV1063X_STREAM_MODE, 0, &ret);
> > +		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
> > +			      OV1063X_SC_CMMN_CLKRST2_SCLK, &ret);
> > +
> > +		pm_runtime_mark_last_busy(priv->dev);
> > +		pm_runtime_put_autosuspend(priv->dev);
> > +
> > +		mutex_lock(priv->hdl.lock);
> > +		priv->streaming = false;
> > +		mutex_unlock(priv->hdl.lock);
> > +
> > +		return ret;
> > +	}
> > +
> > +	mutex_lock(priv->hdl.lock);
> > +
> > +	/* Streaming needs to be true for ov1063x_s_ctrl() to proceed. */
> > +	priv->streaming = true;
> > +
> > +	ret = pm_runtime_get_sync(priv->dev);
> > +	if (ret < 0)
> > +		goto done;
> > +
> > +	ret = ov1063x_configure(priv);
> > +	if (ret < 0)
> > +		goto done;
> > +
> > +	ret = __v4l2_ctrl_handler_setup(&priv->hdl);
> > +	if (ret < 0)
> > +		goto done;
> > +
> > +	ret = 0;
> > +	ov1063x_write(priv, OV1063X_STREAM_MODE, OV1063X_STREAM_MODE_ON, &ret);
> > +	ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
> > +		      OV1063X_SC_CMMN_CLKRST2_PCLK_DVP |
> > +		      OV1063X_SC_CMMN_CLKRST2_SCLK, &ret);
> > +
> > +done:
> > +	if (ret < 0) {
> > +		/*
> > +		 * In case of error, turn the power off synchronously as the
> > +		 * device likely has no other chance to recover.
> > +		 */
> > +		pm_runtime_put_sync(priv->dev);
> > +		priv->streaming = false;
> > +	}
> > +
> > +	mutex_unlock(priv->hdl.lock);
> > +
> > +	return ret;
> > +}
> > +
> > +static struct v4l2_mbus_framefmt *
> > +__ov1063x_get_pad_format(struct ov1063x_priv *priv,
> > +			 struct v4l2_subdev_pad_config *cfg,
> > +			 unsigned int pad, u32 which)
> > +{
> > +	switch (which) {
> > +	case V4L2_SUBDEV_FORMAT_TRY:
> > +		return v4l2_subdev_get_try_format(&priv->subdev, cfg, pad);
> > +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> > +		return &priv->format;
> > +	default:
> > +		return NULL;
> > +	}
> > +}
> > +
> > +static int ov1063x_init_cfg(struct v4l2_subdev *sd,
> > +			    struct v4l2_subdev_pad_config *cfg)
> > +{
> > +	u32 which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
> > +	struct ov1063x_priv *priv = to_ov1063x(sd);
> > +	struct v4l2_mbus_framefmt *format;
> > +
> > +	format = __ov1063x_get_pad_format(priv, cfg, 0, which);
> > +	format->code = ov1063x_mbus_formats[0];
> > +	format->width = ov1063x_framesizes[0].width;
> > +	format->height = ov1063x_framesizes[0].height;
> > +	format->field = V4L2_FIELD_NONE;
> > +	format->colorspace = V4L2_COLORSPACE_SMPTE170M;
> > +
> > +	if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > +		/*
> > +		 * This assumes that ov1063x_mbus_formats[0] doesn't
> > +		 * sub-sample.
> > +		 */
> > +		priv->analog_crop.width = OV1063X_SENSOR_WIDTH;
> > +		priv->analog_crop.height = format->height;
> > +		priv->analog_crop.left = ((OV1063X_SENSOR_WIDTH -
> > +					   priv->analog_crop.width) / 2) & ~1;
> > +		priv->analog_crop.top = ((OV1063X_SENSOR_HEIGHT -
> > +					  priv->analog_crop.height) / 2) & ~1;
> > +
> > +		priv->digital_crop.width = format->width;
> > +		priv->digital_crop.height = format->height;
> > +		priv->digital_crop.left = ((priv->analog_crop.width -
> > +					    priv->digital_crop.width) / 2) & ~1;
> > +		priv->digital_crop.top = 0;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_enum_mbus_code(struct v4l2_subdev *sd,
> > +				  struct v4l2_subdev_pad_config *cfg,
> > +				  struct v4l2_subdev_mbus_code_enum *code)
> > +{
> > +	if (code->index >= ARRAY_SIZE(ov1063x_mbus_formats))
> > +		return -EINVAL;
> > +
> > +	code->code = ov1063x_mbus_formats[code->index];
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_enum_frame_sizes(struct v4l2_subdev *sd,
> > +				    struct v4l2_subdev_pad_config *cfg,
> > +				    struct v4l2_subdev_frame_size_enum *fse)
> > +{
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(ov1063x_mbus_formats); ++i) {
> > +		if (ov1063x_mbus_formats[i] == fse->code)
> > +			break;
> > +	}
> > +
> > +	if (i == ARRAY_SIZE(ov1063x_mbus_formats))
> > +		return -EINVAL;
> > +
> > +	if (fse->index >= ARRAY_SIZE(ov1063x_framesizes))
> > +		return -EINVAL;
> > +
> > +	fse->min_width  = ov1063x_framesizes[fse->index].width;
> > +	fse->max_width  = fse->min_width;
> > +	fse->max_height = ov1063x_framesizes[fse->index].height;
> > +	fse->min_height = fse->max_height;
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_get_fmt(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_pad_config *cfg,
> > +			   struct v4l2_subdev_format *fmt)
> > +{
> > +	struct ov1063x_priv *priv = to_ov1063x(sd);
> > +
> > +	fmt->format = *__ov1063x_get_pad_format(priv, cfg, fmt->pad,
> > +						fmt->which);
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_set_fmt(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_pad_config *cfg,
> > +			   struct v4l2_subdev_format *fmt)
> > +{
> > +	struct ov1063x_priv *priv = to_ov1063x(sd);
> > +	struct v4l2_mbus_framefmt *format;
> > +	const struct v4l2_area *fsize;
> > +	unsigned int i;
> > +	u32 code;
> > +	int ret = 0;
> > +
> > +	/*
> > +	 * Validate the media bus code, defaulting to the first one if the
> > +	 * requested code isn't supported.
> > +	 */
> > +	for (i = 0; i < ARRAY_SIZE(ov1063x_mbus_formats); ++i) {
> > +		if (ov1063x_mbus_formats[i] == fmt->format.code) {
> > +			code = fmt->format.code;
> > +			break;
> > +		}
> > +	}
> > +
> > +	if (i == ARRAY_SIZE(ov1063x_mbus_formats))
> > +		code = ov1063x_mbus_formats[0];
> 
> You could do this assignment unconditionally in variable initialisation.

That's true. Do you mind it being separate though ? I like that it's
kept close to the for loop, to group all the related code together.

> > +
> > +	/* Find the nearest supported frame size. */
> > +	fsize = v4l2_find_nearest_size(ov1063x_framesizes,
> > +				       ARRAY_SIZE(ov1063x_framesizes),
> > +				       width, height, fmt->format.width,
> > +				       fmt->format.height);
> > +
> > +	/* Update the stored format and return it. */
> > +	format = __ov1063x_get_pad_format(priv, cfg, fmt->pad, fmt->which);
> > +
> > +	mutex_lock(priv->hdl.lock);
> > +
> > +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming) {
> > +		ret = -EBUSY;
> > +		goto done;
> > +	}
> > +
> > +	format->code = code;
> > +	format->width = fsize->width;
> > +	format->height = fsize->height;
> > +
> > +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > +		unsigned int hsub;
> > +		unsigned int vsub;
> > +
> > +		/*
> > +		 * Enable horizontal or vertical sub-sampling automatically when
> > +		 * the width or height are smaller than half the maximum
> > +		 * resolution.
> > +		 */
> > +		hsub = format->width <= 640 ? 2 : 1;
> > +		vsub = format->height <= 400 ? 2 : 1;
> > +
> > +		/*
> > +		 * The analog horizontal crop is restricted to the full sensor
> > +		 * width (1312 pixels), 768 or 656 pixels. Additional cropping
> > +		 * will be applied in the digital domain.
> > +		 */
> > +		priv->analog_crop.width = format->width * hsub;
> > +		priv->analog_crop.height = format->height * vsub;
> > +
> > +		if (priv->analog_crop.width > 768)
> > +			priv->analog_crop.width = OV1063X_SENSOR_WIDTH;
> > +		else if (priv->analog_crop.width > 656)
> > +			priv->analog_crop.width = 768;
> > +		else
> > +			priv->analog_crop.width = 656;
> > +
> > +		/*
> > +		 * The digital crop is applied at the ISP input, before
> > +		 * horizontal sub-sampling but after vertical sub-sampling as
> > +		 * the latter is applied in the pixel array.
> > +		 */
> > +		priv->digital_crop.width = format->width * hsub;
> > +		priv->digital_crop.height = format->height;
> > +
> > +		/*
> > +		 * Center the crop rectangles, rounding coordinates to a
> > +		 * multiple of 2 to avoid changing the Bayer pattern.
> > +		 */
> > +		priv->analog_crop.left = ((OV1063X_SENSOR_WIDTH -
> > +					   priv->analog_crop.width) / 2) & ~1;
> > +		priv->analog_crop.top = ((OV1063X_SENSOR_HEIGHT -
> > +					  priv->analog_crop.height) / 2) & ~1;
> > +		priv->digital_crop.left = ((priv->analog_crop.width -
> > +					    priv->digital_crop.width) / 2) & ~1;
> > +		priv->analog_crop.top = 0;
> > +	}
> > +
> > +	fmt->format = *format;
> > +
> > +done:
> > +	mutex_unlock(priv->hdl.lock);
> > +
> > +	return ret;
> > +}
> > +
> > +static const struct v4l2_subdev_core_ops ov1063x_subdev_core_ops = {
> > +	.log_status		= v4l2_ctrl_subdev_log_status,
> > +	.subscribe_event	= v4l2_ctrl_subdev_subscribe_event,
> > +	.unsubscribe_event	= v4l2_event_subdev_unsubscribe,
> > +};
> > +
> > +static const struct v4l2_subdev_video_ops ov1063x_subdev_video_ops = {
> > +	.s_stream	= ov1063x_s_stream,
> > +};
> > +
> > +static const struct v4l2_subdev_pad_ops ov1063x_subdev_pad_ops = {
> > +	.init_cfg		= ov1063x_init_cfg,
> > +	.enum_mbus_code		= ov1063x_enum_mbus_code,
> > +	.enum_frame_size	= ov1063x_enum_frame_sizes,
> > +	.get_fmt		= ov1063x_get_fmt,
> > +	.set_fmt		= ov1063x_set_fmt,
> > +};
> > +
> > +static const struct v4l2_subdev_ops ov1063x_subdev_ops = {
> > +	.core	= &ov1063x_subdev_core_ops,
> > +	.video	= &ov1063x_subdev_video_ops,
> > +	.pad	= &ov1063x_subdev_pad_ops,
> > +};
> > +
> > +/* -----------------------------------------------------------------------------
> > + * Power Management
> > + */
> > +
> > +static int ov1063x_power_on_init(struct ov1063x_priv *priv)
> > +{
> > +	struct i2c_client *client = to_i2c_client(priv->dev);
> > +	unsigned int i;
> > +	int ret;
> > +
> > +	ret = ov1063x_write(priv, OV1063X_SOFTWARE_RESET, 0x01, NULL);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = ov1063x_isp_reset(priv, true);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	/*
> > +	 * Why the I2C address has to be written 23 times (or, actually, at
> > +	 * all) is unknown. This may not be required.
> > +	 */
> > +	for (i = 0; i < 23; ++i) {
> > +		ret = ov1063x_write(priv, OV1063X_SC_CMMN_SCCB_ID,
> > +				    OV1063X_SC_CMMN_SCCB_ID_ADDR(client->addr) |
> > +				    OV1063X_SC_CMMN_SCCB_ID_SEL, NULL);
> > +		if (ret < 0)
> > +			return ret;
> > +	}
> > +
> > +	ret = ov1063x_write_array(priv, ov1063x_regs_default,
> > +				  ARRAY_SIZE(ov1063x_regs_default));
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = ov1063x_isp_reset(priv, false);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	usleep_range(500, 510);
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_power_on(struct ov1063x_priv *priv)
> > +{
> > +	int ret;
> > +
> > +	ret = clk_prepare_enable(priv->clk);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (priv->pwdn_gpio) {
> > +		gpiod_set_value_cansleep(priv->pwdn_gpio, 0);
> > +		usleep_range(1000, 1200);
> > +	}
> > +
> > +	if (priv->reset_gpio) {
> > +		gpiod_set_value_cansleep(priv->reset_gpio, 0);
> > +		usleep_range(250000, 260000);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void ov1063x_power_off(struct ov1063x_priv *priv)
> > +{
> > +	gpiod_set_value_cansleep(priv->pwdn_gpio, 1);
> > +	gpiod_set_value_cansleep(priv->reset_gpio, 1);
> > +
> > +	clk_disable_unprepare(priv->clk);
> > +}
> > +
> > +static int ov1063x_runtime_resume(struct device *dev)
> > +{
> > +	struct i2c_client *client = to_i2c_client(dev);
> > +	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
> > +	struct ov1063x_priv *priv = to_ov1063x(subdev);
> > +	int ret;
> > +
> > +	ret = ov1063x_power_on(priv);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = ov1063x_power_on_init(priv);
> > +	if (ret < 0) {
> > +		ov1063x_power_off(priv);
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov1063x_runtime_suspend(struct device *dev)
> > +{
> > +	struct i2c_client *client = to_i2c_client(dev);
> > +	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
> > +	struct ov1063x_priv *priv = to_ov1063x(subdev);
> > +
> > +	ov1063x_power_off(priv);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct dev_pm_ops ov1063x_pm_ops = {
> > +	SET_RUNTIME_PM_OPS(ov1063x_runtime_suspend, ov1063x_runtime_resume, NULL)
> > +};
> > +
> > +/* -----------------------------------------------------------------------------
> > + * I2C Driver, Probe & Remove
> > + */
> > +
> > +static int ov1063x_detect(struct ov1063x_priv *priv)
> > +{
> > +	u32 pid;
> > +	int ret;
> > +
> > +	/* Read and check the product ID. */
> > +	ret = ov1063x_read(priv, OV1063X_PID, &pid);
> > +	if (ret)
> > +		return ret;
> > +
> > +	switch (pid) {
> > +	case OV10633_VERSION_REG:
> > +		priv->model = SENSOR_OV10633;
> > +		priv->name = "ov10633";
> > +		break;
> > +	case OV10635_VERSION_REG:
> > +		priv->model = SENSOR_OV10635;
> > +		priv->name = "ov10635";
> > +		break;
> > +	default:
> > +		dev_err(priv->dev, "Unknown product ID %04x\n", pid);
> > +		return -ENODEV;
> > +	}
> > +
> > +	dev_dbg(priv->dev, "%s detected\n", priv->name);
> 
> You print the name of the sensor at the end of probe already.

Note that this is a debug message, which could be useful in case probe
fails after the call to ov1063x_detect(). Should I drop it ?

> > +
> > +	return 0;
> > +}
> > +
> > +static const struct regmap_config ov1063x_regmap_config = {
> > +	.reg_bits = 16,
> > +	.val_bits = 8,
> > +};
> > +
> > +static int ov1063x_probe(struct i2c_client *client)
> > +{
> > +	struct ov1063x_priv *priv;
> > +	struct v4l2_subdev *sd;
> > +	int ret;
> > +
> > +	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	priv->dev = &client->dev;
> > +
> > +	/* Acquire resources: regmap, GPIOs and clock. The GPIOs are optional. */
> > +	priv->regmap = devm_regmap_init_i2c(client, &ov1063x_regmap_config);
> > +	if (IS_ERR(priv->regmap))
> > +		return PTR_ERR(priv->regmap);
> > +
> > +	priv->pwdn_gpio = devm_gpiod_get_optional(priv->dev, "powerdown",
> > +						  GPIOD_OUT_HIGH);
> > +	if (IS_ERR(priv->pwdn_gpio))
> > +		return PTR_ERR(priv->pwdn_gpio);
> > +
> > +	priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
> > +						   GPIOD_OUT_HIGH);
> > +	if (IS_ERR(priv->reset_gpio))
> > +		return PTR_ERR(priv->reset_gpio);
> > +	priv->clk = devm_clk_get(priv->dev, "xvclk");
> > +	if (IS_ERR(priv->clk)) {
> > +		ret = PTR_ERR(priv->clk);
> > +		dev_err(priv->dev, "Failed to get xvclk clock: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	priv->clk_rate = clk_get_rate(priv->clk);
> > +	dev_dbg(priv->dev, "xvclk rate: %lu Hz\n", priv->clk_rate);
> > +
> > +	if (priv->clk_rate < 6000000 || priv->clk_rate > 27000000)
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * Enable power and detect the device.
> > +	 *
> > +	 * The driver supports runtime PM, but needs to work when runtime PM is
> > +	 * disabled in the kernel. To that end, power it on manually here.
> > +	 */
> > +	ret = ov1063x_power_on(priv);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = ov1063x_detect(priv);
> > +	if (ret)
> > +		goto err_power;
> > +
> > +	/* Initialize the subdev and its controls. */
> > +	sd = &priv->subdev;
> > +	v4l2_i2c_subdev_init(sd, client, &ov1063x_subdev_ops);
> > +	v4l2_i2c_subdev_set_name(sd, client, priv->name, NULL);
> > +
> > +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
> > +		     V4L2_SUBDEV_FL_HAS_EVENTS;
> > +
> > +	v4l2_ctrl_handler_init(&priv->hdl, 3);
> > +	v4l2_ctrl_new_std(&priv->hdl, &ov1063x_ctrl_ops,
> > +			  V4L2_CID_VFLIP, 0, 1, 1, 0);
> > +	v4l2_ctrl_new_std(&priv->hdl, &ov1063x_ctrl_ops,
> > +			  V4L2_CID_HFLIP, 0, 1, 1, 0);
> > +	v4l2_ctrl_new_std_menu_items(&priv->hdl, &ov1063x_ctrl_ops,
> > +				     V4L2_CID_TEST_PATTERN,
> > +				     ARRAY_SIZE(ov1063x_test_pattern_menu) - 1,
> > +				     0, 0, ov1063x_test_pattern_menu);
> > +
> > +	if (priv->hdl.error) {
> > +		ret = priv->hdl.error;
> > +		goto err_power;
> > +	}
> > +
> > +	sd->ctrl_handler = &priv->hdl;
> > +
> > +	/* Default framerate */
> > +	priv->fps_numerator = 30;
> > +	priv->fps_denominator = 1;
> > +	ov1063x_init_cfg(&priv->subdev, NULL);
> > +
> > +	/* Initialize the media entity. */
> > +	priv->pad.flags = MEDIA_PAD_FL_SOURCE;
> > +	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
> > +	ret = media_entity_pads_init(&sd->entity, 1, &priv->pad);
> > +	if (ret < 0)
> > +		goto err_ctrls;
> > +
> > +	/*
> > +	 * Enable runtime PM. As the device has been powered manually, mark it
> > +	 * as active, and increase the usage count without resuming the device.
> > +	 */
> > +	pm_runtime_set_active(priv->dev);
> > +	pm_runtime_get_noresume(priv->dev);
> > +	pm_runtime_enable(priv->dev);
> > +
> > +	/*
> > +	 * Enable autosuspend as it can help avoiding costly power transitions
> > +	 * when reconfiguring the sensor.
> > +	 */
> > +	pm_runtime_set_autosuspend_delay(priv->dev, 1000);
> > +	pm_runtime_use_autosuspend(priv->dev);
> > +
> > +	/*
> > +	 * At this point the device is powered on and active from a runtime PM
> > +	 * point of view, but hasn't gone through the full initialization
> > +	 * performed by the runtime resume operation. Suspend it synchronously
> > +	 * to turn the power off, ensuring proper initialization will take
> > +	 * place before the first usage.
> > +	 */
> > +	pm_runtime_put_sync(priv->dev);
> > +
> > +	/*
> > +	 * In case runtime PM is disabled in the kernel, the device remains
> > +	 * active and needs to be fully initialized at this point.
> > +	 */
> > +	if (!pm_runtime_status_suspended(priv->dev)) {
> > +		ret = ov1063x_power_on_init(priv);
> > +		if (ret < 0)
> > +			goto err_pm;
> > +	}
> > +
> > +	/* Finally, register the subdev. */
> > +	ret = v4l2_async_register_subdev(sd);
> > +	if (ret < 0)
> > +		goto err_pm;
> > +
> > +	dev_info(priv->dev, "%s probed\n", priv->name);
> > +
> > +	return 0;
> > +
> > +err_pm:
> > +	pm_runtime_disable(priv->dev);
> > +	media_entity_cleanup(&priv->subdev.entity);
> > +err_ctrls:
> > +	v4l2_ctrl_handler_free(&priv->hdl);
> > +err_power:
> > +	if (!pm_runtime_status_suspended(priv->dev))
> > +		ov1063x_power_off(priv);
> > +	return ret;
> > +}
> > +
> > +static int ov1063x_remove(struct i2c_client *client)
> > +{
> > +	struct ov1063x_priv *priv = i2c_get_clientdata(client);
> > +
> > +	v4l2_ctrl_handler_free(&priv->hdl);
> > +	v4l2_async_unregister_subdev(&priv->subdev);
> > +	media_entity_cleanup(&priv->subdev.entity);
> > +
> > +	/*
> > +	 * Disable runtime PM. In case runtime PM is disabled in the kernel,
> > +	 * make sure to turn power off manually.
> > +	 */
> > +	pm_runtime_disable(priv->dev);
> > +	if (!pm_runtime_status_suspended(priv->dev))
> > +		ov1063x_power_off(priv);
> > +	pm_runtime_set_suspended(priv->dev);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct of_device_id ov1063x_dt_id[] = {
> > +	{ .compatible = "ovti,ov10635" },
> > +	{ .compatible = "ovti,ov10633" },
> > +	{ /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, ov1063x_dt_id);
> > +
> > +static struct i2c_driver ov1063x_i2c_driver = {
> > +	.driver = {
> > +		.name = "ov1063x",
> > +		.of_match_table = of_match_ptr(ov1063x_dt_id),
> > +		.pm = &ov1063x_pm_ops,
> > +	},
> > +	.probe_new = ov1063x_probe,
> > +	.remove = ov1063x_remove,
> > +};
> > +
> > +module_i2c_driver(ov1063x_i2c_driver);
> > +
> > +MODULE_DESCRIPTION("Camera Sensor Driver for OmniVision OV10633/OV10635");
> > +MODULE_AUTHOR("Texas Instruments Inc.");
> > +MODULE_LICENSE("GPL v2");
> 
> "GPL"

Ack.

> > diff --git a/drivers/media/i2c/ov1063x_regs.h b/drivers/media/i2c/ov1063x_regs.h
> > new file mode 100644
> > index 000000000000..43a0ca1d1367
> > --- /dev/null
> > +++ b/drivers/media/i2c/ov1063x_regs.h
> > @@ -0,0 +1,626 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * OmniVision OV1063x Camera Driver
> > + *
> > + * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
> > + * Copyright (C) 2020 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > + */
> > +
> > +struct ov1063x_reg {
> > +	u32	reg;
> > +	u32	val;
> > +};
> > +
> > +static const struct ov1063x_reg ov1063x_regs_default[] = {
> > +	/* Register configuration for full resolution : 1280x720 */
> > +	{ OV1063X_SC_CMMN_MISC_CTRL, 0x02 |
> > +				     OV1063X_SC_CMMN_MISC_CTRL_CEN_GLOBAL_O },
> > +	{ OV1063X_SC_CMMN_PAD, 0x02 },
> > +	{ OV1063X_HORIZ_COLORCORRECT, 0x0c },
> > +	{ OV1063X_REG_8BIT(0x6901), 0x01 },
> > +	{ OV1063X_SC_CMMN_SCLK2X_SEL, OV1063X_SC_CMMN_SCLK2X_SEL_DIV4 },
> > +	{ OV1063X_AEC_PK_MANUAL, OV1063X_AEC_PK_MANUAL_DELAY },
> > +	{ OV1063X_SC_CMMN_PWDN_CTRL2, 0x20 |
> > +				      OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG1 |
> > +				      OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG2 |
> > +				      OV1063X_SC_CMMN_PWDN_CTRL2_RST_ISP |
> > +				      OV1063X_SC_CMMN_PWDN_CTRL2_SEQUENCE },
> > +	{ OV1063X_SC_CMMN_CORE_CTRL1, 0x03 },
> > +	/*
> > +	 * For 15fps
> > +	 *
> > +	 * XVCLK: 9MHz
> > +	 * Pre divider: 1
> > +	 * Multiplier: 32
> > +	 * Divider: 8
> > +	 * SCLK: 36MHz
> > +	 */
> > +	{ OV1063X_SC_CMMN_PLL_CTRL0, OV1063X_SC_CMMN_PLL_SCLK_CP(0) |
> > +				     OV1063X_SC_CMMN_PLL_SCLK_MULTI(32) },
> > +	{ OV1063X_SC_CMMN_PLL_CTRL1, OV1063X_SC_CMMN_PLL_SCLK_PRE_DIV(0) |
> > +				     OV1063X_SC_CMMN_PLL_SCLK_CP2(0) |
> > +				     OV1063X_SC_CMMN_PLL_SCLK_DIV(3) },
> > +	{ OV1063X_SC_CMMN_PLL_CTRL2, OV1063X_SC_CMMN_PLL_SCLK_CP(0) |
> > +				     OV1063X_SC_CMMN_PLL_SCLK_MULTI(32) },
> > +	{ OV1063X_SC_CMMN_PLL_CTRL3, OV1063X_SC_CMMN_PLL_PCLK_BYPASS |
> > +				     OV1063X_SC_CMMN_PLL_SCLK_PRE_DIV(1) |
> > +				     OV1063X_SC_CMMN_PLL_SCLK_CP2(0) |
> > +				     OV1063X_SC_CMMN_PLL_SCLK_DIV(1) },
> > +	{ OV1063X_ANA_ADC1, 0x74 },
> > +	{ OV1063X_ANA_ADC2, 0x2b },
> > +	{ OV1063X_ANA_ANALOG3, 0x00 },
> > +	{ OV1063X_ANA_ANALOG2, 0x67 },
> > +	{ OV1063X_ANA_PWC4, 0xba },
> > +	{ OV1063X_ANA_ADC3, 0x2f },
> > +	{ OV1063X_ANA_ADC4, 0x00 },
> > +	{ OV1063X_ANA_PWC1, 0xa8 },
> > +	{ OV1063X_ANA_PWC2, 0x16 },
> > +	{ OV1063X_SENSOR_EQ_GOLOW, 0x10 },
> > +	{ OV1063X_SENSOR_BITSW_GO, 0x0001 },
> > +	{ OV1063X_FORMAT_CTRL00, OV1063X_FORMAT_UYVY },
> > +	{ OV1063X_SC_CMMN_PCLK_DIV_CTRL, 1 },
> > +	{ OV1063X_SC_CMMN_CORE_CTRL_3, OV1063X_SC_CMMN_CORE_CTRL_PCLK_SEC },
> > +	{ OV1063X_SC_CMMN_CLOCK_SEL, 0x0b },
> > +	{ OV1063X_SENSOR_RSTGOLOW, 0x0d },
> > +	{ OV1063X_SENSOR_HLDWIDTH, 0x20 },
> > +	{ OV1063X_SENSOR_TXWIDTH, 0x15 },
> > +	{ OV1063X_SENSOR_REG9, 0x28 },
> > +	{ OV1063X_SENSOR_REGD, 0x00 },
> > +	{ OV1063X_SENSOR_RSTYZ_GOLOW, 32 },
> > +	{ OV1063X_SENSOR_REG15, 0x04 },
> > +	{ OV1063X_TIMING_CTRL1D, OV1063X_TIMING_CTRL1D_WDR },
> > +	{ OV1063X_TIMING_CTRL1C, 0 },
> > +	{ OV1063X_REG_8BIT(0x3824), 0x10 },
> > +	{ OV1063X_TIMING_CTRL15, OV1063X_TIMING_CTRL15_BLACK_LINE_HREF |
> > +				 OV1063X_TIMING_CTRL15_BLACK_LINES(12) },
> > +	{ OV1063X_TIMING_X_END_ADDR, 1311 },
> > +	{ OV1063X_TIMING_X_START_ADDR, 0 },
> > +	{ OV1063X_TIMING_Y_END_ADDR, 769 },
> > +	{ OV1063X_TIMING_Y_START_ADDR, 46 },
> > +	{ OV1063X_TIMING_X_OUTPUT_SIZE, 1280 },
> > +	{ OV1063X_TIMING_Y_OUTPUT_SIZE, 720 },
> > +	{ OV1063X_TIMING_HTS, 1782 },
> > +	{ OV1063X_TIMING_VTS, 748 },
> > +	{ OV1063X_TIMING_ISP_X_WIN, 8 },
> > +	{ OV1063X_VSTART_OFFSET, 12 },
> > +	{ OV1063X_ANA_ARRAY1, 0x60 |
> > +			      OV1063X_ANA_ARRAY1_FULL |
> > +			      OV1063X_ANA_ARRAY1_DELAY(3) },
> > +	{ OV1063X_ISP_RW05, OV1063X_ISP_RW05_SUB_AVG },
> > +	{ OV1063X_AEC_CTRLD5, 8 * 1024 * 1024 },
> > +	{ OV1063X_AEC_CTRLD9, 8 * 1024 * 1024 },
> > +	{ OV1063X_AEC_CTRLE8, 127 },
> > +	{ OV1063X_AEC_CTRLEA, 127 },
> > +	{ OV1063X_GAIN_AWB_MAN_GAIN_B_LONG, 128 },
> > +	{ OV1063X_GAIN_AWB_MAN_GAIN_GB_LONG, 128 },
> > +	{ OV1063X_GAIN_AWB_MAN_GAIN_GR_LONG, 128 },
> > +	{ OV1063X_GAIN_AWB_MAN_GAIN_R_LONG, 128 },
> > +	{ OV1063X_GAIN_AWB_MAN_OFFSET_B_LONG, 0 },
> > +	{ OV1063X_GAIN_AWB_MAN_OFFSET_GB_LONG, 0 },
> > +	{ OV1063X_GAIN_AWB_MAN_OFFSET_GR_LONG, 0 },
> > +	{ OV1063X_GAIN_AWB_MAN_OFFSET_R_LONG, 0 },
> > +	{ OV1063X_GAIN_AWB_MAN_GAIN_B_SHORT, 128 },
> > +	{ OV1063X_GAIN_AWB_MAN_GAIN_GB_SHORT, 128 },
> > +	{ OV1063X_GAIN_AWB_MAN_GAIN_GR_SHORT, 128 },
> > +	{ OV1063X_GAIN_AWB_MAN_GAIN_R_SHORT, 128 },
> > +	{ OV1063X_GAIN_AWB_MAN_OFFSET_B_SHORT, 0 },
> > +	{ OV1063X_GAIN_AWB_MAN_OFFSET_GB_SHORT, 0 },
> > +	{ OV1063X_GAIN_AWB_MAN_OFFSET_GR_SHORT, 0 },
> > +	{ OV1063X_GAIN_AWB_MAN_OFFSET_R_SHORT, 0 },
> > +	{ OV1063X_AEC_CTRLD0, OV1063X_AEC_CTRLD0_R_MAN_EN(0) },
> > +	{ OV1063X_ISP_RW06, OV1063X_ISP_RW06_YUV_MODE_MAN(2) |
> > +			    OV1063X_ISP_RW06_YUV_MODE_MAN_EN },
> > +	{ OV1063X_AEC_CTRL07, 0 },
> > +	{ OV1063X_CIP_HFREQ_COEF_SHORT, 0x06 },
> > +	{ OV1063X_CIP_MAX_SHARPEN_LONG, 0x08 },
> > +	{ OV1063X_CIP_SHARPEN_ALPHA_LONG, 0x12 },
> > +	{ OV1063X_CIP_SHARPEN_ALPHA_SHORT, 0x12 },
> > +	{ OV1063X_CIP_UNSHARPEN_MASK_LONG(0), 0x06 },
> > +	{ OV1063X_CIP_UNSHARPEN_MASK_LONG(1), 0x20 },
> > +	{ OV1063X_CIP_UNSHARPEN_MASK_SHORT(0), 0x06 },
> > +	{ OV1063X_CIP_UNSHARPEN_MASK_SHORT(1), 0x20 },
> > +	{ OV1063X_CIP_MAX_SHARPEN_SHORT, 0x04 },
> > +	{ OV1063X_LLF_MAX_LOW_LEVEL, 255 },
> > +	{ OV1063X_AWB_M_X_LONG, 0x76 },
> > +	{ OV1063X_AWB_M_Y_LONG, 0x47 },
> > +	{ OV1063X_AWB_L_K_LONG, 0xef },
> > +	{ OV1063X_AWB_H_K_LONG, 0xc9 },
> > +	{ OV1063X_AWB_H_LMT_LONG, 0x49 },
> > +	{ OV1063X_AWB_L_LMT_LONG, 0x30 },
> > +	{ OV1063X_REG_8BIT(0x558f), 0x67 },
> > +	{ OV1063X_REG_8BIT(0x5590), 0x3f },
> > +	{ OV1063X_AWB_DATA_ULMT_LONG, 0xf0 },
> > +	{ OV1063X_AWB_DATA_LLMT_LONG, 0x10 },
> > +	{ OV1063X_AWB_M_X_SHORT, 0x6d },
> > +	{ OV1063X_AWB_M_Y_SHORT, 0x55 },
> > +	{ OV1063X_AWB_L_K_SHORT, 0xc3 },
> > +	{ OV1063X_AWB_H_K_SHORT, 0xb5 },
> > +	{ OV1063X_AWB_H_LMT_SHORT, 0x43 },
> > +	{ OV1063X_AWB_L_LMT_SHORT, 0x38 },
> > +	{ OV1063X_REG_8BIT(0x55a8), 0x5f },
> > +	{ OV1063X_REG_8BIT(0x55a9), 0x4b },
> > +	{ OV1063X_AWB_DATA_ULMT_SHORT, 0xf0 },
> > +	{ OV1063X_AWB_DATA_LLMT_SHORT, 0x10 },
> > +	{ OV1063X_AWB_CT_CTRL1, OV1063X_AWB_CT_CTRL1_GAIN_STEP_NORMAL(1) |
> > +				OV1063X_AWB_CT_CTRL1_GAIN_STEP_FAST(1) |
> > +				OV1063X_AWB_CT_CTRL1_SCALE_LONG_2X |
> > +				0x02 },
> > +	{ OV1063X_REG_8BIT(0x5300), 0x01 },
> > +	{ OV1063X_REG_8BIT(0x5301), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5302), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5303), 0x0e },
> > +	{ OV1063X_REG_8BIT(0x5304), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5305), 0x0e },
> > +	{ OV1063X_REG_8BIT(0x5306), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5307), 0x36 },
> > +	{ OV1063X_REG_8BIT(0x5308), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5309), 0xd9 },
> > +	{ OV1063X_REG_8BIT(0x530a), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x530b), 0x0f },
> > +	{ OV1063X_REG_8BIT(0x530c), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x530d), 0x2c },
> > +	{ OV1063X_REG_8BIT(0x530e), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x530f), 0x59 },
> > +	{ OV1063X_REG_8BIT(0x5310), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5311), 0x7b },
> > +	{ OV1063X_REG_8BIT(0x5312), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5313), 0x22 },
> > +	{ OV1063X_REG_8BIT(0x5314), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5315), 0xd5 },
> > +	{ OV1063X_REG_8BIT(0x5316), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5317), 0x13 },
> > +	{ OV1063X_REG_8BIT(0x5318), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5319), 0x18 },
> > +	{ OV1063X_REG_8BIT(0x531a), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x531b), 0x26 },
> > +	{ OV1063X_REG_8BIT(0x531c), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x531d), 0xdc },
> > +	{ OV1063X_REG_8BIT(0x531e), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x531f), 0x02 },
> > +	{ OV1063X_REG_8BIT(0x5320), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5321), 0x24 },
> > +	{ OV1063X_REG_8BIT(0x5322), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5323), 0x56 },
> > +	{ OV1063X_REG_8BIT(0x5324), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5325), 0x85 },
> > +	{ OV1063X_REG_8BIT(0x5326), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5327), 0x20 },
> > +	{ OV1063X_AEC_WIN_LEFT_LONG, 320 },
> > +	{ OV1063X_AEC_WIN_LEFT_SHORT, 320 },
> > +	{ OV1063X_AEC_WIN_TOP_LONG, 250 },
> > +	{ OV1063X_AEC_WIN_TOP_SHORT, 250 },
> > +	{ OV1063X_AEC_WIN_WIDTH_LONG, 640 },
> > +	{ OV1063X_AEC_WIN_WIDTH_SHORT, 640 },
> > +	{ OV1063X_AEC_WIN_HEIGHT_LONG, 300 },
> > +	{ OV1063X_AEC_WIN_HEIGHT_SHORT, 300 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(0), 1 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(1), 1 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(2), 1 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(3), 1 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(4), 3 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(5), 3 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(6), 3 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(7), 5 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(8), 9 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(9), 5 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(10), 5 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(11), 5 },
> > +	{ OV1063X_AEC_WEIGHT_SHORT(12), 5 },
> > +	{ OV1063X_AEC_FINAL_SATURATE_THRESH, 128 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(0), 1 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(1), 3 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(2), 6 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(3), 10 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(4), 14 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(5), 18 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_LONG(6), 22 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(0), 2 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(1), 4 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(2), 8 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(3), 12 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(4), 18 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(5), 24 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_LONG(6), 30 },
> > +	{ OV1063X_DNS_GBGR_EXTRA_SHORT, 4 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(0), 1 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(1), 3 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(2), 6 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(3), 10 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(4), 14 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(5), 18 },
> > +	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(6), 22 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(0), 3 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(1), 4 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(2), 8 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(3), 12 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(4), 18 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(5), 24 },
> > +	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(6), 30 },
> > +	{ OV1063X_VFIFO_LLEN_FIRS1_SEL, 0x00 }, /* 8-bit YUV mode */
> > +	{ OV1063X_VFIFO_LINE_LENGTH_MAN, 1905 },
> > +	{ OV1063X_VFIFO_HSYNC_START_POSITION, 624 },
> > +	{ OV1063X_VFIFO_HSYNC_CTRL, OV1063X_VFIFO_HSYNC_CTRL_HEADER_WIDTH(0) |
> > +				    OV1063X_VFIFO_HSYNC_CTRL_TRAILER_WIDTH(0) },
> > +	{ OV1063X_ROI_CTRL0, OV1063X_ROI_CTRL0_EN_3 |
> > +			     OV1063X_ROI_CTRL0_EN_2 |
> > +			     OV1063X_ROI_CTRL0_EN_1 },
> > +	{ OV1063X_DVP_MOD_SEL, OV1063X_DVP_MOD_SEL_CCIR_F },
> > +	{ OV1063X_DVP_VSYNC_WIDTH, 1 },
> > +	{ OV1063X_DVP_HSYVSY_NEG_WIDTH, 0 },
> > +	{ OV1063X_DVP_VSYNC_MODE, OV1063X_DVP_VSYNC_MODE_VSYNCOUT_SEL(0) },
> > +	/*
> > +	 * Non-overlapping HSYNC-VSYNC.
> > +	 * Therefore do not set the VSYNC delay registers.
> > +	 */
> > +	{ OV1063X_DVP_EOF_VSYNC_DELAY, 0 },
> > +	{ OV1063X_LINE_NUM, 8 },
> > +	{ OV1063X_BLC_CTRL05, OV1063X_BLC_CTRL05_REMOVE_BLACK_LINE |
> > +			      OV1063X_BLC_CTRL05_ONE_MAN_OFFSET_MODE },
> > +	{ OV1063X_START_LINE, 4 },
> > +	{ OV1063X_BLC_AVG_CTRL1, 0x20 },
> > +	{ OV1063X_BLC_AVG_CTRL2, 0x22 },
> > +	{ OV1063X_BLC_OFFSET_TOP_LIMIT, 1948 },
> > +	{ OV1063X_BLC_CTRL5A, 0x00 },
> > +	{ OV1063X_FC_R2, 2 },
> > +	{ OV1063X_SC_CMMN_CORE_CTRL_2, OV1063X_SC_CMMN_CORE_CTRL_CLK_SWITCH },
> > +	{ OV1063X_STREAM_MODE, OV1063X_STREAM_MODE_ON },
> > +	{ OV1063X_STREAM_MODE, OV1063X_STREAM_MODE_ON },
> > +	{ OV1063X_REG_8BIT(0x6f0e), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x6f0f), 0x00 },
> > +	{ OV1063X_VFIFO_EMBD_LINE_CTRL, OV1063X_VFIFO_EMBD_LINE_CTRL_SOF_CLR_RAM },
> > +	{ OV1063X_VFIFO_EMBD_LINE_NUM, 1 },
> > +	{ OV1063X_REG_8BIT(0x4610), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x4611), 0x01 },
> > +	{ OV1063X_REG_8BIT(0x4612), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x4613), 0x01 },
> > +	{ OV1063X_VFIFO_LLEN_FIRS1_SEL, 0x00 },
> > +	{ OV1063X_VFIFO_READ_START, 8 },
> > +	{ OV1063X_EMB_SIZE_MANU_EN, 0 },
> > +	{ OV1063X_EMB_SIZE_MANU, 1536 },
> > +	{ OV1063X_GAIN_AWB_CTRL32, 0 },
> > +	{ OV1063X_REG_8BIT(0x3510), 0x00 },
> > +	{ OV1063X_AEC_PK_MAN_DONE, 0 },
> > +	{ OV1063X_EMB_LINE_EN, 0 },
> > +	{ OV1063X_REG_8BIT(0x6f0d), 0x00 },
> > +	{ OV1063X_ISP_RW00, OV1063X_ISP_RW00_COLOR_MATRIX_EN |
> > +			    OV1063X_ISP_RW00_COLOR_INTERP_EN |
> > +			    OV1063X_ISP_RW00_DENOISE_EN |
> > +			    OV1063X_ISP_RW00_WHITE_DPC_EN |
> > +			    OV1063X_ISP_RW00_BLACK_DPC_EN |
> > +			    OV1063X_ISP_RW00_AWB_STATS_EN |
> > +			    OV1063X_ISP_RW00_AWB_GAIN_EN |
> > +			    OV1063X_ISP_RW00_LSC_EN },
> > +	{ OV1063X_ISP_RW01, OV1063X_ISP_RW01_DATA_WEIGHT_SYNC_EN |
> > +			    OV1063X_ISP_RW01_DARK_LEVEL_FILTER_EN |
> > +			    OV1063X_ISP_RW01_BUFFER_CONTROL_EN |
> > +			    OV1063X_ISP_RW01_AEC_EN |
> > +			    OV1063X_ISP_RW01_TONE_MAPPING_EN |
> > +			    OV1063X_ISP_RW01_NORMALIZE_EN |
> > +			    OV1063X_ISP_RW01_LONG_SHORT_COMB_EN },
> > +	{ OV1063X_ISP_RW02, 0xf0 |
> > +			    OV1063X_ISP_RW02_DIGITAL_GAIN_EN |
> > +			    OV1063X_ISP_RW02_WINDOW_BORDER_CUT_EN |
> > +			    OV1063X_ISP_RW02_DITHERING_EN },
> > +	{ OV1063X_ISP_CTRL3D, 0 },
> > +	{ OV1063X_AEC_TARGET_NUM, OV1063X_AEC_TARGET_NUM_AA_MODE },
> > +	{ OV1063X_AEC_LS_SENS_RATIO, 1024 },
> > +	{ OV1063X_AEC_NONWDR_EN, 0 },
> > +	{ OV1063X_AEC_NONWDR_SWITCH, 0 },
> > +	{ OV1063X_AEC_FIXED_RATIO_EN, 0 },
> > +	{ OV1063X_AEC_GP_MODE_EN, 0 },
> > +	{ OV1063X_AEC_NIGHT_MODE_EN, 0 },
> > +	{ OV1063X_AEC_NIGHT_MODE_CTRL, 0 },
> > +	{ OV1063X_AEC_NONLINEAR_GAIN_EN, 0 },
> > +	{ OV1063X_AEC_MANU_GAMMA_EN, 0 },
> > +	{ OV1063X_AEC_HOLD_BAND_EN, 0 },
> > +	{ OV1063X_AEC_BAND_FILTER_FLAG, OV1063X_AEC_BAND_FILTER_FLAG_0HZ },
> > +	{ OV1063X_AEC_BAND_FILTER_EN, 0 },
> > +	{ OV1063X_AEC_BAND_FILTER_SHORT, 0 },
> > +	{ OV1063X_AEC_LESS_1BAND_EN, 1 },
> > +	{ OV1063X_AEC_LESS_1BAND_SHORT, 1 },
> > +	{ OV1063X_AEC_LOG_TARGET(0), 0x8800 },
> > +	{ OV1063X_AEC_LOG_TARGET(1), 0x8a00 },
> > +	{ OV1063X_AEC_LOG_TARGET(2), 0x8600 },
> > +	{ OV1063X_AEC_TARGET_LONG(0), 0x40 },
> > +	{ OV1063X_AEC_TARGET_LONG(1), 0x50 },
> > +	{ OV1063X_AEC_TARGET_LONG(2), 0x30 },
> > +	{ OV1063X_AEC_TARGET_SHORT(0), 0x28 },
> > +	{ OV1063X_AEC_TARGET_SHORT(1), 0x60 },
> > +	{ OV1063X_AEC_TARGET_SHORT(2), 0x40 },
> > +	{ OV1063X_AEC_MAX_SHORT_LE, 0x01380000 },
> > +	{ OV1063X_AEC_MAX_GAIN_LONG, 255 },
> > +	{ OV1063X_AEC_MAX_GAIN_SHORT, 64 },
> > +	{ OV1063X_AEC_MIN_GAIN_LONG, 24 },
> > +	{ OV1063X_AEC_MIN_GAIN_SHORT, 24 },
> > +	{ OV1063X_AEC_MAX_EXP_LONG, 11904 },
> > +	{ OV1063X_AEC_MAX_EXP_SHORT, 11904 },
> > +	{ OV1063X_AEC_MIN_EXP_LONG, 4 },
> > +	{ OV1063X_AEC_MIN_EXP_SHORT, 4 },
> > +	{ OV1063X_AEC_FIXED_RATIO, 0x07 },
> > +	{ OV1063X_AEC_GP_MODE_RATIO_B2A, 0x20 },
> > +	{ OV1063X_AEC_GP_MODE_RATIO_C2A, 0x08 },
> > +	{ OV1063X_AEC_MIN_GAMMA_LIST(0), 512 },
> > +	{ OV1063X_AEC_MIN_GAMMA_LIST(1), 512 },
> > +	{ OV1063X_AEC_MIN_GAMMA_LIST(2), 512 },
> > +	{ OV1063X_AEC_MAX_GAMMA_LIST(0), 308 },
> > +	{ OV1063X_AEC_MAX_GAMMA_LIST(1), 1024 },
> > +	{ OV1063X_AEC_MAX_GAMMA_LIST(2), 1536 },
> > +	{ OV1063X_AEC_DR_LIST(0), 16 },
> > +	{ OV1063X_AEC_DR_LIST(1), 64 },
> > +	{ OV1063X_AEC_DR_LIST(2), 128 },
> > +	{ OV1063X_AEC_BAND_VALUE_60HZ, 3328 },
> > +	{ OV1063X_AEC_BAND_VALUE_50HZ, 4032 },
> > +	{ OV1063X_REG_8BIT(0xc4b4), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc4b5), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc4b6), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc4b7), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc4b8), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc4b9), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc4ba), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc4bb), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc4be), 0x02 },
> > +	{ OV1063X_REG_8BIT(0xc4bf), 0x33 },
> > +	{ OV1063X_REG_8BIT(0xc4c8), 0x03 },
> > +	{ OV1063X_REG_8BIT(0xc4c9), 0xd0 },
> > +	{ OV1063X_REG_8BIT(0xc4ca), 0x0e },
> > +	{ OV1063X_REG_8BIT(0xc4cb), 0x00 },
> > +	{ OV1063X_AWB_SIMPLE_MIN_NUM, 3665 },
> > +	{ OV1063X_AWB_CT_MIN_NUM, 3665 },
> > +	{ OV1063X_REG_8BIT(0xc4d0), 0x04 },
> > +	{ OV1063X_REG_8BIT(0xc4d1), 0x80 },
> > +	{ OV1063X_REG_8BIT(0xc4e0), 0x04 },
> > +	{ OV1063X_REG_8BIT(0xc4e1), 0x02 },
> > +	{ OV1063X_REG_8BIT(0xc4e2), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc4e4), 0x10 },
> > +	{ OV1063X_REG_8BIT(0xc4e5), 0x20 },
> > +	{ OV1063X_REG_8BIT(0xc4e6), 0x30 },
> > +	{ OV1063X_REG_8BIT(0xc4e7), 0x40 },
> > +	{ OV1063X_REG_8BIT(0xc4e8), 0x50 },
> > +	{ OV1063X_REG_8BIT(0xc4e9), 0x60 },
> > +	{ OV1063X_REG_8BIT(0xc4ea), 0x70 },
> > +	{ OV1063X_REG_8BIT(0xc4eb), 0x80 },
> > +	{ OV1063X_REG_8BIT(0xc4ec), 0x90 },
> > +	{ OV1063X_REG_8BIT(0xc4ed), 0xa0 },
> > +	{ OV1063X_REG_8BIT(0xc4ee), 0xb0 },
> > +	{ OV1063X_REG_8BIT(0xc4ef), 0xc0 },
> > +	{ OV1063X_REG_8BIT(0xc4f0), 0xd0 },
> > +	{ OV1063X_REG_8BIT(0xc4f1), 0xe0 },
> > +	{ OV1063X_REG_8BIT(0xc4f2), 0xf0 },
> > +	{ OV1063X_REG_8BIT(0xc4f3), 0x80 },
> > +	{ OV1063X_REG_8BIT(0xc4f4), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc4f5), 0x20 },
> > +	{ OV1063X_REG_8BIT(0xc4f6), 0x02 },
> > +	{ OV1063X_REG_8BIT(0xc4f7), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc4f8), 0x04 },
> > +	{ OV1063X_REG_8BIT(0xc4f9), 0x0b },
> > +	{ OV1063X_REG_8BIT(0xc4fa), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc4fb), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc4fc), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc4fd), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc4fe), 0x04 },
> > +	{ OV1063X_REG_8BIT(0xc4ff), 0x02 },
> > +	{ OV1063X_REG_8BIT(0xc500), 0x68 },
> > +	{ OV1063X_REG_8BIT(0xc501), 0x74 },
> > +	{ OV1063X_REG_8BIT(0xc502), 0x70 },
> > +	{ OV1063X_REG_8BIT(0xc503), 0x80 },
> > +	{ OV1063X_REG_8BIT(0xc504), 0x05 },
> > +	{ OV1063X_REG_8BIT(0xc505), 0x80 },
> > +	{ OV1063X_REG_8BIT(0xc506), 0x03 },
> > +	{ OV1063X_REG_8BIT(0xc507), 0x80 },
> > +	{ OV1063X_REG_8BIT(0xc508), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc509), 0xc0 },
> > +	{ OV1063X_REG_8BIT(0xc50a), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc50b), 0xa0 },
> > +	{ OV1063X_REG_8BIT(0xc50c), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc50d), 0x2c },
> > +	{ OV1063X_REG_8BIT(0xc50e), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc50f), 0x0a },
> > +	{ OV1063X_REG_8BIT(0xc510), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc511), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc512), 0xe5 },
> > +	{ OV1063X_REG_8BIT(0xc513), 0x14 },
> > +	{ OV1063X_REG_8BIT(0xc514), 0x04 },
> > +	{ OV1063X_REG_8BIT(0xc515), 0x00 },
> > +	{ OV1063X_VTS_ADDR, 840 },
> > +	{ OV1063X_HTS_ADDR, 1904 },
> > +	{ OV1063X_REG_8BIT(0xc2e0), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc2e1), 0x51 },
> > +	{ OV1063X_REG_8BIT(0xc2e2), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc2e3), 0xd6 },
> > +	{ OV1063X_REG_8BIT(0xc2e4), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc2e5), 0x5e },
> > +	{ OV1063X_REG_8BIT(0xc2e9), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc2ea), 0x7a },
> > +	{ OV1063X_REG_8BIT(0xc2eb), 0x90 },
> > +	{ OV1063X_REG_8BIT(0xc2ed), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc2ee), 0x7a },
> > +	{ OV1063X_REG_8BIT(0xc2ef), 0x64 },
> > +	{ OV1063X_REG_8BIT(0xc308), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc309), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc30a), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc30c), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc30d), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc30e), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc30f), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc310), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc311), 0x60 },
> > +	{ OV1063X_REG_8BIT(0xc312), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc313), 0x08 },
> > +	{ OV1063X_REG_8BIT(0xc314), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc315), 0x7f },
> > +	{ OV1063X_REG_8BIT(0xc316), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc317), 0x0b },
> > +	{ OV1063X_REG_8BIT(0xc318), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc319), 0x0c },
> > +	{ OV1063X_REG_8BIT(0xc31a), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc31b), 0xe0 },
> > +	{ OV1063X_REG_8BIT(0xc31c), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc31d), 0x14 },
> > +	{ OV1063X_REG_8BIT(0xc31e), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc31f), 0xc5 },
> > +	{ OV1063X_REG_8BIT(0xc320), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc321), 0x4b },
> > +	{ OV1063X_REG_8BIT(0xc322), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc323), 0xf0 },
> > +	{ OV1063X_REG_8BIT(0xc324), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc325), 0xe8 },
> > +	{ OV1063X_REG_8BIT(0xc326), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc327), 0x46 },
> > +	{ OV1063X_REG_8BIT(0xc328), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc329), 0xd2 },
> > +	{ OV1063X_REG_8BIT(0xc32a), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc32b), 0xe4 },
> > +	{ OV1063X_REG_8BIT(0xc32c), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc32d), 0xbb },
> > +	{ OV1063X_REG_8BIT(0xc32e), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc32f), 0x61 },
> > +	{ OV1063X_REG_8BIT(0xc330), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc331), 0xf9 },
> > +	{ OV1063X_REG_8BIT(0xc332), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc333), 0xd9 },
> > +	{ OV1063X_REG_8BIT(0xc334), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc335), 0x2e },
> > +	{ OV1063X_REG_8BIT(0xc336), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc337), 0xb1 },
> > +	{ OV1063X_REG_8BIT(0xc338), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc339), 0x64 },
> > +	{ OV1063X_REG_8BIT(0xc33a), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc33b), 0xeb },
> > +	{ OV1063X_REG_8BIT(0xc33c), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc33d), 0xe8 },
> > +	{ OV1063X_REG_8BIT(0xc33e), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc33f), 0x48 },
> > +	{ OV1063X_REG_8BIT(0xc340), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc341), 0xd0 },
> > +	{ OV1063X_REG_8BIT(0xc342), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc343), 0xed },
> > +	{ OV1063X_REG_8BIT(0xc344), 0xff },
> > +	{ OV1063X_REG_8BIT(0xc345), 0xad },
> > +	{ OV1063X_REG_8BIT(0xc346), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc347), 0x66 },
> > +	{ OV1063X_REG_8BIT(0xc348), 0x01 },
> > +	{ OV1063X_REG_8BIT(0xc349), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x6700), 0x04 },
> > +	{ OV1063X_REG_8BIT(0x6701), 0x7b },
> > +	{ OV1063X_REG_8BIT(0x6702), 0xfd },
> > +	{ OV1063X_REG_8BIT(0x6703), 0xf9 },
> > +	{ OV1063X_REG_8BIT(0x6704), 0x3d },
> > +	{ OV1063X_REG_8BIT(0x6705), 0x71 },
> > +	{ OV1063X_TPM_CTRL0, 0x70 | OV1063X_TPM_CTRL0_CLK_DIV(1) },
> > +	{ OV1063X_REG_8BIT(0x6708), 0x05 },
> > +	{ OV1063X_REG_8BIT(0x3822), 0x50 },
> > +	{ OV1063X_PARI_ADDR_MIN, 0x6f00 },
> > +	{ OV1063X_PARI_ADDR_MAX, 0x6f00 },
> > +	{ OV1063X_GROUP_WRITER_COMMAND, OV1063X_GROUP_WRITER_COMMAND_EN },
> > +};
> > +
> > +static const struct ov1063x_reg ov1063x_regs_bt656[] = {
> > +	{ OV1063X_DVP_MOD_SEL, OV1063X_DVP_MOD_SEL_CCIR_656 },
> > +	{ OV1063X_FORMAT_YMAX, 1016 },
> > +	{ OV1063X_FORMAT_YMIN, 8 },
> > +	{ OV1063X_FORMAT_UMAX, 1016 },
> > +	{ OV1063X_FORMAT_UMIN, 8 },
> > +};
> > +
> > +static const struct ov1063x_reg ov1063x_regs_bt656_10bit[] = {
> > +	{ OV1063X_DVP_MOD_SEL, OV1063X_DVP_MOD_SEL_CCIR_656 },
> > +	{ OV1063X_FORMAT_YMAX, 1022 },
> > +	{ OV1063X_FORMAT_YMIN, 2 },
> > +	{ OV1063X_FORMAT_UMAX, 1022 },
> > +	{ OV1063X_FORMAT_UMIN, 2 },
> > +};
> > +
> > +static const struct ov1063x_reg ov1063x_regs_vert_no_sub[] = {
> > +	{ OV1063X_TIMING_CTRL1C, 0 },
> > +	{ OV1063X_VSTART_OFFSET, 12 },
> > +	{ OV1063X_START_LINE, 4 },
> > +	{ OV1063X_LINE_NUM, 8 },
> > +	{ OV1063X_BLC_AVG_CTRL1, 0x20 },
> > +	{ OV1063X_BLC_AVG_CTRL2, 0x22 },
> > +	{ OV1063X_REG_8BIT(0x6e47), 0x0c },
> > +	{ OV1063X_REG_8BIT(0x4610), 0x05 },
> > +	{ OV1063X_REG_8BIT(0x4613), 0x10 },
> > +};
> > +
> > +static const struct ov1063x_reg ov1063x_regs_vert_sub2[] = {
> > +	{ OV1063X_TIMING_CTRL1C, OV1063X_TIMING_CTRL1C_VSUB2 },
> > +	{ OV1063X_VSTART_OFFSET, 6 },
> > +	{ OV1063X_START_LINE, 2 },
> > +	{ OV1063X_LINE_NUM, 2 },
> > +	{ OV1063X_BLC_AVG_CTRL1, 0x10 },
> > +	{ OV1063X_BLC_AVG_CTRL2, 0x11 },
> > +	{ OV1063X_REG_8BIT(0x6e47), 0x06 },
> > +	{ OV1063X_REG_8BIT(0x4610), 0x03 },
> > +	{ OV1063X_REG_8BIT(0x4613), 0x0a },
> > +};
> > +
> > +/*
> > + * Datasheet highlight the following sequence to enable and disable
> > + * Test Pattern mode i.e. colobar
> > + */
> > +static const struct ov1063x_reg ov1063x_regs_colorbar_enable[] = {
> > +	{ OV1063X_GAIN_AWB_CTRL32, OV1063X_GAIN_AWB_CTRL32_MANUAL_EN },
> > +	{ OV1063X_AEC_CTRLD0, OV1063X_AEC_CTRLD0_R_MAN_EN(1) },
> > +	{ OV1063X_REG_8BIT(0x5300), 0x01 }, { OV1063X_REG_8BIT(0x5301), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5302), 0x00 }, { OV1063X_REG_8BIT(0x5303), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5304), 0x00 }, { OV1063X_REG_8BIT(0x5305), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5306), 0x00 }, { OV1063X_REG_8BIT(0x5307), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5308), 0x01 }, { OV1063X_REG_8BIT(0x5309), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x530a), 0x00 }, { OV1063X_REG_8BIT(0x530b), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x530c), 0x00 }, { OV1063X_REG_8BIT(0x530d), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x530e), 0x00 }, { OV1063X_REG_8BIT(0x530f), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5310), 0x01 }, { OV1063X_REG_8BIT(0x5311), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5312), 0x00 }, { OV1063X_REG_8BIT(0x5313), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5314), 0x01 }, { OV1063X_REG_8BIT(0x5315), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5316), 0x00 }, { OV1063X_REG_8BIT(0x5317), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5318), 0x00 }, { OV1063X_REG_8BIT(0x5319), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x531a), 0x00 }, { OV1063X_REG_8BIT(0x531b), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x531c), 0x01 }, { OV1063X_REG_8BIT(0x531d), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x531e), 0x00 }, { OV1063X_REG_8BIT(0x531f), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5320), 0x00 }, { OV1063X_REG_8BIT(0x5321), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5322), 0x00 }, { OV1063X_REG_8BIT(0x5323), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5324), 0x01 }, { OV1063X_REG_8BIT(0x5325), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5326), 0x00 }, { OV1063X_REG_8BIT(0x5327), 0x00 },
> > +	{ OV1063X_REG_8BIT(0xc2ea), 0x80 }, { OV1063X_REG_8BIT(0xc2eb), 0x80 },
> > +	{ OV1063X_ISP_RW00, OV1063X_ISP_RW00_COLOR_INTERP_EN |
> > +			    OV1063X_ISP_RW00_DENOISE_EN |
> > +			    OV1063X_ISP_RW00_WHITE_DPC_EN |
> > +			    OV1063X_ISP_RW00_BLACK_DPC_EN |
> > +			    OV1063X_ISP_RW00_LSC_EN },
> > +};
> > +
> > +static const struct ov1063x_reg ov1063x_regs_colorbar_disable[] = {
> > +	{ OV1063X_ISP_CTRL3D, 0 },
> > +	{ OV1063X_ISP_CTRL3E, 0 },
> > +	{ OV1063X_GAIN_AWB_CTRL32, 0 },
> > +	{ OV1063X_AEC_CTRLD0, OV1063X_AEC_CTRLD0_R_MAN_EN(0) },
> > +	{ OV1063X_REG_8BIT(0x5300), 0x01 }, { OV1063X_REG_8BIT(0x5301), 0x00 },
> > +	{ OV1063X_REG_8BIT(0x5302), 0x00 }, { OV1063X_REG_8BIT(0x5303), 0x0e },
> > +	{ OV1063X_REG_8BIT(0x5304), 0x00 }, { OV1063X_REG_8BIT(0x5305), 0x0e },
> > +	{ OV1063X_REG_8BIT(0x5306), 0x00 }, { OV1063X_REG_8BIT(0x5307), 0x36 },
> > +	{ OV1063X_REG_8BIT(0x5308), 0x00 }, { OV1063X_REG_8BIT(0x5309), 0xd9 },
> > +	{ OV1063X_REG_8BIT(0x530a), 0x00 }, { OV1063X_REG_8BIT(0x530b), 0x0f },
> > +	{ OV1063X_REG_8BIT(0x530c), 0x00 }, { OV1063X_REG_8BIT(0x530d), 0x2c },
> > +	{ OV1063X_REG_8BIT(0x530e), 0x00 }, { OV1063X_REG_8BIT(0x530f), 0x59 },
> > +	{ OV1063X_REG_8BIT(0x5310), 0x00 }, { OV1063X_REG_8BIT(0x5311), 0x7b },
> > +	{ OV1063X_REG_8BIT(0x5312), 0x00 }, { OV1063X_REG_8BIT(0x5313), 0x22 },
> > +	{ OV1063X_REG_8BIT(0x5314), 0x00 }, { OV1063X_REG_8BIT(0x5315), 0xd5 },
> > +	{ OV1063X_REG_8BIT(0x5316), 0x00 }, { OV1063X_REG_8BIT(0x5317), 0x13 },
> > +	{ OV1063X_REG_8BIT(0x5318), 0x00 }, { OV1063X_REG_8BIT(0x5319), 0x18 },
> > +	{ OV1063X_REG_8BIT(0x531a), 0x00 }, { OV1063X_REG_8BIT(0x531b), 0x26 },
> > +	{ OV1063X_REG_8BIT(0x531c), 0x00 }, { OV1063X_REG_8BIT(0x531d), 0xdc },
> > +	{ OV1063X_REG_8BIT(0x531e), 0x00 }, { OV1063X_REG_8BIT(0x531f), 0x02 },
> > +	{ OV1063X_REG_8BIT(0x5320), 0x00 }, { OV1063X_REG_8BIT(0x5321), 0x24 },
> > +	{ OV1063X_REG_8BIT(0x5322), 0x00 }, { OV1063X_REG_8BIT(0x5323), 0x56 },
> > +	{ OV1063X_REG_8BIT(0x5324), 0x00 }, { OV1063X_REG_8BIT(0x5325), 0x85 },
> > +	{ OV1063X_REG_8BIT(0x5326), 0x00 }, { OV1063X_REG_8BIT(0x5327), 0x20 },
> > +	{ OV1063X_REG_8BIT(0xc2ea), 0x7a }, { OV1063X_REG_8BIT(0xc2eb), 0x90 },
> > +	{ OV1063X_ISP_RW00, OV1063X_ISP_RW00_COLOR_MATRIX_EN |
> > +			    OV1063X_ISP_RW00_COLOR_INTERP_EN |
> > +			    OV1063X_ISP_RW00_DENOISE_EN |
> > +			    OV1063X_ISP_RW00_WHITE_DPC_EN |
> > +			    OV1063X_ISP_RW00_BLACK_DPC_EN |
> > +			    OV1063X_ISP_RW00_AWB_STATS_EN |
> > +			    OV1063X_ISP_RW00_AWB_GAIN_EN |
> > +			    OV1063X_ISP_RW00_LSC_EN },
> > +};
Tomi Valkeinen Jan. 12, 2021, 1:32 p.m. UTC | #6
Hi Laurent,

On 04/01/2021 07:39, Laurent Pinchart wrote:
> Add a new V4L2 subdev driver for the OmniVision OV10633 and OV10635
> camera sensors. The work is based on the driver from the TI BSP, itself
> based on original work by Phil Edworthy posted to the linux-media
> mailing list ([1]). This version of the code is a large rewrite of many
> parts.
> 
> [1] http://www.spinics.net/lists/linux-media/msg64347.html
> 
> Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
> Signed-off-by: Benoit Parrot <bparrot@ti.com>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---

<snip>

> +static int ov1063x_remove(struct i2c_client *client)
> +{
> +	struct ov1063x_priv *priv = i2c_get_clientdata(client);

This should be

	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct ov1063x_priv *priv = to_ov1063x(sd);

Let me guess, you never tried as a module? ;)

 Tomi
Laurent Pinchart Jan. 14, 2021, 5:32 a.m. UTC | #7
Hi Tomi,

On Tue, Jan 12, 2021 at 03:32:30PM +0200, Tomi Valkeinen wrote:
> On 04/01/2021 07:39, Laurent Pinchart wrote:
> > Add a new V4L2 subdev driver for the OmniVision OV10633 and OV10635
> > camera sensors. The work is based on the driver from the TI BSP, itself
> > based on original work by Phil Edworthy posted to the linux-media
> > mailing list ([1]). This version of the code is a large rewrite of many
> > parts.
> > 
> > [1] http://www.spinics.net/lists/linux-media/msg64347.html
> > 
> > Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
> > Signed-off-by: Benoit Parrot <bparrot@ti.com>
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> 
> <snip>
> 
> > +static int ov1063x_remove(struct i2c_client *client)
> > +{
> > +	struct ov1063x_priv *priv = i2c_get_clientdata(client);
> 
> This should be
> 
> 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> 	struct ov1063x_priv *priv = to_ov1063x(sd);
> 
> Let me guess, you never tried as a module? ;)

I don't know what you're talking about, I load the driver as a module.
The trick is to never unload it ;-)
Tomi Valkeinen Jan. 18, 2021, 2:04 p.m. UTC | #8
Hi Laurent,

On 04/01/2021 07:39, Laurent Pinchart wrote:

> +static int ov1063x_pll_setup(unsigned int clk_rate,
> +			     unsigned int *htsmin, unsigned int vts,
> +			     unsigned int fps_numerator,
> +			     unsigned int fps_denominator,
> +			     struct ov1063x_pll_config *cfg)
> +{
> +	static const unsigned int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
> +
> +	unsigned int best_pclk = UINT_MAX;
> +	unsigned int best_pre_div;
> +	unsigned int best_mult;
> +	unsigned int best_div;
> +	unsigned int best_hts;
> +	unsigned int max_pre_div;
> +	unsigned int pre_div;
> +	unsigned int hts;
> +
> +	/*
> +	 *  XVCLK --> pre-div -------> mult ----------> div --> output
> +	 * 6-27 MHz           3-27 MHz      200-500 MHz       Max 96 MHz
> +	 *
> +	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7. The
> +	 * pre_divs array stores the pre-dividers multiplied by two, indexed by
> +	 * register values.
> +	 *
> +	 * Valid multiplier values are [1, 63], stored as-is in registers.
> +	 *
> +	 * Valid divider values are 2 to 16 with a step of 2, stored in
> +	 * registers as (div / 2) - 1.
> +	 */
> +
> +	if (clk_rate < 6 * 1000 * 1000 || clk_rate > 27 * 1000 * 1000)
> +		return -EINVAL;
> +
> +	/*
> +	 * We try all valid combinations of settings for the 3 blocks to get
> +	 * the pixel clock, and from that calculate the actual hts/vts to use.
> +	 * The vts is extended so as to achieve the required frame rate.
> +	 */
> +
> +	max_pre_div = max(clk_rate / (3 * 1000 * 1000),
> +			  ARRAY_SIZE(pre_divs) - 1);
> +
> +	for (pre_div = 0; pre_div <= max_pre_div; pre_div++) {
> +		unsigned int clk1 = clk_rate * 2 / pre_divs[pre_div];
> +		unsigned int min_mult;
> +		unsigned int max_mult;
> +		unsigned int mult;

This PLL setup is a bit confusing to understand, because:

- "pre_div" is not the divider value, but an index to the pre_divs array
and a value to be written into the register, and pre_div is also stored
into the pll_cfg.

- "div" _is_ the divider value but it's not stored into the pll_cfg,
instead (div / 2) - 1 is stored there.

And calculating max_pre_div is probably not right above, I think it
should be min(), and additionally "clk_rate / (3 * 1000 * 1000)" is
calculating the divider value, not the index, but it's then used as a
max to the index loop... And even if it were the index, it should be -1,
as the loop check uses <=.

Suggestions:

- Redefine the PLL formula. Instead of having fractional pre_divider (I
wonder if it's actually fractional in the HW... Aren't dividers usually
integer dividers?), redefine the formula as pclk = xvclk * 2 / pre_div *
mul / div, and say that the possible pre_dividers are what's currently
in pre_divs array. Or pclk = xvclk / pre_div * 2 * mul / div, which
gives a different result with integer divisions. I don't know which one
is the correct one (or is it either of those... If the HW handles
fractionals, both are wrong).

- Clearly separate divider value and index/regvalue variables. The
iteration loop should use the plain divider values, and I think it would
be best to store the values as such to pll_config. And map the divider
values to register values only when writing to the register.

 Tomi
Laurent Pinchart Jan. 20, 2021, 8:26 a.m. UTC | #9
Hi Tomi,

On Mon, Jan 18, 2021 at 04:04:47PM +0200, Tomi Valkeinen wrote:
> On 04/01/2021 07:39, Laurent Pinchart wrote:
> 
> > +static int ov1063x_pll_setup(unsigned int clk_rate,
> > +			     unsigned int *htsmin, unsigned int vts,
> > +			     unsigned int fps_numerator,
> > +			     unsigned int fps_denominator,
> > +			     struct ov1063x_pll_config *cfg)
> > +{
> > +	static const unsigned int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
> > +
> > +	unsigned int best_pclk = UINT_MAX;
> > +	unsigned int best_pre_div;
> > +	unsigned int best_mult;
> > +	unsigned int best_div;
> > +	unsigned int best_hts;
> > +	unsigned int max_pre_div;
> > +	unsigned int pre_div;
> > +	unsigned int hts;
> > +
> > +	/*
> > +	 *  XVCLK --> pre-div -------> mult ----------> div --> output
> > +	 * 6-27 MHz           3-27 MHz      200-500 MHz       Max 96 MHz
> > +	 *
> > +	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7. The
> > +	 * pre_divs array stores the pre-dividers multiplied by two, indexed by
> > +	 * register values.
> > +	 *
> > +	 * Valid multiplier values are [1, 63], stored as-is in registers.
> > +	 *
> > +	 * Valid divider values are 2 to 16 with a step of 2, stored in
> > +	 * registers as (div / 2) - 1.
> > +	 */
> > +
> > +	if (clk_rate < 6 * 1000 * 1000 || clk_rate > 27 * 1000 * 1000)
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * We try all valid combinations of settings for the 3 blocks to get
> > +	 * the pixel clock, and from that calculate the actual hts/vts to use.
> > +	 * The vts is extended so as to achieve the required frame rate.
> > +	 */
> > +
> > +	max_pre_div = max(clk_rate / (3 * 1000 * 1000),
> > +			  ARRAY_SIZE(pre_divs) - 1);
> > +
> > +	for (pre_div = 0; pre_div <= max_pre_div; pre_div++) {
> > +		unsigned int clk1 = clk_rate * 2 / pre_divs[pre_div];
> > +		unsigned int min_mult;
> > +		unsigned int max_mult;
> > +		unsigned int mult;
> 
> This PLL setup is a bit confusing to understand, because:
> 
> - "pre_div" is not the divider value, but an index to the pre_divs array
> and a value to be written into the register, and pre_div is also stored
> into the pll_cfg.

Correct.

> - "div" _is_ the divider value but it's not stored into the pll_cfg,
> instead (div / 2) - 1 is stored there.

Correct too. cfg->div stores the register value.

> And calculating max_pre_div is probably not right above, I think it
> should be min(),

Indeed. Good catch, I'll fix that.

> and additionally "clk_rate / (3 * 1000 * 1000)" is
> calculating the divider value, not the index, but it's then used as a
> max to the index loop... And even if it were the index, it should be -1,
> as the loop check uses <=.

Those are real issues too, I'll address them.

> Suggestions:
> 
> - Redefine the PLL formula. Instead of having fractional pre_divider (I
> wonder if it's actually fractional in the HW... Aren't dividers usually
> integer dividers?), redefine the formula as pclk = xvclk * 2 / pre_div *
> mul / div, and say that the possible pre_dividers are what's currently
> in pre_divs array. Or pclk = xvclk / pre_div * 2 * mul / div, which
> gives a different result with integer divisions. I don't know which one
> is the correct one (or is it either of those... If the HW handles
> fractionals, both are wrong).
> 
> - Clearly separate divider value and index/regvalue variables. The
> iteration loop should use the plain divider values, and I think it would
> be best to store the values as such to pll_config. And map the divider
> values to register values only when writing to the register.

I'd agree if it wasn't for the pre-div value. Storing the pre-div value
in pll_config would make it more complicated to calculate the register
value in the caller. And mixing register values and multiplier/divider
values in the structure isn't nice :-S That's why I've stored register
values only in pll_config.

How about this ?

commit b2356f1b87576a540ca99fbcd2ad2f0b81c494b7
Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Date:   Wed Jan 20 10:25:43 2021 +0200

    media: i2c: ov1063x: Fix PLL calculation

    Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

diff --git a/drivers/media/i2c/ov1063x.c b/drivers/media/i2c/ov1063x.c
index cfd852b3eb2f..cd8d6bba3d70 100644
--- a/drivers/media/i2c/ov1063x.c
+++ b/drivers/media/i2c/ov1063x.c
@@ -642,24 +642,21 @@ static int ov1063x_pll_setup(unsigned int clk_rate,
 			     unsigned int fps_denominator,
 			     struct ov1063x_pll_config *cfg)
 {
-	static const unsigned int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
-
 	unsigned int best_pclk = UINT_MAX;
-	unsigned int best_pre_div;
+	unsigned int best_pre_div_x2;
 	unsigned int best_mult;
 	unsigned int best_div;
 	unsigned int best_hts;
-	unsigned int max_pre_div;
-	unsigned int pre_div;
+	unsigned int max_pre_div_x2;
+	unsigned int pre_div_x2;
 	unsigned int hts;
 
 	/*
 	 *  XVCLK --> pre-div -------> mult ----------> div --> output
 	 * 6-27 MHz           3-27 MHz      200-500 MHz       Max 96 MHz
 	 *
-	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7. The
-	 * pre_divs array stores the pre-dividers multiplied by two, indexed by
-	 * register values.
+	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7, stored in
+	 * registers as the index in this list of values.
 	 *
 	 * Valid multiplier values are [1, 63], stored as-is in registers.
 	 *
@@ -676,11 +673,15 @@ static int ov1063x_pll_setup(unsigned int clk_rate,
 	 * The vts is extended so as to achieve the required frame rate.
 	 */
 
-	max_pre_div = max(clk_rate / (3 * 1000 * 1000),
-			  ARRAY_SIZE(pre_divs) - 1);
+	/*
+	 * The pre_div_x2 variable stores the pre-div value multiplied by 2, to
+	 * support the fractional divider 1.5.
+	 */
+	max_pre_div_x2 = min(clk_rate * 2 / (3 * 1000 * 1000), 14U);
 
-	for (pre_div = 0; pre_div <= max_pre_div; pre_div++) {
-		unsigned int clk1 = clk_rate * 2 / pre_divs[pre_div];
+	for (pre_div_x2 = 2; pre_div_x2 <= max_pre_div_x2;
+	     pre_div_x2 += (pre_div_x2 < 4 ? 1 : 2)) {
+		unsigned int clk1 = clk_rate * 2 / pre_div_x2;
 		unsigned int min_mult;
 		unsigned int max_mult;
 		unsigned int mult;
@@ -720,7 +721,7 @@ static int ov1063x_pll_setup(unsigned int clk_rate,
 				if (pclk < best_pclk) {
 					best_pclk = pclk;
 					best_hts = hts;
-					best_pre_div = pre_div;
+					best_pre_div_x2 = pre_div_x2;
 					best_mult = mult;
 					best_div = div;
 				}
@@ -731,8 +732,10 @@ static int ov1063x_pll_setup(unsigned int clk_rate,
 	if (best_pclk == UINT_MAX)
 		return -EINVAL;
 
+	/* Store the mult, pre_div and div as register values. */
 	cfg->mult = best_mult;
-	cfg->pre_div = best_pre_div;
+	cfg->pre_div = best_pre_div_x2 < 4 ? best_pre_div_x2 - 2
+		     : best_pre_div_x2 / 2;
 	cfg->div = (best_div / 2) - 1;
 	cfg->clk_out = best_pclk;
Tomi Valkeinen Jan. 20, 2021, 11:52 a.m. UTC | #10
Hi,

On 20/01/2021 10:26, Laurent Pinchart wrote:
> Hi Tomi,
> 
> On Mon, Jan 18, 2021 at 04:04:47PM +0200, Tomi Valkeinen wrote:
>> On 04/01/2021 07:39, Laurent Pinchart wrote:
>>
>>> +static int ov1063x_pll_setup(unsigned int clk_rate,
>>> +			     unsigned int *htsmin, unsigned int vts,
>>> +			     unsigned int fps_numerator,
>>> +			     unsigned int fps_denominator,
>>> +			     struct ov1063x_pll_config *cfg)
>>> +{
>>> +	static const unsigned int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
>>> +
>>> +	unsigned int best_pclk = UINT_MAX;
>>> +	unsigned int best_pre_div;
>>> +	unsigned int best_mult;
>>> +	unsigned int best_div;
>>> +	unsigned int best_hts;
>>> +	unsigned int max_pre_div;
>>> +	unsigned int pre_div;
>>> +	unsigned int hts;
>>> +
>>> +	/*
>>> +	 *  XVCLK --> pre-div -------> mult ----------> div --> output
>>> +	 * 6-27 MHz           3-27 MHz      200-500 MHz       Max 96 MHz
>>> +	 *
>>> +	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7. The
>>> +	 * pre_divs array stores the pre-dividers multiplied by two, indexed by
>>> +	 * register values.
>>> +	 *
>>> +	 * Valid multiplier values are [1, 63], stored as-is in registers.
>>> +	 *
>>> +	 * Valid divider values are 2 to 16 with a step of 2, stored in
>>> +	 * registers as (div / 2) - 1.
>>> +	 */
>>> +
>>> +	if (clk_rate < 6 * 1000 * 1000 || clk_rate > 27 * 1000 * 1000)
>>> +		return -EINVAL;
>>> +
>>> +	/*
>>> +	 * We try all valid combinations of settings for the 3 blocks to get
>>> +	 * the pixel clock, and from that calculate the actual hts/vts to use.
>>> +	 * The vts is extended so as to achieve the required frame rate.
>>> +	 */
>>> +
>>> +	max_pre_div = max(clk_rate / (3 * 1000 * 1000),
>>> +			  ARRAY_SIZE(pre_divs) - 1);
>>> +
>>> +	for (pre_div = 0; pre_div <= max_pre_div; pre_div++) {
>>> +		unsigned int clk1 = clk_rate * 2 / pre_divs[pre_div];
>>> +		unsigned int min_mult;
>>> +		unsigned int max_mult;
>>> +		unsigned int mult;
>>
>> This PLL setup is a bit confusing to understand, because:
>>
>> - "pre_div" is not the divider value, but an index to the pre_divs array
>> and a value to be written into the register, and pre_div is also stored
>> into the pll_cfg.
> 
> Correct.
> 
>> - "div" _is_ the divider value but it's not stored into the pll_cfg,
>> instead (div / 2) - 1 is stored there.
> 
> Correct too. cfg->div stores the register value.
> 
>> And calculating max_pre_div is probably not right above, I think it
>> should be min(),
> 
> Indeed. Good catch, I'll fix that.
> 
>> and additionally "clk_rate / (3 * 1000 * 1000)" is
>> calculating the divider value, not the index, but it's then used as a
>> max to the index loop... And even if it were the index, it should be -1,
>> as the loop check uses <=.
> 
> Those are real issues too, I'll address them.
> 
>> Suggestions:
>>
>> - Redefine the PLL formula. Instead of having fractional pre_divider (I
>> wonder if it's actually fractional in the HW... Aren't dividers usually
>> integer dividers?), redefine the formula as pclk = xvclk * 2 / pre_div *
>> mul / div, and say that the possible pre_dividers are what's currently
>> in pre_divs array. Or pclk = xvclk / pre_div * 2 * mul / div, which
>> gives a different result with integer divisions. I don't know which one
>> is the correct one (or is it either of those... If the HW handles
>> fractionals, both are wrong).
>>
>> - Clearly separate divider value and index/regvalue variables. The
>> iteration loop should use the plain divider values, and I think it would
>> be best to store the values as such to pll_config. And map the divider
>> values to register values only when writing to the register.
> 
> I'd agree if it wasn't for the pre-div value. Storing the pre-div value
> in pll_config would make it more complicated to calculate the register
> value in the caller. And mixing register values and multiplier/divider
> values in the structure isn't nice :-S That's why I've stored register
> values only in pll_config.

Yes, I wouldn't mix them. But why is pre-div complicating it? Isn't all
that's needed a table with prediv values, which you already have? A
simple lookup to that table will give the needed register value.

> How about this ?
> 
> commit b2356f1b87576a540ca99fbcd2ad2f0b81c494b7
> Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Date:   Wed Jan 20 10:25:43 2021 +0200
> 
>     media: i2c: ov1063x: Fix PLL calculation
> 
>     Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> diff --git a/drivers/media/i2c/ov1063x.c b/drivers/media/i2c/ov1063x.c
> index cfd852b3eb2f..cd8d6bba3d70 100644
> --- a/drivers/media/i2c/ov1063x.c
> +++ b/drivers/media/i2c/ov1063x.c
> @@ -642,24 +642,21 @@ static int ov1063x_pll_setup(unsigned int clk_rate,
>  			     unsigned int fps_denominator,
>  			     struct ov1063x_pll_config *cfg)
>  {
> -	static const unsigned int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
> -
>  	unsigned int best_pclk = UINT_MAX;
> -	unsigned int best_pre_div;
> +	unsigned int best_pre_div_x2;
>  	unsigned int best_mult;
>  	unsigned int best_div;
>  	unsigned int best_hts;
> -	unsigned int max_pre_div;
> -	unsigned int pre_div;
> +	unsigned int max_pre_div_x2;
> +	unsigned int pre_div_x2;
>  	unsigned int hts;
>  
>  	/*
>  	 *  XVCLK --> pre-div -------> mult ----------> div --> output
>  	 * 6-27 MHz           3-27 MHz      200-500 MHz       Max 96 MHz
>  	 *
> -	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7. The
> -	 * pre_divs array stores the pre-dividers multiplied by two, indexed by
> -	 * register values.
> +	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7, stored in
> +	 * registers as the index in this list of values.
>  	 *
>  	 * Valid multiplier values are [1, 63], stored as-is in registers.
>  	 *
> @@ -676,11 +673,15 @@ static int ov1063x_pll_setup(unsigned int clk_rate,
>  	 * The vts is extended so as to achieve the required frame rate.
>  	 */
>  
> -	max_pre_div = max(clk_rate / (3 * 1000 * 1000),
> -			  ARRAY_SIZE(pre_divs) - 1);
> +	/*
> +	 * The pre_div_x2 variable stores the pre-div value multiplied by 2, to
> +	 * support the fractional divider 1.5.
> +	 */
> +	max_pre_div_x2 = min(clk_rate * 2 / (3 * 1000 * 1000), 14U);
>  
> -	for (pre_div = 0; pre_div <= max_pre_div; pre_div++) {
> -		unsigned int clk1 = clk_rate * 2 / pre_divs[pre_div];
> +	for (pre_div_x2 = 2; pre_div_x2 <= max_pre_div_x2;
> +	     pre_div_x2 += (pre_div_x2 < 4 ? 1 : 2)) {
> +		unsigned int clk1 = clk_rate * 2 / pre_div_x2;
>  		unsigned int min_mult;
>  		unsigned int max_mult;
>  		unsigned int mult;
> @@ -720,7 +721,7 @@ static int ov1063x_pll_setup(unsigned int clk_rate,
>  				if (pclk < best_pclk) {
>  					best_pclk = pclk;
>  					best_hts = hts;
> -					best_pre_div = pre_div;
> +					best_pre_div_x2 = pre_div_x2;
>  					best_mult = mult;
>  					best_div = div;
>  				}
> @@ -731,8 +732,10 @@ static int ov1063x_pll_setup(unsigned int clk_rate,
>  	if (best_pclk == UINT_MAX)
>  		return -EINVAL;
>  
> +	/* Store the mult, pre_div and div as register values. */
>  	cfg->mult = best_mult;
> -	cfg->pre_div = best_pre_div;
> +	cfg->pre_div = best_pre_div_x2 < 4 ? best_pre_div_x2 - 2
> +		     : best_pre_div_x2 / 2;
>  	cfg->div = (best_div / 2) - 1;
>  	cfg->clk_out = best_pclk;

Works for me and looks relatively clean, so I'm ok with this fix.

 Tomi
Tomi Valkeinen Feb. 8, 2021, 2:18 p.m. UTC | #11
Hi Laurent,

On 04/01/2021 07:39, Laurent Pinchart wrote:
> Add a new V4L2 subdev driver for the OmniVision OV10633 and OV10635
> camera sensors. The work is based on the driver from the TI BSP, itself
> based on original work by Phil Edworthy posted to the linux-media
> mailing list ([1]). This version of the code is a large rewrite of many
> parts.

<snip>

> +static int ov1063x_tpg_setup(struct ov1063x_priv *priv, struct v4l2_ctrl *ctrl)
> +{
> +	const struct ov1063x_tpg_config *cfg;
> +	int ret = 0;
> +
> +	if (!ctrl->val)
> +		return ov1063x_write_array(priv, ov1063x_regs_colorbar_disable,
> +					   ARRAY_SIZE(ov1063x_regs_colorbar_disable));
> +
> +	if (!ctrl->cur.val) {
> +		/*
> +		 * Only write the full settings when the test pattern was
> +		 * disabled, not when we're just changing the test pattern type.
> +		 */
> +		ret = ov1063x_write_array(priv, ov1063x_regs_colorbar_enable,
> +					  ARRAY_SIZE(ov1063x_regs_colorbar_enable));
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	cfg = &ov1063x_tpg_configs[ctrl->val - 1];
> +
> +	/* TODO: Add support for the moving bar overlay. */
> +	ov1063x_write(priv, OV1063X_ISP_CTRL3D, cfg->ctrl3d, &ret);
> +	ov1063x_write(priv, OV1063X_ISP_CTRL3E, cfg->ctrl3e, &ret);
> +
> +	return ret;
> +}

I didn't go through the code in detail, but looks like the color bar
settings from ov1063x_regs_colorbar_enable are lost if capture is
stopped and started again. The color bar itself stays, but it's
distorted due to all the ISP processing being done.

 Tomi
Laurent Pinchart Dec. 6, 2021, 10:23 p.m. UTC | #12
Hi Sakari,

I realize I've never replied to your e-mail.

On Mon, Jan 04, 2021 at 01:41:15PM +0200, Sakari Ailus wrote:
> On Mon, Jan 04, 2021 at 07:39:45AM +0200, Laurent Pinchart wrote:
> > Add a new V4L2 subdev driver for the OmniVision OV10633 and OV10635
> > camera sensors. The work is based on the driver from the TI BSP, itself
> > based on original work by Phil Edworthy posted to the linux-media
> > mailing list ([1]). This version of the code is a large rewrite of many
> > parts.
> 
> The driver seems generally quite nice. It doesn't check known-good link
> frequencies are not defined in bindings nor checked by the driver. Could
> you add them?

That won't work easily with the existing PLL configuration code, and I'm
afraid I don't have enough information about the hardware to fix it.
Please see below.

> Same or the assigned-clock-rates in bindings.
> 
> Please see more comments below.
>
> > [1] http://www.spinics.net/lists/linux-media/msg64347.html
> > 
> > Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
> > Signed-off-by: Benoit Parrot <bparrot@ti.com>
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  MAINTAINERS                      |    2 +
> >  drivers/media/i2c/Kconfig        |   12 +
> >  drivers/media/i2c/Makefile       |    1 +
> >  drivers/media/i2c/ov1063x.c      | 1692 ++++++++++++++++++++++++++++++
> >  drivers/media/i2c/ov1063x_regs.h |  626 +++++++++++
> >  5 files changed, 2333 insertions(+)
> >  create mode 100644 drivers/media/i2c/ov1063x.c
> >  create mode 100644 drivers/media/i2c/ov1063x_regs.h

[snip]

> > diff --git a/drivers/media/i2c/ov1063x.c b/drivers/media/i2c/ov1063x.c
> > new file mode 100644
> > index 000000000000..5b25ed5e766b
> > --- /dev/null
> > +++ b/drivers/media/i2c/ov1063x.c
> > @@ -0,0 +1,1692 @@

[snip]

> > +struct ov1063x_pll_config {
> > +	unsigned int pre_div;
> > +	unsigned int mult;
> > +	unsigned int div;
> > +	unsigned int clk_out;
> > +};
> > +
> > +static int ov1063x_pll_setup(unsigned int clk_rate,
> > +			     unsigned int *htsmin, unsigned int vts,
> > +			     unsigned int fps_numerator,
> > +			     unsigned int fps_denominator,
> > +			     struct ov1063x_pll_config *cfg)
> > +{
> > +	static const unsigned int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
> > +
> > +	unsigned int best_pclk = UINT_MAX;
> > +	unsigned int best_pre_div;
> > +	unsigned int best_mult;
> > +	unsigned int best_div;
> > +	unsigned int best_hts;
> > +	unsigned int max_pre_div;
> > +	unsigned int pre_div;
> > +	unsigned int hts;
> > +
> > +	/*
> > +	 *  XVCLK --> pre-div -------> mult ----------> div --> output
> > +	 * 6-27 MHz           3-27 MHz      200-500 MHz       Max 96 MHz
> > +	 *
> > +	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7. The
> > +	 * pre_divs array stores the pre-dividers multiplied by two, indexed by
> > +	 * register values.
> > +	 *
> > +	 * Valid multiplier values are [1, 63], stored as-is in registers.
> > +	 *
> > +	 * Valid divider values are 2 to 16 with a step of 2, stored in
> > +	 * registers as (div / 2) - 1.
> > +	 */
> > +
> > +	if (clk_rate < 6 * 1000 * 1000 || clk_rate > 27 * 1000 * 1000)
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * We try all valid combinations of settings for the 3 blocks to get
> > +	 * the pixel clock, and from that calculate the actual hts/vts to use.
> > +	 * The vts is extended so as to achieve the required frame rate.
> > +	 */
> > +
> > +	max_pre_div = max(clk_rate / (3 * 1000 * 1000),
> > +			  ARRAY_SIZE(pre_divs) - 1);
> > +
> > +	for (pre_div = 0; pre_div <= max_pre_div; pre_div++) {
> > +		unsigned int clk1 = clk_rate * 2 / pre_divs[pre_div];
> > +		unsigned int min_mult;
> > +		unsigned int max_mult;
> > +		unsigned int mult;
> > +
> > +		if (clk1 < 3 * 1000 * 1000 || clk1 > 27 * 1000 * 1000)
> > +			continue;
> > +
> > +		min_mult = DIV_ROUND_UP(200 * 1000 * 1000, clk1);
> > +		max_mult = min(500 * 1000 * 1000 / clk1, 63U);
> > +
> > +		for (mult = min_mult; mult <= max_mult; mult++) {
> > +			unsigned int clk2 = clk1 * mult;
> > +			unsigned int min_div;
> > +			unsigned int div;
> > +
> > +			min_div = DIV_ROUND_UP(clk2, 96 * 1000 * 1000);
> > +			min_div = round_up(min_div, 2);
> > +
> > +			for (div = min_div; div <= 16; div += 2) {
> > +				unsigned int pclk = clk2 / div;
> > +				unsigned int min_pclk;
> > +
> > +				/*
> > +				 * TODO: HTS calculation should ideally be split
> > +				 * from the PLL calculations. This requires
> > +				 * figuring out where the pclk / 300000 comes
> > +				 * from.
> > +				 */
> > +				hts = *htsmin + pclk / (300*1000);
> > +
> > +				/* 2 clock cycles for every YUV422 pixel. */
> > +				min_pclk = hts * vts / fps_denominator
> > +					 * fps_numerator * 2;
> > +				if (pclk < min_pclk)
> > +					continue;
> > +
> > +				if (pclk < best_pclk) {
> > +					best_pclk = pclk;
> > +					best_hts = hts;
> > +					best_pre_div = pre_div;
> > +					best_mult = mult;
> > +					best_div = div;
> 
> Can the requested frame rate exceed the highest possible rate here?
> 
> You already control the sensor's PLL and other capabilities such as
> analogue cropping directly. You could make these all configurable from the
> user space the same way the ccs driver does. What do you think?

HTS and VTS should be configurable by userspace, and so should the link
frequency (and possibly even the input clock frequency, indirectly at
least).

I however don't have enough documentation to implement this. I've
reworked this driver from a BSP kernel, with access to some
documentation, but the constraints on HTS and VTS are not documented.
The above TODO comment explains part of the issue. This is the best I
can do for new I believe.

> > +				}
> > +			}
> > +		}
> > +	}
> > +
> > +	if (best_pclk == UINT_MAX)
> > +		return -EINVAL;
> > +
> > +	cfg->mult = best_mult;
> > +	cfg->pre_div = best_pre_div;
> > +	cfg->div = (best_div / 2) - 1;
> > +	cfg->clk_out = best_pclk;
> > +
> > +	*htsmin = best_hts;
> > +
> > +	return 0;
> > +}

[snip]

> > +static int ov1063x_set_fmt(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_pad_config *cfg,
> > +			   struct v4l2_subdev_format *fmt)
> > +{
> > +	struct ov1063x_priv *priv = to_ov1063x(sd);
> > +	struct v4l2_mbus_framefmt *format;
> > +	const struct v4l2_area *fsize;
> > +	unsigned int i;
> > +	u32 code;
> > +	int ret = 0;
> > +
> > +	/*
> > +	 * Validate the media bus code, defaulting to the first one if the
> > +	 * requested code isn't supported.
> > +	 */
> > +	for (i = 0; i < ARRAY_SIZE(ov1063x_mbus_formats); ++i) {
> > +		if (ov1063x_mbus_formats[i] == fmt->format.code) {
> > +			code = fmt->format.code;
> > +			break;
> > +		}
> > +	}
> > +
> > +	if (i == ARRAY_SIZE(ov1063x_mbus_formats))
> > +		code = ov1063x_mbus_formats[0];
> 
> You could do this assignment unconditionally in variable initialisation.

I could, but I think it would be more confusing than the current code
pattern, which expresses "try to find format, and if failed, default to
[0]".

> > +
> > +	/* Find the nearest supported frame size. */
> > +	fsize = v4l2_find_nearest_size(ov1063x_framesizes,
> > +				       ARRAY_SIZE(ov1063x_framesizes),
> > +				       width, height, fmt->format.width,
> > +				       fmt->format.height);
> > +
> > +	/* Update the stored format and return it. */
> > +	format = __ov1063x_get_pad_format(priv, cfg, fmt->pad, fmt->which);
> > +
> > +	mutex_lock(priv->hdl.lock);
> > +
> > +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming) {
> > +		ret = -EBUSY;
> > +		goto done;
> > +	}
> > +
> > +	format->code = code;
> > +	format->width = fsize->width;
> > +	format->height = fsize->height;
> > +
> > +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > +		unsigned int hsub;
> > +		unsigned int vsub;
> > +
> > +		/*
> > +		 * Enable horizontal or vertical sub-sampling automatically when
> > +		 * the width or height are smaller than half the maximum
> > +		 * resolution.
> > +		 */
> > +		hsub = format->width <= 640 ? 2 : 1;
> > +		vsub = format->height <= 400 ? 2 : 1;
> > +
> > +		/*
> > +		 * The analog horizontal crop is restricted to the full sensor
> > +		 * width (1312 pixels), 768 or 656 pixels. Additional cropping
> > +		 * will be applied in the digital domain.
> > +		 */
> > +		priv->analog_crop.width = format->width * hsub;
> > +		priv->analog_crop.height = format->height * vsub;
> > +
> > +		if (priv->analog_crop.width > 768)
> > +			priv->analog_crop.width = OV1063X_SENSOR_WIDTH;
> > +		else if (priv->analog_crop.width > 656)
> > +			priv->analog_crop.width = 768;
> > +		else
> > +			priv->analog_crop.width = 656;
> > +
> > +		/*
> > +		 * The digital crop is applied at the ISP input, before
> > +		 * horizontal sub-sampling but after vertical sub-sampling as
> > +		 * the latter is applied in the pixel array.
> > +		 */
> > +		priv->digital_crop.width = format->width * hsub;
> > +		priv->digital_crop.height = format->height;
> > +
> > +		/*
> > +		 * Center the crop rectangles, rounding coordinates to a
> > +		 * multiple of 2 to avoid changing the Bayer pattern.
> > +		 */
> > +		priv->analog_crop.left = ((OV1063X_SENSOR_WIDTH -
> > +					   priv->analog_crop.width) / 2) & ~1;
> > +		priv->analog_crop.top = ((OV1063X_SENSOR_HEIGHT -
> > +					  priv->analog_crop.height) / 2) & ~1;
> > +		priv->digital_crop.left = ((priv->analog_crop.width -
> > +					    priv->digital_crop.width) / 2) & ~1;
> > +		priv->analog_crop.top = 0;
> > +	}
> > +
> > +	fmt->format = *format;
> > +
> > +done:
> > +	mutex_unlock(priv->hdl.lock);
> > +
> > +	return ret;
> > +}

[snip]
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 9dc3a7d75460..4b94061130cf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12873,6 +12873,8 @@  L:	linux-media@vger.kernel.org
 S:	Maintained
 T:	git git://linuxtv.org/media_tree.git
 F:	Documentation/devicetree/bindings/media/i2c/ov1063x.yaml
+F:	drivers/media/i2c/ov1063x.c
+F:	drivers/media/i2c/ov1063x_regs.h
 
 OMNIVISION OV13858 SENSOR DRIVER
 M:	Sakari Ailus <sakari.ailus@linux.intel.com>
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 878f66ef2719..84a97989775e 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -1050,6 +1050,18 @@  config VIDEO_OV9650
 	  This is a V4L2 sensor driver for the Omnivision
 	  OV9650 and OV9652 camera sensors.
 
+config VIDEO_OV10633
+	tristate "OmniVision OV10633/OV10635 sensor support"
+	depends on I2C && VIDEO_V4L2
+	depends on GPIOLIB && OF
+	select MEDIA_CONTROLLER
+	select REGMAP_I2C
+	select V4L2_FWNODE
+	select VIDEO_V4L2_SUBDEV_API
+	help
+	  This is a Video4Linux2 driver for the OmniVision
+	  OV10633 and OV10635 camera sensors.
+
 config VIDEO_OV13858
 	tristate "OmniVision OV13858 sensor support"
 	depends on I2C && VIDEO_V4L2
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index f0a77473979d..6eef97e2423d 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -83,6 +83,7 @@  obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
 obj-$(CONFIG_VIDEO_OV8856) += ov8856.o
 obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
 obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
+obj-$(CONFIG_VIDEO_OV10633) += ov1063x.o
 obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
 obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
 obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
diff --git a/drivers/media/i2c/ov1063x.c b/drivers/media/i2c/ov1063x.c
new file mode 100644
index 000000000000..5b25ed5e766b
--- /dev/null
+++ b/drivers/media/i2c/ov1063x.c
@@ -0,0 +1,1692 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OmniVision OV10633/OV10635 Camera Driver
+ *
+ * Based on the original driver written by Phil Edworthy.
+ * Copyright (C) 2013 Phil Edworthy
+ * Copyright (C) 2013 Renesas Electronics
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2020 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+/* Register definitions */
+#define OV1063X_REG_8BIT(n)			((1 << 16) | (n))
+#define OV1063X_REG_16BIT(n)			((2 << 16) | (n))
+#define OV1063X_REG_24BIT(n)			((3 << 16) | (n))
+#define OV1063X_REG_32BIT(n)			((4 << 16) | (n))
+#define OV1063X_REG_SIZE_SHIFT			16
+#define OV1063X_REG_ADDR_MASK			0xffff
+
+#define OV1063X_STREAM_MODE			OV1063X_REG_8BIT(0x0100)
+#define OV1063X_STREAM_MODE_ON			BIT(0)
+#define OV1063X_SOFTWARE_RESET			OV1063X_REG_8BIT(0x0103)
+
+#define OV1063X_SC_CMMN_PLL_CTRL0		OV1063X_REG_8BIT(0x3003)
+#define OV1063X_SC_CMMN_PLL_SCLK_CP(n)		((n) << 6)
+#define OV1063X_SC_CMMN_PLL_SCLK_MULTI(n)	((n) << 0)
+#define OV1063X_SC_CMMN_PLL_CTRL1		OV1063X_REG_8BIT(0x3004)
+#define OV1063X_SC_CMMN_PLL_SCLK_BYPASS		BIT(7)
+#define OV1063X_SC_CMMN_PLL_SCLK_PRE_DIV(n)	((n) << 4)	/* /1, /1.5, /2, /3, /4, /5, /6, /7 */
+#define OV1063X_SC_CMMN_PLL_SCLK_CP2(n)		((n) << 3)
+#define OV1063X_SC_CMMN_PLL_SCLK_DIV(n)		((n) << 0)	/* Divider = 2 * (1 + n) */
+#define OV1063X_SC_CMMN_PLL_CTRL2		OV1063X_REG_8BIT(0x3005)
+#define OV1063X_SC_CMMN_PLL_PCLK_CP(n)		((n) << 6)
+#define OV1063X_SC_CMMN_PLL_PCLK_MULTI(n)	((n) << 0)
+#define OV1063X_SC_CMMN_PLL_CTRL3		OV1063X_REG_8BIT(0x3006)
+#define OV1063X_SC_CMMN_PLL_PCLK_BYPASS		BIT(7)
+#define OV1063X_SC_CMMN_PLL_PCLK_PRE_DIV(n)	((n) << 4)	/* /1, /1.5, /2, /3, /4, /5, /6, /7 */
+#define OV1063X_SC_CMMN_PLL_PCLK_CP2(n)		((n) << 3)
+#define OV1063X_SC_CMMN_PLL_PCLK_DIV(n)		((n) << 0)	/* Divider = 2 * (1 + n) */
+#define OV1063X_SC_CMMN_PCLK_DIV_CTRL		OV1063X_REG_8BIT(0x3007)
+#define OV1063X_PID				OV1063X_REG_16BIT(0x300a)
+#define OV1063X_SC_CMMN_SCCB_ID			OV1063X_REG_8BIT(0x300c)
+#define OV1063X_SC_CMMN_SCCB_ID_ADDR(n)		((n) << 1)
+#define OV1063X_SC_CMMN_SCCB_ID_SEL		BIT(0)
+#define OV1063X_SC_CMMN_PAD			OV1063X_REG_8BIT(0x3011)
+#define OV1063X_SC_CMMN_PAD_DRIVE(n)		((n) << 6)
+#define OV1063X_SC_CMMN_CLKRST0			OV1063X_REG_8BIT(0x301a)
+#define OV1063X_SC_CMMN_CLKRST0_SCLK		GENMASK(7, 4)
+#define OV1063X_SC_CMMN_CLKRST0_RST		GENMASK(3, 0)
+#define OV1063X_SC_CMMN_CLKRST1			OV1063X_REG_8BIT(0x301b)
+#define OV1063X_SC_CMMN_CLKRST1_SCLK		GENMASK(7, 4)
+#define OV1063X_SC_CMMN_CLKRST1_RST		GENMASK(3, 0)
+#define OV1063X_SC_CMMN_CLKRST2			OV1063X_REG_8BIT(0x301c)
+#define OV1063X_SC_CMMN_CLKRST2_PCLK_DVP	BIT(7)
+#define OV1063X_SC_CMMN_CLKRST2_SCLK		GENMASK(6, 4)
+#define OV1063X_SC_CMMN_CLKRST2_RST_DVP		BIT(3)
+#define OV1063X_SC_CMMN_CLKRST2_RST		GENMASK(2, 0)
+#define OV1063X_SC_CMMN_CLOCK_SEL		OV1063X_REG_8BIT(0x3020)
+#define OV1063X_SC_CMMN_MISC_CTRL		OV1063X_REG_8BIT(0x3021)
+#define OV1063X_SC_CMMN_MISC_CTRL_PCLK_INV	BIT(7)
+#define OV1063X_SC_CMMN_MISC_CTRL_SCLK_INV	BIT(6)
+#define OV1063X_SC_CMMN_MISC_CTRL_SCLK2X_INV	BIT(5)
+#define OV1063X_SC_CMMN_MISC_CTRL_CEN_GLOBAL_O	BIT(0)
+#define OV1063X_SC_CMMN_CORE_CTRL_1		OV1063X_REG_8BIT(0x3022)
+#define OV1063X_SC_CMMN_CORE_CTRL_2		OV1063X_REG_8BIT(0x3023)
+#define OV1063X_SC_CMMN_CORE_CTRL_BIST_EN	BIT(5)
+#define OV1063X_SC_CMMN_CORE_CTRL_CLK_SWITCH	BIT(4)
+#define OV1063X_SC_CMMN_CORE_CTRL_3		OV1063X_REG_8BIT(0x3024)
+#define OV1063X_SC_CMMN_CORE_CTRL_RAW_LONG	(0U << 4)
+#define OV1063X_SC_CMMN_CORE_CTRL_RAW_SHORT	(1U << 4)
+#define OV1063X_SC_CMMN_CORE_CTRL_RAW_LONG_SHORT	(2U << 4)
+#define OV1063X_SC_CMMN_CORE_CTRL_RAW_COMBINED	(0U << 4)
+#define OV1063X_SC_CMMN_CORE_CTRL_YUV_LONG	(1U << 1)
+#define OV1063X_SC_CMMN_CORE_CTRL_YUV_SHORT	(2U << 1)
+#define OV1063X_SC_CMMN_CORE_CTRL_PCLK_SYS	(0U << 0)	/* PCLK from system PLL */
+#define OV1063X_SC_CMMN_CORE_CTRL_PCLK_SEC	(1U << 0)	/* PCLK from secondary PLL */
+#define OV1063X_SC_CMMN_CORE_CTRL1		OV1063X_REG_8BIT(0x3025)
+#define OV1063X_SC_CMMN_PWDN_CTRL2		OV1063X_REG_8BIT(0x302d)
+#define OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG1	BIT(3)
+#define OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG2	BIT(2)
+#define OV1063X_SC_CMMN_PWDN_CTRL2_RST_ISP	BIT(1)
+#define OV1063X_SC_CMMN_PWDN_CTRL2_SEQUENCE	BIT(0)
+#define OV1063X_SC_CMMN_SCLK2X_SEL		OV1063X_REG_8BIT(0x3033)
+#define OV1063X_SC_CMMN_SCLK2X_SEL_DIV2		(1U << 2)
+#define OV1063X_SC_CMMN_SCLK2X_SEL_DIV4		(2U << 2)
+#define OV1063X_SC_SOC_CLKRST7			OV1063X_REG_8BIT(0x3042)
+#define OV1063X_SC_SOC_CLKRST7_SCLK		GENMASK(7, 4)
+#define OV1063X_SC_SOC_CLKRST7_RST		GENMASK(3, 0)
+
+#define OV1063X_AEC_PK_MANUAL			OV1063X_REG_8BIT(0x3503)
+#define OV1063X_AEC_PK_MANUAL_GAIN_DELAY	BIT(5)
+#define OV1063X_AEC_PK_MANUAL_DELAY		BIT(4)
+#define OV1063X_AEC_PK_MAN_DONE			OV1063X_REG_8BIT(0x3504)
+#define OV1063X_AEC_PK_MAN_DONE_AEC_DONE	BIT(0)
+
+#define OV1063X_ANA_ADC1			OV1063X_REG_8BIT(0x3600)
+#define OV1063X_ANA_ADC2			OV1063X_REG_8BIT(0x3601)
+#define OV1063X_ANA_ADC3			OV1063X_REG_8BIT(0x3602)
+#define OV1063X_ANA_ADC4			OV1063X_REG_8BIT(0x3603)
+#define OV1063X_ANA_ANALOG1			OV1063X_REG_8BIT(0x3610)
+#define OV1063X_ANA_ANALOG2			OV1063X_REG_8BIT(0x3611)
+#define OV1063X_ANA_ANALOG3			OV1063X_REG_8BIT(0x3612)
+#define OV1063X_ANA_ARRAY1			OV1063X_REG_8BIT(0x3621)
+#define OV1063X_ANA_ARRAY1_FULL			(0 << 3)
+#define OV1063X_ANA_ARRAY1_CROP_768		(1 << 3)
+#define OV1063X_ANA_ARRAY1_CROP_656		(2 << 3)
+#define OV1063X_ANA_ARRAY1_DELAY(n)		((n) << 0)
+#define OV1063X_ANA_PWC1			OV1063X_REG_8BIT(0x3630)
+#define OV1063X_ANA_PWC2			OV1063X_REG_8BIT(0x3631)
+#define OV1063X_ANA_PWC3			OV1063X_REG_8BIT(0x3632)
+#define OV1063X_ANA_PWC4			OV1063X_REG_8BIT(0x3633)
+
+#define OV1063X_SENSOR_RSTGOLOW			OV1063X_REG_8BIT(0x3702)
+#define OV1063X_SENSOR_HLDWIDTH			OV1063X_REG_8BIT(0x3703)
+#define OV1063X_SENSOR_TXWIDTH			OV1063X_REG_8BIT(0x3704)
+#define OV1063X_SENSOR_REG9			OV1063X_REG_8BIT(0x3709)
+#define OV1063X_SENSOR_REGD			OV1063X_REG_8BIT(0x370d)
+#define OV1063X_SENSOR_RSTYZ_GOLOW		OV1063X_REG_16BIT(0x3712)
+#define OV1063X_SENSOR_EQ_GOLOW			OV1063X_REG_8BIT(0x3714)
+#define OV1063X_SENSOR_REG15			OV1063X_REG_8BIT(0x3715)
+#define OV1063X_SENSOR_BITSW_GO			OV1063X_REG_16BIT(0x371c)
+
+#define OV1063X_TIMING_X_START_ADDR		OV1063X_REG_16BIT(0x3800)
+#define OV1063X_TIMING_Y_START_ADDR		OV1063X_REG_16BIT(0x3802)
+#define OV1063X_TIMING_X_END_ADDR		OV1063X_REG_16BIT(0x3804)
+#define OV1063X_TIMING_Y_END_ADDR		OV1063X_REG_16BIT(0x3806)
+#define OV1063X_TIMING_X_OUTPUT_SIZE		OV1063X_REG_16BIT(0x3808)
+#define OV1063X_TIMING_Y_OUTPUT_SIZE		OV1063X_REG_16BIT(0x380a)
+#define OV1063X_TIMING_HTS			OV1063X_REG_16BIT(0x380c)
+#define OV1063X_TIMING_VTS			OV1063X_REG_16BIT(0x380e)
+#define OV1063X_TIMING_ISP_X_WIN		OV1063X_REG_16BIT(0x3810)
+#define OV1063X_TIMING_ISP_Y_WIN		OV1063X_REG_16BIT(0x3812)
+#define OV1063X_TIMING_CTRL15			OV1063X_REG_8BIT(0x3815)
+#define OV1063X_TIMING_CTRL15_BLACK_LINE_HREF	BIT(7)
+#define OV1063X_TIMING_CTRL15_RIP_SOF		BIT(5)
+#define OV1063X_TIMING_CTRL15_BLACK_LINES(n)	((n) << 0)
+#define OV1063X_TIMING_CTRL1C			OV1063X_REG_8BIT(0x381c)
+#define OV1063X_TIMING_CTRL1C_VFLIP_DIG		BIT(7)
+#define OV1063X_TIMING_CTRL1C_VFLIP_ARRAY	BIT(6)
+#define OV1063X_TIMING_CTRL1C_VSUB4		BIT(1)
+#define OV1063X_TIMING_CTRL1C_VSUB2		BIT(0)
+#define OV1063X_TIMING_CTRL1D			OV1063X_REG_8BIT(0x381d)
+#define OV1063X_TIMING_CTRL1D_VFLIP_BLACK_LINE	BIT(7)
+#define OV1063X_TIMING_CTRL1D_WDR		BIT(6)
+#define OV1063X_TIMING_CTRL1D_HFLIP_DIG		BIT(1)
+#define OV1063X_TIMING_CTRL1D_HFLIP_ARRAY	BIT(0)
+#define OV1063X_VSTART_OFFSET			OV1063X_REG_16BIT(0x381e)
+
+#define OV1063X_START_LINE			OV1063X_REG_8BIT(0x4001)
+#define OV1063X_LINE_NUM			OV1063X_REG_8BIT(0x4004)	/* Black lines */
+#define OV1063X_BLC_CTRL05			OV1063X_REG_8BIT(0x4005)
+#define OV1063X_BLC_CTRL05_ONE_LINE_MODE	BIT(5)
+#define OV1063X_BLC_CTRL05_REMOVE_BLACK_LINE	BIT(4)
+#define OV1063X_BLC_CTRL05_ONE_MAN_OFFSET_MODE	BIT(3)
+#define OV1063X_BLC_CTRL05_BL_RBLUE_RVS		BIT(2)
+#define OV1063X_BLC_CTRL05_BLC_ALWAYS_DO	BIT(1)
+#define OV1063X_BLC_AVG_CTRL1			OV1063X_REG_8BIT(0x4050)
+#define OV1063X_BLC_AVG_CTRL2			OV1063X_REG_8BIT(0x4051)
+#define OV1063X_BLC_OFFSET_TOP_LIMIT		OV1063X_REG_16BIT(0x4056)
+#define OV1063X_BLC_OFFSET_BOT_LIMIT		OV1063X_REG_16BIT(0x4058)
+#define OV1063X_BLC_CTRL5A			OV1063X_REG_8BIT(0x405a)
+
+#define OV1063X_FC_R2				OV1063X_REG_8BIT(0x4202)
+
+#define OV1063X_FORMAT_CTRL00			OV1063X_REG_8BIT(0x4300)
+#define OV1063X_FORMAT_YUYV			0x38
+#define OV1063X_FORMAT_YYYU			0x39
+#define OV1063X_FORMAT_UYVY			0x3a
+#define OV1063X_FORMAT_VYUY			0x3b
+#define OV1063X_FORMAT_YMAX			OV1063X_REG_16BIT(0x4302)
+#define OV1063X_FORMAT_YMIN			OV1063X_REG_16BIT(0x4304)
+#define OV1063X_FORMAT_UMAX			OV1063X_REG_16BIT(0x4306)
+#define OV1063X_FORMAT_UMIN			OV1063X_REG_16BIT(0x4308)
+
+#define OV1063X_VFIFO_LLEN_FIRS1_SEL		OV1063X_REG_8BIT(0x4605)
+#define OV1063X_VFIFO_LLEN_FIRS1_SEL_8B_YUV	BIT(3)
+#define OV1063X_VFIFO_LINE_LENGTH_MAN		OV1063X_REG_16BIT(0x4606)
+#define OV1063X_VFIFO_READ_START		OV1063X_REG_16BIT(0x4608)
+#define OV1063X_VFIFO_HSYNC_START_POSITION	OV1063X_REG_16BIT(0x460a)
+#define OV1063X_VFIFO_HSYNC_CTRL		OV1063X_REG_8BIT(0x460c)
+#define OV1063X_VFIFO_HSYNC_CTRL_HEADER_WIDTH(n)	((n) << 4)
+#define OV1063X_VFIFO_HSYNC_CTRL_TRAILER_WIDTH(n)	((n) << 0)
+#define OV1063X_VFIFO_EMBD_LINE_CTRL		OV1063X_REG_8BIT(0x460e)
+#define OV1063X_VFIFO_EMBD_LINE_CTRL_SOF_CLR_RAM	BIT(3)
+#define OV1063X_VFIFO_EMBD_LINE_CTRL_ST_MOD	BIT(2)
+#define OV1063X_VFIFO_EMBD_LINE_CTRL_EMBD_ROM	BIT(1)
+#define OV1063X_VFIFO_EMBD_LINE_CTRL_EMBD_EN	BIT(0)
+#define OV1063X_VFIFO_EMBD_LINE_NUM		OV1063X_REG_8BIT(0x460f)
+#define OV1063X_ROI_CTRL0			OV1063X_REG_8BIT(0x4620)
+#define OV1063X_ROI_CTRL0_SYNC_BYP		BIT(7)
+#define OV1063X_ROI_CTRL0_FR_COMP		BIT(6)
+#define OV1063X_ROI_CTRL0_FULL_DAT_MOD		BIT(5)
+#define OV1063X_ROI_CTRL0_EN_3			BIT(3)
+#define OV1063X_ROI_CTRL0_EN_2			BIT(2)
+#define OV1063X_ROI_CTRL0_EN_1			BIT(1)
+#define OV1063X_ROI_CTRL0_FUNC_E		BIT(0)
+
+#define OV1063X_DVP_MOD_SEL			OV1063X_REG_8BIT(0x4700)
+#define OV1063X_DVP_MOD_SEL_CCIR_V		BIT(3)
+#define OV1063X_DVP_MOD_SEL_CCIR_F		BIT(2)
+#define OV1063X_DVP_MOD_SEL_CCIR_656		BIT(1)
+#define OV1063X_DVP_MOD_SEL_HSYNC		BIT(0)
+#define OV1063X_DVP_VSYNC_WIDTH			OV1063X_REG_8BIT(0x4701)
+#define OV1063X_DVP_HSYVSY_NEG_WIDTH		OV1063X_REG_16BIT(0x4702)
+#define OV1063X_DVP_VSYNC_MODE			OV1063X_REG_8BIT(0x4704)
+#define OV1063X_DVP_VSYNC_MODE_VSYNCOUT_SEL(n)	((n) << 2)
+#define OV1063X_DVP_VSYNC_MODE_VSYNC3_MOD	BIT(1)
+#define OV1063X_DVP_VSYNC_MODE_VSYNC2_MOD	BIT(0)
+#define OV1063X_DVP_EOF_VSYNC_DELAY		OV1063X_REG_24BIT(0x4705)
+
+#define OV1063X_ISP_RW00			OV1063X_REG_8BIT(0x5000)
+#define OV1063X_ISP_RW00_COLOR_MATRIX_EN	BIT(7)
+#define OV1063X_ISP_RW00_COLOR_INTERP_EN	BIT(6)
+#define OV1063X_ISP_RW00_DENOISE_EN		BIT(5)
+#define OV1063X_ISP_RW00_WHITE_DPC_EN		BIT(4)	/* White defect pixel correction enable */
+#define OV1063X_ISP_RW00_BLACK_DPC_EN		BIT(3)	/* Black defect pixel connection enable */
+#define OV1063X_ISP_RW00_AWB_STATS_EN		BIT(2)
+#define OV1063X_ISP_RW00_AWB_GAIN_EN		BIT(1)
+#define OV1063X_ISP_RW00_LSC_EN			BIT(0)
+#define OV1063X_ISP_RW01			OV1063X_REG_8BIT(0x5001)
+#define OV1063X_ISP_RW01_DATA_WEIGHT_SYNC_EN	BIT(7)
+#define OV1063X_ISP_RW01_BLACK_WHITE_MODE_EN	BIT(6)
+#define OV1063X_ISP_RW01_DARK_LEVEL_FILTER_EN	BIT(5)
+#define OV1063X_ISP_RW01_BUFFER_CONTROL_EN	BIT(4)
+#define OV1063X_ISP_RW01_AEC_EN			BIT(3)
+#define OV1063X_ISP_RW01_TONE_MAPPING_EN	BIT(2)
+#define OV1063X_ISP_RW01_NORMALIZE_EN		BIT(1)
+#define OV1063X_ISP_RW01_LONG_SHORT_COMB_EN	BIT(0)
+#define OV1063X_ISP_RW02			OV1063X_REG_8BIT(0x5002)
+#define OV1063X_ISP_RW02_DIGITAL_GAIN_EN	BIT(3)
+#define OV1063X_ISP_RW02_WINDOW_BORDER_CUT_EN	BIT(2)
+#define OV1063X_ISP_RW02_DITHERING_EN		BIT(1)
+#define OV1063X_ISP_RW02_LSLS			(0U << 0)
+#define OV1063X_ISP_RW02_SLSL			(1U << 0)
+#define OV1063X_ISP_RW05			OV1063X_REG_8BIT(0x5005)
+#define OV1063X_ISP_RW05_VERT_SUB_EN		BIT(7)	/* Enable vertical subsampling */
+#define OV1063X_ISP_RW05_LSC_CENTER_AUTO	BIT(6)	/* Set LSC center automatically based on image window */
+#define OV1063X_ISP_RW05_SUB_OUT_ROW_2ND	BIT(5)	/* Output 2nd (1) or 1st (0) row when skipping */
+#define OV1063X_ISP_RW05_SUB_OUT_COL_2ND	BIT(4)	/* Output 2nd (1) or 1st (0) column when skipping */
+#define OV1063X_ISP_RW05_SUB_AVG		BIT(3)	/* Average (1) or sum (0) when binning */
+#define OV1063X_ISP_RW05_SUB_G_DROP		BIT(2)	/* Skip (1) or bin (0) Green / Y */
+#define OV1063X_ISP_RW05_SUB_RB_DROP		BIT(1)	/* Skip (1) or bin (0) Red Blue / UV */
+#define OV1063X_ISP_RW05_SUB_ENABLE		BIT(0)	/* Enable sub-sampling */
+#define OV1063X_ISP_RW06			OV1063X_REG_8BIT(0x5006)
+#define OV1063X_ISP_RW06_RAW_MODE_MAN(n)	((n) << 6)
+#define OV1063X_ISP_RW06_YUV_MODE_MAN(n)	((n) << 4)
+#define OV1063X_ISP_RW06_RAW_MODE_MAN_EN	BIT(3)
+#define OV1063X_ISP_RW06_YUV_MODE_MAN_EN	BIT(2)
+#define OV1063X_ISP_CTRL3D			OV1063X_REG_8BIT(0x503d)
+#define OV1063X_ISP_CTRL3D_TEST_PATTERN_EN	BIT(7)
+#define OV1063X_ISP_CTRL3D_COLOR_BAR(n)		((n) << 4)
+#define OV1063X_ISP_CTRL3D_ROLLING_BAR_EN	BIT(2)
+#define OV1063X_ISP_CTRL3E			OV1063X_REG_8BIT(0x503e)
+#define OV1063X_ISP_CTRL3E_SQUARE_BW		BIT(3)
+#define OV1063X_ISP_CTRL3E_TRANSPARENT_EN	BIT(2)
+#define OV1063X_ISP_CTRL3E_PATTERN_BARS		(0U << 0)
+#define OV1063X_ISP_CTRL3E_PATTERN_RANDOM	(1U << 0)
+#define OV1063X_ISP_CTRL3E_PATTERN_SQUARES	(2U << 0)
+
+#define OV1063X_GAIN_AWB_MAN_GAIN_B_LONG	OV1063X_REG_16BIT(0x5100)
+#define OV1063X_GAIN_AWB_MAN_GAIN_GB_LONG	OV1063X_REG_16BIT(0x5102)
+#define OV1063X_GAIN_AWB_MAN_GAIN_GR_LONG	OV1063X_REG_16BIT(0x5104)
+#define OV1063X_GAIN_AWB_MAN_GAIN_R_LONG	OV1063X_REG_16BIT(0x5106)
+#define OV1063X_GAIN_AWB_MAN_OFFSET_B_LONG	OV1063X_REG_16BIT(0x5108)
+#define OV1063X_GAIN_AWB_MAN_OFFSET_GB_LONG	OV1063X_REG_16BIT(0x510a)
+#define OV1063X_GAIN_AWB_MAN_OFFSET_GR_LONG	OV1063X_REG_16BIT(0x510c)
+#define OV1063X_GAIN_AWB_MAN_OFFSET_R_LONG	OV1063X_REG_16BIT(0x510e)
+#define OV1063X_GAIN_AWB_MAN_GAIN_B_SHORT	OV1063X_REG_16BIT(0x5110)
+#define OV1063X_GAIN_AWB_MAN_GAIN_GB_SHORT	OV1063X_REG_16BIT(0x5112)
+#define OV1063X_GAIN_AWB_MAN_GAIN_GR_SHORT	OV1063X_REG_16BIT(0x5114)
+#define OV1063X_GAIN_AWB_MAN_GAIN_R_SHORT	OV1063X_REG_16BIT(0x5116)
+#define OV1063X_GAIN_AWB_MAN_OFFSET_B_SHORT	OV1063X_REG_16BIT(0x5118)
+#define OV1063X_GAIN_AWB_MAN_OFFSET_GB_SHORT	OV1063X_REG_16BIT(0x511a)
+#define OV1063X_GAIN_AWB_MAN_OFFSET_GR_SHORT	OV1063X_REG_16BIT(0x511c)
+#define OV1063X_GAIN_AWB_MAN_OFFSET_R_SHORT	OV1063X_REG_16BIT(0x511e)
+#define OV1063X_GAIN_AWB_CTRL32			OV1063X_REG_8BIT(0x5120)
+#define OV1063X_GAIN_AWB_CTRL32_MANUAL_EN	BIT(0)
+
+#define OV1063X_DNS_NOISE_Y_LIST_LONG(n)	OV1063X_REG_8BIT(0x521a + (n))
+#define OV1063X_DNS_NOISE_UV_LIST_LONG(n)	OV1063X_REG_16BIT(0x5222 + (n) * 2)
+#define OV1063X_DNS_GBGR_EXTRA_SHORT		OV1063X_REG_8BIT(0x5241)
+#define OV1063X_DNS_NOISE_Y_LIST_SHORT(n)	OV1063X_REG_8BIT(0x5242 + (n))
+#define OV1063X_DNS_NOISE_UV_LIST_SHORT(n)	OV1063X_REG_16BIT(0x5249 + (n) * 2)
+#define OV1063X_CIP_UNSHARPEN_MASK_LONG(n)	OV1063X_REG_8BIT(0x5288 + (n))
+#define OV1063X_CIP_MAX_SHARPEN_LONG		OV1063X_REG_8BIT(0x528d)
+#define OV1063X_CIP_SHARPEN_ALPHA_LONG		OV1063X_REG_8BIT(0x5293)
+#define OV1063X_CIP_UNSHARPEN_MASK_SHORT(n)	OV1063X_REG_8BIT(0x52c8 + (n))
+#define OV1063X_CIP_MAX_SHARPEN_SHORT		OV1063X_REG_8BIT(0x52cd)
+#define OV1063X_CIP_SHARPEN_ALPHA_SHORT		OV1063X_REG_8BIT(0x52d3)
+#define OV1063X_CIP_HFREQ_COEF_SHORT		OV1063X_REG_8BIT(0x52d7)
+
+#define OV1063X_LLF_MAX_LOW_LEVEL		OV1063X_REG_16BIT(0x5381)
+
+#define OV1063X_AWB_CT_CTRL1			OV1063X_REG_8BIT(0x5581)
+#define OV1063X_AWB_CT_CTRL1_GAIN_STEP_NORMAL(n)	((n) << 6)
+#define OV1063X_AWB_CT_CTRL1_GAIN_STEP_FAST(n)	((n) << 4)
+#define OV1063X_AWB_CT_CTRL1_SCALE_LONG_2X	(0 << 2)
+#define OV1063X_AWB_CT_CTRL1_SCALE_LONG_4X	(1 << 2)
+#define OV1063X_AWB_CT_CTRL1_SCALE_LONG_8X	(2 << 2)
+#define OV1063X_AWB_M_RNG_LONG			OV1063X_REG_8BIT(0x5586)
+#define OV1063X_AWB_L_XRNG_LONG			OV1063X_REG_8BIT(0x5587)
+#define OV1063X_AWB_H_YRNG_LONG			OV1063X_REG_8BIT(0x5588)
+#define OV1063X_AWB_M_X_LONG			OV1063X_REG_8BIT(0x5589)
+#define OV1063X_AWB_M_Y_LONG			OV1063X_REG_8BIT(0x558a)
+#define OV1063X_AWB_L_K_LONG			OV1063X_REG_8BIT(0x558b)
+#define OV1063X_AWB_H_K_LONG			OV1063X_REG_8BIT(0x558c)
+#define OV1063X_AWB_H_LMT_LONG			OV1063X_REG_8BIT(0x558d)
+#define OV1063X_AWB_L_LMT_LONG			OV1063X_REG_8BIT(0x558e)
+#define OV1063X_AWB_DATA_ULMT_LONG		OV1063X_REG_8BIT(0x5591)
+#define OV1063X_AWB_DATA_LLMT_LONG		OV1063X_REG_8BIT(0x5592)
+#define OV1063X_AWB_M_RNG_SHORT			OV1063X_REG_8BIT(0x559f)
+#define OV1063X_AWB_L_XRNG_SHORT		OV1063X_REG_8BIT(0x55a0)
+#define OV1063X_AWB_H_YRNG_SHORT		OV1063X_REG_8BIT(0x55a1)
+#define OV1063X_AWB_M_X_SHORT			OV1063X_REG_8BIT(0x55a2)
+#define OV1063X_AWB_M_Y_SHORT			OV1063X_REG_8BIT(0x55a3)
+#define OV1063X_AWB_L_K_SHORT			OV1063X_REG_8BIT(0x55a4)
+#define OV1063X_AWB_H_K_SHORT			OV1063X_REG_8BIT(0x55a5)
+#define OV1063X_AWB_H_LMT_SHORT			OV1063X_REG_8BIT(0x55a6)
+#define OV1063X_AWB_L_LMT_SHORT			OV1063X_REG_8BIT(0x55a7)
+#define OV1063X_AWB_DATA_ULMT_SHORT		OV1063X_REG_8BIT(0x55aa)
+#define OV1063X_AWB_DATA_LLMT_SHORT		OV1063X_REG_8BIT(0x55ab)
+
+#define OV1063X_AEC_CTRL07			OV1063X_REG_16BIT(0x5607)
+#define OV1063X_AEC_WIN_LEFT_LONG		OV1063X_REG_16BIT(0x5609)
+#define OV1063X_AEC_WIN_LEFT_SHORT		OV1063X_REG_16BIT(0x560b)
+#define OV1063X_AEC_WIN_TOP_LONG		OV1063X_REG_16BIT(0x560d)
+#define OV1063X_AEC_WIN_TOP_SHORT		OV1063X_REG_16BIT(0x560f)
+#define OV1063X_AEC_WIN_WIDTH_LONG		OV1063X_REG_16BIT(0x5611)
+#define OV1063X_AEC_WIN_WIDTH_SHORT		OV1063X_REG_16BIT(0x5613)
+#define OV1063X_AEC_WIN_HEIGHT_LONG		OV1063X_REG_16BIT(0x5615)
+#define OV1063X_AEC_WIN_HEIGHT_SHORT		OV1063X_REG_16BIT(0x5617)
+#define OV1063X_AEC_WEIGHT_SHORT(n)		OV1063X_REG_8BIT(0x563b + (n))
+#define OV1063X_AEC_FINAL_SATURATE_THRESH	OV1063X_REG_16BIT(0x5651)
+#define OV1063X_AEC_CTRLD0			OV1063X_REG_8BIT(0x56d0)
+#define OV1063X_AEC_CTRLD0_R_MAN_EN(n)		((n) << 0)
+#define OV1063X_AEC_CTRLD5			OV1063X_REG_32BIT(0x56d5)	/* r_exp_l_m */
+#define OV1063X_AEC_CTRLD9			OV1063X_REG_32BIT(0x56d9)	/* r_exp_s_m */
+#define OV1063X_AEC_CTRLE8			OV1063X_REG_16BIT(0x56e8)	/* r_snrgain_l_m */
+#define OV1063X_AEC_CTRLEA			OV1063X_REG_16BIT(0x56ea)	/* r_snrgain_s_m */
+
+#define OV1063X_TPM_CTRL0			OV1063X_REG_8BIT(0x6706)
+#define OV1063X_TPM_CTRL0_CLK_DIV(n)		((n) << 0)
+
+#define OV1063X_GROUP_WRITER_COMMAND		OV1063X_REG_8BIT(0x6f00)
+#define OV1063X_GROUP_WRITER_COMMAND_OP(n)	((n) << 6)
+#define OV1063X_GROUP_WRITER_COMMAND_ID(n)	((n) << 4)
+#define OV1063X_GROUP_WRITER_COMMAND_EN		(3U << 0)
+#define OV1063X_PARI_ADDR_MIN			OV1063X_REG_16BIT(0x6f06)
+#define OV1063X_PARI_ADDR_MAX			OV1063X_REG_16BIT(0x6f0a)
+
+#define OV1063X_EMB_LINE_EN			OV1063X_REG_8BIT(0x6800)
+#define OV1063X_EMB_LINE_EN_ENABLE		BIT(0)
+#define OV1063X_EMB_SIZE_MANU_EN		OV1063X_REG_8BIT(0x6804)
+#define OV1063X_EMB_SIZE_EN_ENABLE		BIT(0)
+#define OV1063X_EMB_SIZE_MANU			OV1063X_REG_16BIT(0x6805)
+
+#define OV1063X_HORIZ_COLORCORRECT		OV1063X_REG_8BIT(0x6900)
+#define OV1063X_HORIZ_COLORCORRECT_ON		BIT(0)
+
+#define OV1063X_AEC_TARGET_NUM			OV1063X_REG_8BIT(0xc450)
+#define OV1063X_AEC_TARGET_NUM_AA_MODE		(1U << 0)
+#define OV1063X_AEC_TARGET_NUM_AB_MODE		(2U << 0)
+#define OV1063X_AEC_TARGET_NUM_ABC_MODE		(3U << 0)
+#define OV1063X_AEC_LS_SENS_RATIO		OV1063X_REG_16BIT(0xc452)
+#define OV1063X_AEC_NONWDR_EN			OV1063X_REG_8BIT(0xc454)
+#define OV1063X_AEC_NONWDR_SWITCH		OV1063X_REG_8BIT(0xc455)
+#define OV1063X_AEC_FIXED_RATIO_EN		OV1063X_REG_8BIT(0xc456)
+#define OV1063X_AEC_GP_MODE_EN			OV1063X_REG_8BIT(0xc457)
+#define OV1063X_AEC_NIGHT_MODE_EN		OV1063X_REG_8BIT(0xc458)
+#define OV1063X_AEC_NIGHT_MODE_CTRL		OV1063X_REG_8BIT(0xc459)
+#define OV1063X_AEC_NIGHT_MODE_CTRL_INSERT	BIT(0)
+#define OV1063X_AEC_FRACTAL_EXP_EN		OV1063X_REG_8BIT(0xc45a)
+#define OV1063X_AEC_NONLINEAR_GAIN_EN		OV1063X_REG_8BIT(0xc45b)
+#define OV1063X_AEC_MANU_GAMMA_EN		OV1063X_REG_8BIT(0xc45c)
+#define OV1063X_AEC_HOLD_BAND_EN		OV1063X_REG_8BIT(0xc45d)
+#define OV1063X_AEC_BAND_FILTER_FLAG		OV1063X_REG_8BIT(0xc45e)
+#define OV1063X_AEC_BAND_FILTER_FLAG_0HZ	(0U << 0)
+#define OV1063X_AEC_BAND_FILTER_FLAG_60HZ	(1U << 0)
+#define OV1063X_AEC_BAND_FILTER_FLAG_50HZ	(2U << 0)
+#define OV1063X_AEC_BAND_FILTER_EN		OV1063X_REG_8BIT(0xc45f)
+#define OV1063X_AEC_BAND_FILTER_SHORT		OV1063X_REG_8BIT(0xc460)
+#define OV1063X_AEC_LESS_1BAND_EN		OV1063X_REG_8BIT(0xc461)
+#define OV1063X_AEC_LESS_1BAND_SHORT		OV1063X_REG_8BIT(0xc462)
+#define OV1063X_AEC_WDR_GAIN_LIMIT_EN		OV1063X_REG_8BIT(0xc463)
+#define OV1063X_AEC_LOG_TARGET(n)		OV1063X_REG_16BIT(0xc464 + (n) * 2)
+#define OV1063X_AEC_TARGET_LONG(n)		OV1063X_REG_8BIT(0xc46a + (n))
+#define OV1063X_AEC_TARGET_SHORT(n)		OV1063X_REG_8BIT(0xc46d + (n))
+#define OV1063X_AEC_MAX_SHORT_LE		OV1063X_REG_32BIT(0xc47c)
+#define OV1063X_AEC_MAX_GAIN_LONG		OV1063X_REG_16BIT(0xc480)
+#define OV1063X_AEC_MAX_GAIN_SHORT		OV1063X_REG_16BIT(0xc482)
+#define OV1063X_AEC_MIN_GAIN_LONG		OV1063X_REG_16BIT(0xc484)
+#define OV1063X_AEC_MIN_GAIN_SHORT		OV1063X_REG_16BIT(0xc486)
+#define OV1063X_AEC_MAX_EXP_LONG		OV1063X_REG_16BIT(0xc488)
+#define OV1063X_AEC_MAX_EXP_SHORT		OV1063X_REG_16BIT(0xc48a)
+#define OV1063X_AEC_MIN_EXP_LONG		OV1063X_REG_16BIT(0xc48c)
+#define OV1063X_AEC_MIN_EXP_SHORT		OV1063X_REG_16BIT(0xc48e)
+#define OV1063X_AEC_FIXED_RATIO			OV1063X_REG_8BIT(0xc490)
+#define OV1063X_AEC_GP_MODE_RATIO_B2A		OV1063X_REG_8BIT(0xc492)
+#define OV1063X_AEC_GP_MODE_RATIO_C2A		OV1063X_REG_8BIT(0xc493)
+#define OV1063X_AEC_MIN_GAMMA_LIST(n)		OV1063X_REG_16BIT(0xc498 + (n) * 2)
+#define OV1063X_AEC_MAX_GAMMA_LIST(n)		OV1063X_REG_16BIT(0xc49e + (n) * 2)
+#define OV1063X_AEC_DR_LIST(n)			OV1063X_REG_16BIT(0xc4a4 + (n) * 2)
+#define OV1063X_AEC_BAND_VALUE_60HZ		OV1063X_REG_16BIT(0xc4aa)
+#define OV1063X_AEC_BAND_VALUE_50HZ		OV1063X_REG_16BIT(0xc4ac)
+
+#define OV1063X_AWB_SIMPLE_MIN_NUM		OV1063X_REG_16BIT(0xc4cc)
+#define OV1063X_AWB_CT_MIN_NUM			OV1063X_REG_16BIT(0xc4ce)
+
+#define OV1063X_VTS_ADDR			OV1063X_REG_16BIT(0xc518)
+#define OV1063X_HTS_ADDR			OV1063X_REG_16BIT(0xc51a)
+
+#include "ov1063x_regs.h"
+
+/* IDs */
+#define OV10633_VERSION_REG			0xa630
+#define OV10635_VERSION_REG			0xa635
+
+enum ov1063x_model {
+	SENSOR_OV10633,
+	SENSOR_OV10635,
+};
+
+#define OV1063X_SENSOR_WIDTH			1312
+#define OV1063X_SENSOR_HEIGHT			814
+
+struct ov1063x_priv {
+	struct device			*dev;
+
+	struct regmap			*regmap;
+	struct clk			*clk;
+	struct gpio_desc		*reset_gpio;
+	struct gpio_desc		*pwdn_gpio;
+
+	int				model;
+	const char			*name;
+	unsigned long			clk_rate;
+
+	struct v4l2_subdev		subdev;
+	struct media_pad		pad;
+
+	struct v4l2_ctrl_handler	hdl;
+
+	/*
+	 * The streaming and format fields are protected by the control handler
+	 * lock.
+	 */
+	bool				streaming;
+	struct v4l2_rect		analog_crop;
+	struct v4l2_rect		digital_crop;
+	struct v4l2_mbus_framefmt	format;
+
+	unsigned int			fps_numerator;
+	unsigned int			fps_denominator;
+};
+
+/*
+ * TODO: Expose multiple subdevs to control cropping and subsampling separately
+ * from userspace instead of hardcoding resolutions.
+ *
+ * TODO: Resolutions with an analog crop rectangle width equal to 768 or higher
+ * don't work properly.
+ */
+static const struct v4l2_area ov1063x_framesizes[] = {
+	{
+		.width		= 1280,
+		.height		= 800,
+	}, {
+		.width		= 1280,
+		.height		= 720,
+	}, {
+		.width		= 752,
+		.height		= 480,
+	}, {
+		.width		= 640,
+		.height		= 480,
+	}, {
+		.width		= 600,
+		.height		= 400,
+	}, {
+		.width		= 352,
+		.height		= 288,
+	}, {
+		.width		= 320,
+		.height		= 240,
+	},
+};
+
+static const u32 ov1063x_mbus_formats[] = {
+	MEDIA_BUS_FMT_YUYV8_2X8,
+	MEDIA_BUS_FMT_UYVY8_2X8,
+	MEDIA_BUS_FMT_VYUY8_2X8,
+	MEDIA_BUS_FMT_YVYU8_2X8,
+};
+
+static inline struct ov1063x_priv *to_ov1063x(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct ov1063x_priv, subdev);
+}
+
+/* -----------------------------------------------------------------------------
+ * Read/Write Helpers
+ */
+
+static int ov1063x_read(struct ov1063x_priv *priv, u32 reg, u32 *val)
+{
+	unsigned int len = (reg >> OV1063X_REG_SIZE_SHIFT) & 3;
+	u16 addr = reg & OV1063X_REG_ADDR_MASK;
+	unsigned int i;
+	int ret;
+
+	*val = 0;
+
+	for (i = 0; i < len; ++i) {
+		u32 byte;
+
+		ret = regmap_read(priv->regmap, addr, &byte);
+		if (ret)
+			return ret;
+
+		*val = (*val << 8) | byte;
+		addr++;
+	}
+
+	return 0;
+}
+
+static int ov1063x_write(struct ov1063x_priv *priv, u32 reg, u32 val, int *err)
+{
+	unsigned int len = (reg >> OV1063X_REG_SIZE_SHIFT) & 7;
+	u16 addr = reg & OV1063X_REG_ADDR_MASK;
+	unsigned int shift = (len - 1) * 8;
+	unsigned int i;
+	int ret;
+
+	if (err && *err)
+		return *err;
+
+	for (i = 0; i < len; ++i) {
+		ret = regmap_write(priv->regmap, addr, (val >> shift) & 0xff);
+		if (ret) {
+			if (err)
+				*err = ret;
+			return ret;
+		}
+
+		shift -= 8;
+		addr++;
+	}
+
+	return 0;
+}
+
+static int ov1063x_write_array(struct ov1063x_priv *priv,
+			       const struct ov1063x_reg *regs,
+			       unsigned int nr_regs)
+{
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < nr_regs; i++) {
+		ret = ov1063x_write(priv, regs[i].reg, regs[i].val, NULL);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ov1063x_update(struct ov1063x_priv *priv, u32 reg, u32 mask, u32 val,
+			  int *err)
+{
+	unsigned int len = (reg >> OV1063X_REG_SIZE_SHIFT) & 7;
+	u16 addr = reg & OV1063X_REG_ADDR_MASK;
+	unsigned int shift = (len - 1) * 8;
+	unsigned int i;
+	int ret;
+
+	if (err && *err)
+		return *err;
+
+	for (i = 0; i < len; ++i) {
+		ret = regmap_update_bits(priv->regmap, addr,
+					 (mask >> shift) & 0xff,
+					 (val >> shift) & 0xff);
+		if (ret) {
+			if (err)
+				*err = ret;
+			return ret;
+		}
+
+		shift -= 8;
+		addr++;
+	}
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Hardware Configuration
+ */
+
+struct ov1063x_pll_config {
+	unsigned int pre_div;
+	unsigned int mult;
+	unsigned int div;
+	unsigned int clk_out;
+};
+
+static int ov1063x_pll_setup(unsigned int clk_rate,
+			     unsigned int *htsmin, unsigned int vts,
+			     unsigned int fps_numerator,
+			     unsigned int fps_denominator,
+			     struct ov1063x_pll_config *cfg)
+{
+	static const unsigned int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
+
+	unsigned int best_pclk = UINT_MAX;
+	unsigned int best_pre_div;
+	unsigned int best_mult;
+	unsigned int best_div;
+	unsigned int best_hts;
+	unsigned int max_pre_div;
+	unsigned int pre_div;
+	unsigned int hts;
+
+	/*
+	 *  XVCLK --> pre-div -------> mult ----------> div --> output
+	 * 6-27 MHz           3-27 MHz      200-500 MHz       Max 96 MHz
+	 *
+	 * Valid pre-divider values are 1, 1.5, 2, 3, 4, 5, 6 and 7. The
+	 * pre_divs array stores the pre-dividers multiplied by two, indexed by
+	 * register values.
+	 *
+	 * Valid multiplier values are [1, 63], stored as-is in registers.
+	 *
+	 * Valid divider values are 2 to 16 with a step of 2, stored in
+	 * registers as (div / 2) - 1.
+	 */
+
+	if (clk_rate < 6 * 1000 * 1000 || clk_rate > 27 * 1000 * 1000)
+		return -EINVAL;
+
+	/*
+	 * We try all valid combinations of settings for the 3 blocks to get
+	 * the pixel clock, and from that calculate the actual hts/vts to use.
+	 * The vts is extended so as to achieve the required frame rate.
+	 */
+
+	max_pre_div = max(clk_rate / (3 * 1000 * 1000),
+			  ARRAY_SIZE(pre_divs) - 1);
+
+	for (pre_div = 0; pre_div <= max_pre_div; pre_div++) {
+		unsigned int clk1 = clk_rate * 2 / pre_divs[pre_div];
+		unsigned int min_mult;
+		unsigned int max_mult;
+		unsigned int mult;
+
+		if (clk1 < 3 * 1000 * 1000 || clk1 > 27 * 1000 * 1000)
+			continue;
+
+		min_mult = DIV_ROUND_UP(200 * 1000 * 1000, clk1);
+		max_mult = min(500 * 1000 * 1000 / clk1, 63U);
+
+		for (mult = min_mult; mult <= max_mult; mult++) {
+			unsigned int clk2 = clk1 * mult;
+			unsigned int min_div;
+			unsigned int div;
+
+			min_div = DIV_ROUND_UP(clk2, 96 * 1000 * 1000);
+			min_div = round_up(min_div, 2);
+
+			for (div = min_div; div <= 16; div += 2) {
+				unsigned int pclk = clk2 / div;
+				unsigned int min_pclk;
+
+				/*
+				 * TODO: HTS calculation should ideally be split
+				 * from the PLL calculations. This requires
+				 * figuring out where the pclk / 300000 comes
+				 * from.
+				 */
+				hts = *htsmin + pclk / (300*1000);
+
+				/* 2 clock cycles for every YUV422 pixel. */
+				min_pclk = hts * vts / fps_denominator
+					 * fps_numerator * 2;
+				if (pclk < min_pclk)
+					continue;
+
+				if (pclk < best_pclk) {
+					best_pclk = pclk;
+					best_hts = hts;
+					best_pre_div = pre_div;
+					best_mult = mult;
+					best_div = div;
+				}
+			}
+		}
+	}
+
+	if (best_pclk == UINT_MAX)
+		return -EINVAL;
+
+	cfg->mult = best_mult;
+	cfg->pre_div = best_pre_div;
+	cfg->div = (best_div / 2) - 1;
+	cfg->clk_out = best_pclk;
+
+	*htsmin = best_hts;
+
+	return 0;
+}
+
+static int ov1063x_isp_reset(struct ov1063x_priv *priv, bool reset)
+{
+	unsigned int i;
+	int ret = 0;
+
+	if (!reset) {
+		/*
+		 * Enable ISP blocks. Why OV1063X_SC_SOC_CLKRST7 needs to be
+		 * written 26 times is unknown.
+		 */
+		for (i = 0; i < 26; ++i)
+			ov1063x_write(priv, OV1063X_SC_SOC_CLKRST7,
+				      OV1063X_SC_SOC_CLKRST7_SCLK, &ret);
+
+		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST1,
+			      OV1063X_SC_CMMN_CLKRST1_SCLK, &ret);
+		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
+			      OV1063X_SC_CMMN_CLKRST2_PCLK_DVP |
+			      OV1063X_SC_CMMN_CLKRST2_SCLK, &ret);
+		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST0,
+			      OV1063X_SC_CMMN_CLKRST0_SCLK, &ret);
+	} else {
+		/* Reset the ISP. */
+		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST1,
+			      OV1063X_SC_CMMN_CLKRST1_SCLK |
+			      OV1063X_SC_CMMN_CLKRST1_RST, &ret);
+		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
+			      OV1063X_SC_CMMN_CLKRST2_PCLK_DVP |
+			      OV1063X_SC_CMMN_CLKRST2_SCLK |
+			      OV1063X_SC_CMMN_CLKRST2_RST_DVP |
+			      OV1063X_SC_CMMN_CLKRST2_RST, &ret);
+		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST0,
+			      OV1063X_SC_CMMN_CLKRST0_SCLK |
+			      OV1063X_SC_CMMN_CLKRST0_RST, &ret);
+	}
+
+	return ret;
+}
+
+static int ov1063x_configure(struct ov1063x_priv *priv)
+{
+	struct ov1063x_pll_config pll_cfg;
+	unsigned int width_pre_subsample;
+	unsigned int nr_isp_pixels;
+	unsigned int hts, vts;
+	u32 val;
+	int ret;
+
+	/* Minimum values for HTS anv VTS. */
+	hts = priv->analog_crop.width + 200;
+	vts = priv->analog_crop.height + 50;
+
+	/*
+	 * Get the best PCLK and adjust HTS accordingly. Adjust VTS to get as
+	 * close to the desired frame rate as we can.
+	 */
+	ret = ov1063x_pll_setup(priv->clk_rate, &hts, vts,
+				priv->fps_numerator, priv->fps_denominator,
+				&pll_cfg);
+	if (ret < 0)
+		return -EINVAL;
+
+	vts = pll_cfg.clk_out
+	    / (hts * 2 * priv->fps_numerator / priv->fps_denominator);
+
+	dev_dbg(priv->dev, "active %ux%u (total %ux%u) %u/%u fps, @%u MP/s\n",
+		priv->format.width, priv->format.height,
+		hts, vts, priv->fps_numerator, priv->fps_denominator,
+		pll_cfg.clk_out);
+	dev_dbg(priv->dev, "PLL pre-div %u mult %u div %u\n",
+		pll_cfg.pre_div, pll_cfg.mult, pll_cfg.div);
+
+	/* Reset the ISP and configure the PLL. */
+	ret = ov1063x_isp_reset(priv, true);
+
+	ov1063x_write(priv, OV1063X_SC_CMMN_PLL_CTRL0, pll_cfg.mult, &ret);
+	ov1063x_write(priv, OV1063X_SC_CMMN_PLL_CTRL1,
+		      (pll_cfg.pre_div << 4) | pll_cfg.div, &ret);
+
+	/* Analog array configuration (including horizontal cropping) */
+	switch (priv->analog_crop.width) {
+	case OV1063X_SENSOR_WIDTH:
+	default:
+		val = 0x60 | OV1063X_ANA_ARRAY1_FULL
+		    | OV1063X_ANA_ARRAY1_DELAY(3);
+		break;
+	case 768:
+		val = 0x60 | OV1063X_ANA_ARRAY1_CROP_768
+		    | OV1063X_ANA_ARRAY1_DELAY(3);
+		break;
+	case 656:
+		val = 0x60 | OV1063X_ANA_ARRAY1_CROP_656
+		    | OV1063X_ANA_ARRAY1_DELAY(3);
+		break;
+	}
+
+	ov1063x_write(priv, OV1063X_ANA_ARRAY1, val, &ret);
+
+	/* Sensor configuration */
+	ov1063x_write(priv, OV1063X_SENSOR_RSTGOLOW,
+		      (pll_cfg.clk_out + 1500000) / 3000000, &ret);
+	ov1063x_write(priv, OV1063X_SENSOR_HLDWIDTH,
+		      (pll_cfg.clk_out + 666666) / 1333333, &ret);
+	ov1063x_write(priv, OV1063X_SENSOR_TXWIDTH,
+		      (pll_cfg.clk_out + 961500) / 1923000, &ret);
+
+	/*
+	 * Timings (including cropping)
+	 *
+	 * TODO: The vertical size is set to the height of the analog crop
+	 * rectangle plus 4 pixels. This margin is probably used by the ISP for
+	 * CFA interpolation, and should be moved to the crop rectangle height
+	 * after investigating how the ISP operates.
+	 */
+	ov1063x_write(priv, OV1063X_TIMING_Y_START_ADDR,
+		      priv->analog_crop.top, &ret);
+	ov1063x_write(priv, OV1063X_TIMING_Y_END_ADDR,
+		      priv->analog_crop.top + priv->analog_crop.height + 3,
+		      &ret);
+	ov1063x_write(priv, OV1063X_TIMING_ISP_X_WIN, priv->digital_crop.left,
+		      &ret);
+	ov1063x_write(priv, OV1063X_TIMING_ISP_Y_WIN, priv->digital_crop.top,
+		      &ret);
+	ov1063x_write(priv, OV1063X_TIMING_X_OUTPUT_SIZE, priv->format.width,
+		      &ret);
+	ov1063x_write(priv, OV1063X_TIMING_Y_OUTPUT_SIZE, priv->format.height,
+		      &ret);
+	ov1063x_write(priv, OV1063X_TIMING_HTS, hts, &ret);
+	ov1063x_write(priv, OV1063X_TIMING_VTS, vts, &ret);
+
+	/*
+	 * Sub-sampling. Horizontal sub-sampling is applied in the ISP, vertical
+	 * sub-sampling in the pixel array.
+	 */
+	if (priv->format.width <= 640) {
+		ov1063x_write(priv, OV1063X_ISP_RW05, OV1063X_ISP_RW05_SUB_AVG |
+			      OV1063X_ISP_RW05_SUB_ENABLE, &ret);
+		ov1063x_write(priv, OV1063X_SC_CMMN_PCLK_DIV_CTRL, 2, &ret);
+	} else {
+		ov1063x_write(priv, OV1063X_ISP_RW05, OV1063X_ISP_RW05_SUB_AVG,
+			      &ret);
+		ov1063x_write(priv, OV1063X_SC_CMMN_PCLK_DIV_CTRL, 1, &ret);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	if (priv->format.height <= 400)
+		ret = ov1063x_write_array(priv, ov1063x_regs_vert_sub2,
+					  ARRAY_SIZE(ov1063x_regs_vert_sub2));
+	else
+		ret = ov1063x_write_array(priv, ov1063x_regs_vert_no_sub,
+					  ARRAY_SIZE(ov1063x_regs_vert_no_sub));
+
+	/*
+	 * AEC & AWB
+	 *
+	 * TODO: The number of pixels fed to the ISP is computed using the
+	 * analog crop width and the vertical output size, to account for the
+	 * fact that vertical sub-sampling is applied in the pixel array while
+	 * horizontal sub-sampling is applied in the ISP. The 4 pixels margin
+	 * seems incorrect when sub-sampling, as the vertical timing start and
+	 * stop registers are programmed with a 4 pixels margin before
+	 * sub-sampling, the ISP should thus receive a 2 pixels margin only.
+	 * This needs to be investigated.
+	 *
+	 * TODO: When applying vertical digital crop, the output height is
+	 * likely the wrong value to compute the total number of pixels fed to
+	 * the ISP.
+	 */
+	val = (vts - 8) * 16;
+	ov1063x_write(priv, OV1063X_AEC_MAX_EXP_LONG, val, &ret);
+	ov1063x_write(priv, OV1063X_AEC_MAX_EXP_SHORT, val, &ret);
+
+	nr_isp_pixels = priv->analog_crop.width * (priv->format.height + 4);
+	ov1063x_write(priv, OV1063X_AWB_SIMPLE_MIN_NUM, nr_isp_pixels / 256, &ret);
+	ov1063x_write(priv, OV1063X_AWB_CT_MIN_NUM, nr_isp_pixels / 256, &ret);
+	ov1063x_write(priv, OV1063X_REG_16BIT(0xc512), nr_isp_pixels / 16,
+		      &ret);
+
+	ov1063x_write(priv, OV1063X_VTS_ADDR, vts, &ret);
+	ov1063x_write(priv, OV1063X_HTS_ADDR, hts, &ret);
+
+	/* FIFO */
+	ov1063x_write(priv, OV1063X_VFIFO_LLEN_FIRS1_SEL,
+		      OV1063X_VFIFO_LLEN_FIRS1_SEL_8B_YUV, &ret);
+	width_pre_subsample = priv->format.width <= 640
+			    ? priv->format.width * 2 : priv->format.width;
+	ov1063x_write(priv, OV1063X_VFIFO_LINE_LENGTH_MAN, 2 * hts, &ret);
+	ov1063x_write(priv, OV1063X_VFIFO_HSYNC_START_POSITION,
+		      2 * (hts - width_pre_subsample), &ret);
+
+	/* Output interface (DVP). */
+	switch (priv->format.code) {
+	case MEDIA_BUS_FMT_UYVY8_2X8:
+		val = OV1063X_FORMAT_UYVY;
+		break;
+	case MEDIA_BUS_FMT_VYUY8_2X8:
+		val = OV1063X_FORMAT_VYUY;
+		break;
+	case MEDIA_BUS_FMT_YUYV8_2X8:
+		val = OV1063X_FORMAT_YUYV;
+		break;
+	case MEDIA_BUS_FMT_YVYU8_2X8:
+		val = OV1063X_FORMAT_YYYU;
+		break;
+	default:
+		val = OV1063X_FORMAT_UYVY;
+		break;
+	}
+
+	ov1063x_write(priv, OV1063X_FORMAT_CTRL00, val, &ret);
+	ov1063x_write(priv, OV1063X_DVP_MOD_SEL, 0, &ret);
+
+	if (ret)
+		return ret;
+
+	/* Take the ISP out of reset. */
+	return ov1063x_isp_reset(priv, false);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Control Operations
+ */
+
+static const char * const ov1063x_test_pattern_menu[] = {
+	"Disabled",
+	"Color Bars, Plain",
+	"Color Bars, Vertical Gradient",
+	"Color Bars, Horizontal Gradient",
+	"Color Bars, Repeating",
+	"Random Data",
+	"Squares, Color",
+	"Squares, Black & White",
+};
+
+struct ov1063x_tpg_config {
+	u8 ctrl3d;
+	u8 ctrl3e;
+};
+
+static const struct ov1063x_tpg_config
+ov1063x_tpg_configs[ARRAY_SIZE(ov1063x_test_pattern_menu) - 1] = {
+	{
+		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
+			| OV1063X_ISP_CTRL3D_COLOR_BAR(0),
+		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
+	}, {
+		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
+			| OV1063X_ISP_CTRL3D_COLOR_BAR(1),
+		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
+	}, {
+		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
+			| OV1063X_ISP_CTRL3D_COLOR_BAR(2),
+		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
+	}, {
+		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN
+			| OV1063X_ISP_CTRL3D_COLOR_BAR(3),
+		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_BARS,
+	}, {
+		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN,
+		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_RANDOM,
+	}, {
+		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN,
+		.ctrl3e = OV1063X_ISP_CTRL3E_PATTERN_SQUARES,
+	}, {
+		.ctrl3d = OV1063X_ISP_CTRL3D_TEST_PATTERN_EN,
+		.ctrl3e = OV1063X_ISP_CTRL3E_SQUARE_BW
+			| OV1063X_ISP_CTRL3E_PATTERN_SQUARES,
+	},
+};
+
+static int ov1063x_tpg_setup(struct ov1063x_priv *priv, struct v4l2_ctrl *ctrl)
+{
+	const struct ov1063x_tpg_config *cfg;
+	int ret = 0;
+
+	if (!ctrl->val)
+		return ov1063x_write_array(priv, ov1063x_regs_colorbar_disable,
+					   ARRAY_SIZE(ov1063x_regs_colorbar_disable));
+
+	if (!ctrl->cur.val) {
+		/*
+		 * Only write the full settings when the test pattern was
+		 * disabled, not when we're just changing the test pattern type.
+		 */
+		ret = ov1063x_write_array(priv, ov1063x_regs_colorbar_enable,
+					  ARRAY_SIZE(ov1063x_regs_colorbar_enable));
+		if (ret < 0)
+			return ret;
+	}
+
+	cfg = &ov1063x_tpg_configs[ctrl->val - 1];
+
+	/* TODO: Add support for the moving bar overlay. */
+	ov1063x_write(priv, OV1063X_ISP_CTRL3D, cfg->ctrl3d, &ret);
+	ov1063x_write(priv, OV1063X_ISP_CTRL3E, cfg->ctrl3e, &ret);
+
+	return ret;
+}
+
+static int ov1063x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov1063x_priv *priv = container_of(ctrl->handler,
+					struct ov1063x_priv, hdl);
+	int ret = 0;
+
+	if (!priv->streaming)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP: {
+		const u32 vflip = OV1063X_TIMING_CTRL1C_VFLIP_DIG
+				| OV1063X_TIMING_CTRL1C_VFLIP_ARRAY;
+
+		return ov1063x_update(priv, OV1063X_TIMING_CTRL1C, vflip,
+				      ctrl->val ? vflip : 0, NULL);
+	}
+
+	case V4L2_CID_HFLIP: {
+		const u32 hflip = OV1063X_TIMING_CTRL1D_HFLIP_DIG
+				| OV1063X_TIMING_CTRL1D_HFLIP_ARRAY;
+
+		ov1063x_update(priv, OV1063X_HORIZ_COLORCORRECT,
+			       OV1063X_HORIZ_COLORCORRECT_ON,
+			       ctrl->val ? OV1063X_HORIZ_COLORCORRECT_ON : 0,
+			       &ret);
+		ov1063x_update(priv, OV1063X_TIMING_CTRL1D, hflip,
+			       ctrl->val ? hflip : 0, &ret);
+		return ret;
+	}
+
+	case V4L2_CID_TEST_PATTERN:
+		return ov1063x_tpg_setup(priv, ctrl);
+	}
+
+	return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops ov1063x_ctrl_ops = {
+	.s_ctrl = ov1063x_s_ctrl,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdev Operations
+ */
+
+static int ov1063x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct ov1063x_priv *priv = to_ov1063x(sd);
+	int ret = 0;
+
+	if (!enable) {
+		ov1063x_write(priv, OV1063X_STREAM_MODE, 0, &ret);
+		ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
+			      OV1063X_SC_CMMN_CLKRST2_SCLK, &ret);
+
+		pm_runtime_mark_last_busy(priv->dev);
+		pm_runtime_put_autosuspend(priv->dev);
+
+		mutex_lock(priv->hdl.lock);
+		priv->streaming = false;
+		mutex_unlock(priv->hdl.lock);
+
+		return ret;
+	}
+
+	mutex_lock(priv->hdl.lock);
+
+	/* Streaming needs to be true for ov1063x_s_ctrl() to proceed. */
+	priv->streaming = true;
+
+	ret = pm_runtime_get_sync(priv->dev);
+	if (ret < 0)
+		goto done;
+
+	ret = ov1063x_configure(priv);
+	if (ret < 0)
+		goto done;
+
+	ret = __v4l2_ctrl_handler_setup(&priv->hdl);
+	if (ret < 0)
+		goto done;
+
+	ret = 0;
+	ov1063x_write(priv, OV1063X_STREAM_MODE, OV1063X_STREAM_MODE_ON, &ret);
+	ov1063x_write(priv, OV1063X_SC_CMMN_CLKRST2,
+		      OV1063X_SC_CMMN_CLKRST2_PCLK_DVP |
+		      OV1063X_SC_CMMN_CLKRST2_SCLK, &ret);
+
+done:
+	if (ret < 0) {
+		/*
+		 * In case of error, turn the power off synchronously as the
+		 * device likely has no other chance to recover.
+		 */
+		pm_runtime_put_sync(priv->dev);
+		priv->streaming = false;
+	}
+
+	mutex_unlock(priv->hdl.lock);
+
+	return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+__ov1063x_get_pad_format(struct ov1063x_priv *priv,
+			 struct v4l2_subdev_pad_config *cfg,
+			 unsigned int pad, u32 which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_format(&priv->subdev, cfg, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &priv->format;
+	default:
+		return NULL;
+	}
+}
+
+static int ov1063x_init_cfg(struct v4l2_subdev *sd,
+			    struct v4l2_subdev_pad_config *cfg)
+{
+	u32 which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	struct ov1063x_priv *priv = to_ov1063x(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __ov1063x_get_pad_format(priv, cfg, 0, which);
+	format->code = ov1063x_mbus_formats[0];
+	format->width = ov1063x_framesizes[0].width;
+	format->height = ov1063x_framesizes[0].height;
+	format->field = V4L2_FIELD_NONE;
+	format->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		/*
+		 * This assumes that ov1063x_mbus_formats[0] doesn't
+		 * sub-sample.
+		 */
+		priv->analog_crop.width = OV1063X_SENSOR_WIDTH;
+		priv->analog_crop.height = format->height;
+		priv->analog_crop.left = ((OV1063X_SENSOR_WIDTH -
+					   priv->analog_crop.width) / 2) & ~1;
+		priv->analog_crop.top = ((OV1063X_SENSOR_HEIGHT -
+					  priv->analog_crop.height) / 2) & ~1;
+
+		priv->digital_crop.width = format->width;
+		priv->digital_crop.height = format->height;
+		priv->digital_crop.left = ((priv->analog_crop.width -
+					    priv->digital_crop.width) / 2) & ~1;
+		priv->digital_crop.top = 0;
+	}
+
+	return 0;
+}
+
+static int ov1063x_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index >= ARRAY_SIZE(ov1063x_mbus_formats))
+		return -EINVAL;
+
+	code->code = ov1063x_mbus_formats[code->index];
+
+	return 0;
+}
+
+static int ov1063x_enum_frame_sizes(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_frame_size_enum *fse)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(ov1063x_mbus_formats); ++i) {
+		if (ov1063x_mbus_formats[i] == fse->code)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(ov1063x_mbus_formats))
+		return -EINVAL;
+
+	if (fse->index >= ARRAY_SIZE(ov1063x_framesizes))
+		return -EINVAL;
+
+	fse->min_width  = ov1063x_framesizes[fse->index].width;
+	fse->max_width  = fse->min_width;
+	fse->max_height = ov1063x_framesizes[fse->index].height;
+	fse->min_height = fse->max_height;
+
+	return 0;
+}
+
+static int ov1063x_get_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_pad_config *cfg,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct ov1063x_priv *priv = to_ov1063x(sd);
+
+	fmt->format = *__ov1063x_get_pad_format(priv, cfg, fmt->pad,
+						fmt->which);
+
+	return 0;
+}
+
+static int ov1063x_set_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_pad_config *cfg,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct ov1063x_priv *priv = to_ov1063x(sd);
+	struct v4l2_mbus_framefmt *format;
+	const struct v4l2_area *fsize;
+	unsigned int i;
+	u32 code;
+	int ret = 0;
+
+	/*
+	 * Validate the media bus code, defaulting to the first one if the
+	 * requested code isn't supported.
+	 */
+	for (i = 0; i < ARRAY_SIZE(ov1063x_mbus_formats); ++i) {
+		if (ov1063x_mbus_formats[i] == fmt->format.code) {
+			code = fmt->format.code;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(ov1063x_mbus_formats))
+		code = ov1063x_mbus_formats[0];
+
+	/* Find the nearest supported frame size. */
+	fsize = v4l2_find_nearest_size(ov1063x_framesizes,
+				       ARRAY_SIZE(ov1063x_framesizes),
+				       width, height, fmt->format.width,
+				       fmt->format.height);
+
+	/* Update the stored format and return it. */
+	format = __ov1063x_get_pad_format(priv, cfg, fmt->pad, fmt->which);
+
+	mutex_lock(priv->hdl.lock);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	format->code = code;
+	format->width = fsize->width;
+	format->height = fsize->height;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		unsigned int hsub;
+		unsigned int vsub;
+
+		/*
+		 * Enable horizontal or vertical sub-sampling automatically when
+		 * the width or height are smaller than half the maximum
+		 * resolution.
+		 */
+		hsub = format->width <= 640 ? 2 : 1;
+		vsub = format->height <= 400 ? 2 : 1;
+
+		/*
+		 * The analog horizontal crop is restricted to the full sensor
+		 * width (1312 pixels), 768 or 656 pixels. Additional cropping
+		 * will be applied in the digital domain.
+		 */
+		priv->analog_crop.width = format->width * hsub;
+		priv->analog_crop.height = format->height * vsub;
+
+		if (priv->analog_crop.width > 768)
+			priv->analog_crop.width = OV1063X_SENSOR_WIDTH;
+		else if (priv->analog_crop.width > 656)
+			priv->analog_crop.width = 768;
+		else
+			priv->analog_crop.width = 656;
+
+		/*
+		 * The digital crop is applied at the ISP input, before
+		 * horizontal sub-sampling but after vertical sub-sampling as
+		 * the latter is applied in the pixel array.
+		 */
+		priv->digital_crop.width = format->width * hsub;
+		priv->digital_crop.height = format->height;
+
+		/*
+		 * Center the crop rectangles, rounding coordinates to a
+		 * multiple of 2 to avoid changing the Bayer pattern.
+		 */
+		priv->analog_crop.left = ((OV1063X_SENSOR_WIDTH -
+					   priv->analog_crop.width) / 2) & ~1;
+		priv->analog_crop.top = ((OV1063X_SENSOR_HEIGHT -
+					  priv->analog_crop.height) / 2) & ~1;
+		priv->digital_crop.left = ((priv->analog_crop.width -
+					    priv->digital_crop.width) / 2) & ~1;
+		priv->analog_crop.top = 0;
+	}
+
+	fmt->format = *format;
+
+done:
+	mutex_unlock(priv->hdl.lock);
+
+	return ret;
+}
+
+static const struct v4l2_subdev_core_ops ov1063x_subdev_core_ops = {
+	.log_status		= v4l2_ctrl_subdev_log_status,
+	.subscribe_event	= v4l2_ctrl_subdev_subscribe_event,
+	.unsubscribe_event	= v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops ov1063x_subdev_video_ops = {
+	.s_stream	= ov1063x_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov1063x_subdev_pad_ops = {
+	.init_cfg		= ov1063x_init_cfg,
+	.enum_mbus_code		= ov1063x_enum_mbus_code,
+	.enum_frame_size	= ov1063x_enum_frame_sizes,
+	.get_fmt		= ov1063x_get_fmt,
+	.set_fmt		= ov1063x_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov1063x_subdev_ops = {
+	.core	= &ov1063x_subdev_core_ops,
+	.video	= &ov1063x_subdev_video_ops,
+	.pad	= &ov1063x_subdev_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * Power Management
+ */
+
+static int ov1063x_power_on_init(struct ov1063x_priv *priv)
+{
+	struct i2c_client *client = to_i2c_client(priv->dev);
+	unsigned int i;
+	int ret;
+
+	ret = ov1063x_write(priv, OV1063X_SOFTWARE_RESET, 0x01, NULL);
+	if (ret < 0)
+		return ret;
+
+	ret = ov1063x_isp_reset(priv, true);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Why the I2C address has to be written 23 times (or, actually, at
+	 * all) is unknown. This may not be required.
+	 */
+	for (i = 0; i < 23; ++i) {
+		ret = ov1063x_write(priv, OV1063X_SC_CMMN_SCCB_ID,
+				    OV1063X_SC_CMMN_SCCB_ID_ADDR(client->addr) |
+				    OV1063X_SC_CMMN_SCCB_ID_SEL, NULL);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = ov1063x_write_array(priv, ov1063x_regs_default,
+				  ARRAY_SIZE(ov1063x_regs_default));
+	if (ret < 0)
+		return ret;
+
+	ret = ov1063x_isp_reset(priv, false);
+	if (ret < 0)
+		return ret;
+
+	usleep_range(500, 510);
+	return 0;
+}
+
+static int ov1063x_power_on(struct ov1063x_priv *priv)
+{
+	int ret;
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret < 0)
+		return ret;
+
+	if (priv->pwdn_gpio) {
+		gpiod_set_value_cansleep(priv->pwdn_gpio, 0);
+		usleep_range(1000, 1200);
+	}
+
+	if (priv->reset_gpio) {
+		gpiod_set_value_cansleep(priv->reset_gpio, 0);
+		usleep_range(250000, 260000);
+	}
+
+	return 0;
+}
+
+static void ov1063x_power_off(struct ov1063x_priv *priv)
+{
+	gpiod_set_value_cansleep(priv->pwdn_gpio, 1);
+	gpiod_set_value_cansleep(priv->reset_gpio, 1);
+
+	clk_disable_unprepare(priv->clk);
+}
+
+static int ov1063x_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct ov1063x_priv *priv = to_ov1063x(subdev);
+	int ret;
+
+	ret = ov1063x_power_on(priv);
+	if (ret < 0)
+		return ret;
+
+	ret = ov1063x_power_on_init(priv);
+	if (ret < 0) {
+		ov1063x_power_off(priv);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ov1063x_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct ov1063x_priv *priv = to_ov1063x(subdev);
+
+	ov1063x_power_off(priv);
+
+	return 0;
+}
+
+static const struct dev_pm_ops ov1063x_pm_ops = {
+	SET_RUNTIME_PM_OPS(ov1063x_runtime_suspend, ov1063x_runtime_resume, NULL)
+};
+
+/* -----------------------------------------------------------------------------
+ * I2C Driver, Probe & Remove
+ */
+
+static int ov1063x_detect(struct ov1063x_priv *priv)
+{
+	u32 pid;
+	int ret;
+
+	/* Read and check the product ID. */
+	ret = ov1063x_read(priv, OV1063X_PID, &pid);
+	if (ret)
+		return ret;
+
+	switch (pid) {
+	case OV10633_VERSION_REG:
+		priv->model = SENSOR_OV10633;
+		priv->name = "ov10633";
+		break;
+	case OV10635_VERSION_REG:
+		priv->model = SENSOR_OV10635;
+		priv->name = "ov10635";
+		break;
+	default:
+		dev_err(priv->dev, "Unknown product ID %04x\n", pid);
+		return -ENODEV;
+	}
+
+	dev_dbg(priv->dev, "%s detected\n", priv->name);
+
+	return 0;
+}
+
+static const struct regmap_config ov1063x_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+};
+
+static int ov1063x_probe(struct i2c_client *client)
+{
+	struct ov1063x_priv *priv;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &client->dev;
+
+	/* Acquire resources: regmap, GPIOs and clock. The GPIOs are optional. */
+	priv->regmap = devm_regmap_init_i2c(client, &ov1063x_regmap_config);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	priv->pwdn_gpio = devm_gpiod_get_optional(priv->dev, "powerdown",
+						  GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->pwdn_gpio))
+		return PTR_ERR(priv->pwdn_gpio);
+
+	priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
+						   GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->reset_gpio))
+		return PTR_ERR(priv->reset_gpio);
+	priv->clk = devm_clk_get(priv->dev, "xvclk");
+	if (IS_ERR(priv->clk)) {
+		ret = PTR_ERR(priv->clk);
+		dev_err(priv->dev, "Failed to get xvclk clock: %d\n", ret);
+		return ret;
+	}
+
+	priv->clk_rate = clk_get_rate(priv->clk);
+	dev_dbg(priv->dev, "xvclk rate: %lu Hz\n", priv->clk_rate);
+
+	if (priv->clk_rate < 6000000 || priv->clk_rate > 27000000)
+		return -EINVAL;
+
+	/*
+	 * Enable power and detect the device.
+	 *
+	 * The driver supports runtime PM, but needs to work when runtime PM is
+	 * disabled in the kernel. To that end, power it on manually here.
+	 */
+	ret = ov1063x_power_on(priv);
+	if (ret < 0)
+		return ret;
+
+	ret = ov1063x_detect(priv);
+	if (ret)
+		goto err_power;
+
+	/* Initialize the subdev and its controls. */
+	sd = &priv->subdev;
+	v4l2_i2c_subdev_init(sd, client, &ov1063x_subdev_ops);
+	v4l2_i2c_subdev_set_name(sd, client, priv->name, NULL);
+
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+		     V4L2_SUBDEV_FL_HAS_EVENTS;
+
+	v4l2_ctrl_handler_init(&priv->hdl, 3);
+	v4l2_ctrl_new_std(&priv->hdl, &ov1063x_ctrl_ops,
+			  V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&priv->hdl, &ov1063x_ctrl_ops,
+			  V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std_menu_items(&priv->hdl, &ov1063x_ctrl_ops,
+				     V4L2_CID_TEST_PATTERN,
+				     ARRAY_SIZE(ov1063x_test_pattern_menu) - 1,
+				     0, 0, ov1063x_test_pattern_menu);
+
+	if (priv->hdl.error) {
+		ret = priv->hdl.error;
+		goto err_power;
+	}
+
+	sd->ctrl_handler = &priv->hdl;
+
+	/* Default framerate */
+	priv->fps_numerator = 30;
+	priv->fps_denominator = 1;
+	ov1063x_init_cfg(&priv->subdev, NULL);
+
+	/* Initialize the media entity. */
+	priv->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	ret = media_entity_pads_init(&sd->entity, 1, &priv->pad);
+	if (ret < 0)
+		goto err_ctrls;
+
+	/*
+	 * Enable runtime PM. As the device has been powered manually, mark it
+	 * as active, and increase the usage count without resuming the device.
+	 */
+	pm_runtime_set_active(priv->dev);
+	pm_runtime_get_noresume(priv->dev);
+	pm_runtime_enable(priv->dev);
+
+	/*
+	 * Enable autosuspend as it can help avoiding costly power transitions
+	 * when reconfiguring the sensor.
+	 */
+	pm_runtime_set_autosuspend_delay(priv->dev, 1000);
+	pm_runtime_use_autosuspend(priv->dev);
+
+	/*
+	 * At this point the device is powered on and active from a runtime PM
+	 * point of view, but hasn't gone through the full initialization
+	 * performed by the runtime resume operation. Suspend it synchronously
+	 * to turn the power off, ensuring proper initialization will take
+	 * place before the first usage.
+	 */
+	pm_runtime_put_sync(priv->dev);
+
+	/*
+	 * In case runtime PM is disabled in the kernel, the device remains
+	 * active and needs to be fully initialized at this point.
+	 */
+	if (!pm_runtime_status_suspended(priv->dev)) {
+		ret = ov1063x_power_on_init(priv);
+		if (ret < 0)
+			goto err_pm;
+	}
+
+	/* Finally, register the subdev. */
+	ret = v4l2_async_register_subdev(sd);
+	if (ret < 0)
+		goto err_pm;
+
+	dev_info(priv->dev, "%s probed\n", priv->name);
+
+	return 0;
+
+err_pm:
+	pm_runtime_disable(priv->dev);
+	media_entity_cleanup(&priv->subdev.entity);
+err_ctrls:
+	v4l2_ctrl_handler_free(&priv->hdl);
+err_power:
+	if (!pm_runtime_status_suspended(priv->dev))
+		ov1063x_power_off(priv);
+	return ret;
+}
+
+static int ov1063x_remove(struct i2c_client *client)
+{
+	struct ov1063x_priv *priv = i2c_get_clientdata(client);
+
+	v4l2_ctrl_handler_free(&priv->hdl);
+	v4l2_async_unregister_subdev(&priv->subdev);
+	media_entity_cleanup(&priv->subdev.entity);
+
+	/*
+	 * Disable runtime PM. In case runtime PM is disabled in the kernel,
+	 * make sure to turn power off manually.
+	 */
+	pm_runtime_disable(priv->dev);
+	if (!pm_runtime_status_suspended(priv->dev))
+		ov1063x_power_off(priv);
+	pm_runtime_set_suspended(priv->dev);
+
+	return 0;
+}
+
+static const struct of_device_id ov1063x_dt_id[] = {
+	{ .compatible = "ovti,ov10635" },
+	{ .compatible = "ovti,ov10633" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ov1063x_dt_id);
+
+static struct i2c_driver ov1063x_i2c_driver = {
+	.driver = {
+		.name = "ov1063x",
+		.of_match_table = of_match_ptr(ov1063x_dt_id),
+		.pm = &ov1063x_pm_ops,
+	},
+	.probe_new = ov1063x_probe,
+	.remove = ov1063x_remove,
+};
+
+module_i2c_driver(ov1063x_i2c_driver);
+
+MODULE_DESCRIPTION("Camera Sensor Driver for OmniVision OV10633/OV10635");
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/ov1063x_regs.h b/drivers/media/i2c/ov1063x_regs.h
new file mode 100644
index 000000000000..43a0ca1d1367
--- /dev/null
+++ b/drivers/media/i2c/ov1063x_regs.h
@@ -0,0 +1,626 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * OmniVision OV1063x Camera Driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
+ * Copyright (C) 2020 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+struct ov1063x_reg {
+	u32	reg;
+	u32	val;
+};
+
+static const struct ov1063x_reg ov1063x_regs_default[] = {
+	/* Register configuration for full resolution : 1280x720 */
+	{ OV1063X_SC_CMMN_MISC_CTRL, 0x02 |
+				     OV1063X_SC_CMMN_MISC_CTRL_CEN_GLOBAL_O },
+	{ OV1063X_SC_CMMN_PAD, 0x02 },
+	{ OV1063X_HORIZ_COLORCORRECT, 0x0c },
+	{ OV1063X_REG_8BIT(0x6901), 0x01 },
+	{ OV1063X_SC_CMMN_SCLK2X_SEL, OV1063X_SC_CMMN_SCLK2X_SEL_DIV4 },
+	{ OV1063X_AEC_PK_MANUAL, OV1063X_AEC_PK_MANUAL_DELAY },
+	{ OV1063X_SC_CMMN_PWDN_CTRL2, 0x20 |
+				      OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG1 |
+				      OV1063X_SC_CMMN_PWDN_CTRL2_RST_DIG2 |
+				      OV1063X_SC_CMMN_PWDN_CTRL2_RST_ISP |
+				      OV1063X_SC_CMMN_PWDN_CTRL2_SEQUENCE },
+	{ OV1063X_SC_CMMN_CORE_CTRL1, 0x03 },
+	/*
+	 * For 15fps
+	 *
+	 * XVCLK: 9MHz
+	 * Pre divider: 1
+	 * Multiplier: 32
+	 * Divider: 8
+	 * SCLK: 36MHz
+	 */
+	{ OV1063X_SC_CMMN_PLL_CTRL0, OV1063X_SC_CMMN_PLL_SCLK_CP(0) |
+				     OV1063X_SC_CMMN_PLL_SCLK_MULTI(32) },
+	{ OV1063X_SC_CMMN_PLL_CTRL1, OV1063X_SC_CMMN_PLL_SCLK_PRE_DIV(0) |
+				     OV1063X_SC_CMMN_PLL_SCLK_CP2(0) |
+				     OV1063X_SC_CMMN_PLL_SCLK_DIV(3) },
+	{ OV1063X_SC_CMMN_PLL_CTRL2, OV1063X_SC_CMMN_PLL_SCLK_CP(0) |
+				     OV1063X_SC_CMMN_PLL_SCLK_MULTI(32) },
+	{ OV1063X_SC_CMMN_PLL_CTRL3, OV1063X_SC_CMMN_PLL_PCLK_BYPASS |
+				     OV1063X_SC_CMMN_PLL_SCLK_PRE_DIV(1) |
+				     OV1063X_SC_CMMN_PLL_SCLK_CP2(0) |
+				     OV1063X_SC_CMMN_PLL_SCLK_DIV(1) },
+	{ OV1063X_ANA_ADC1, 0x74 },
+	{ OV1063X_ANA_ADC2, 0x2b },
+	{ OV1063X_ANA_ANALOG3, 0x00 },
+	{ OV1063X_ANA_ANALOG2, 0x67 },
+	{ OV1063X_ANA_PWC4, 0xba },
+	{ OV1063X_ANA_ADC3, 0x2f },
+	{ OV1063X_ANA_ADC4, 0x00 },
+	{ OV1063X_ANA_PWC1, 0xa8 },
+	{ OV1063X_ANA_PWC2, 0x16 },
+	{ OV1063X_SENSOR_EQ_GOLOW, 0x10 },
+	{ OV1063X_SENSOR_BITSW_GO, 0x0001 },
+	{ OV1063X_FORMAT_CTRL00, OV1063X_FORMAT_UYVY },
+	{ OV1063X_SC_CMMN_PCLK_DIV_CTRL, 1 },
+	{ OV1063X_SC_CMMN_CORE_CTRL_3, OV1063X_SC_CMMN_CORE_CTRL_PCLK_SEC },
+	{ OV1063X_SC_CMMN_CLOCK_SEL, 0x0b },
+	{ OV1063X_SENSOR_RSTGOLOW, 0x0d },
+	{ OV1063X_SENSOR_HLDWIDTH, 0x20 },
+	{ OV1063X_SENSOR_TXWIDTH, 0x15 },
+	{ OV1063X_SENSOR_REG9, 0x28 },
+	{ OV1063X_SENSOR_REGD, 0x00 },
+	{ OV1063X_SENSOR_RSTYZ_GOLOW, 32 },
+	{ OV1063X_SENSOR_REG15, 0x04 },
+	{ OV1063X_TIMING_CTRL1D, OV1063X_TIMING_CTRL1D_WDR },
+	{ OV1063X_TIMING_CTRL1C, 0 },
+	{ OV1063X_REG_8BIT(0x3824), 0x10 },
+	{ OV1063X_TIMING_CTRL15, OV1063X_TIMING_CTRL15_BLACK_LINE_HREF |
+				 OV1063X_TIMING_CTRL15_BLACK_LINES(12) },
+	{ OV1063X_TIMING_X_END_ADDR, 1311 },
+	{ OV1063X_TIMING_X_START_ADDR, 0 },
+	{ OV1063X_TIMING_Y_END_ADDR, 769 },
+	{ OV1063X_TIMING_Y_START_ADDR, 46 },
+	{ OV1063X_TIMING_X_OUTPUT_SIZE, 1280 },
+	{ OV1063X_TIMING_Y_OUTPUT_SIZE, 720 },
+	{ OV1063X_TIMING_HTS, 1782 },
+	{ OV1063X_TIMING_VTS, 748 },
+	{ OV1063X_TIMING_ISP_X_WIN, 8 },
+	{ OV1063X_VSTART_OFFSET, 12 },
+	{ OV1063X_ANA_ARRAY1, 0x60 |
+			      OV1063X_ANA_ARRAY1_FULL |
+			      OV1063X_ANA_ARRAY1_DELAY(3) },
+	{ OV1063X_ISP_RW05, OV1063X_ISP_RW05_SUB_AVG },
+	{ OV1063X_AEC_CTRLD5, 8 * 1024 * 1024 },
+	{ OV1063X_AEC_CTRLD9, 8 * 1024 * 1024 },
+	{ OV1063X_AEC_CTRLE8, 127 },
+	{ OV1063X_AEC_CTRLEA, 127 },
+	{ OV1063X_GAIN_AWB_MAN_GAIN_B_LONG, 128 },
+	{ OV1063X_GAIN_AWB_MAN_GAIN_GB_LONG, 128 },
+	{ OV1063X_GAIN_AWB_MAN_GAIN_GR_LONG, 128 },
+	{ OV1063X_GAIN_AWB_MAN_GAIN_R_LONG, 128 },
+	{ OV1063X_GAIN_AWB_MAN_OFFSET_B_LONG, 0 },
+	{ OV1063X_GAIN_AWB_MAN_OFFSET_GB_LONG, 0 },
+	{ OV1063X_GAIN_AWB_MAN_OFFSET_GR_LONG, 0 },
+	{ OV1063X_GAIN_AWB_MAN_OFFSET_R_LONG, 0 },
+	{ OV1063X_GAIN_AWB_MAN_GAIN_B_SHORT, 128 },
+	{ OV1063X_GAIN_AWB_MAN_GAIN_GB_SHORT, 128 },
+	{ OV1063X_GAIN_AWB_MAN_GAIN_GR_SHORT, 128 },
+	{ OV1063X_GAIN_AWB_MAN_GAIN_R_SHORT, 128 },
+	{ OV1063X_GAIN_AWB_MAN_OFFSET_B_SHORT, 0 },
+	{ OV1063X_GAIN_AWB_MAN_OFFSET_GB_SHORT, 0 },
+	{ OV1063X_GAIN_AWB_MAN_OFFSET_GR_SHORT, 0 },
+	{ OV1063X_GAIN_AWB_MAN_OFFSET_R_SHORT, 0 },
+	{ OV1063X_AEC_CTRLD0, OV1063X_AEC_CTRLD0_R_MAN_EN(0) },
+	{ OV1063X_ISP_RW06, OV1063X_ISP_RW06_YUV_MODE_MAN(2) |
+			    OV1063X_ISP_RW06_YUV_MODE_MAN_EN },
+	{ OV1063X_AEC_CTRL07, 0 },
+	{ OV1063X_CIP_HFREQ_COEF_SHORT, 0x06 },
+	{ OV1063X_CIP_MAX_SHARPEN_LONG, 0x08 },
+	{ OV1063X_CIP_SHARPEN_ALPHA_LONG, 0x12 },
+	{ OV1063X_CIP_SHARPEN_ALPHA_SHORT, 0x12 },
+	{ OV1063X_CIP_UNSHARPEN_MASK_LONG(0), 0x06 },
+	{ OV1063X_CIP_UNSHARPEN_MASK_LONG(1), 0x20 },
+	{ OV1063X_CIP_UNSHARPEN_MASK_SHORT(0), 0x06 },
+	{ OV1063X_CIP_UNSHARPEN_MASK_SHORT(1), 0x20 },
+	{ OV1063X_CIP_MAX_SHARPEN_SHORT, 0x04 },
+	{ OV1063X_LLF_MAX_LOW_LEVEL, 255 },
+	{ OV1063X_AWB_M_X_LONG, 0x76 },
+	{ OV1063X_AWB_M_Y_LONG, 0x47 },
+	{ OV1063X_AWB_L_K_LONG, 0xef },
+	{ OV1063X_AWB_H_K_LONG, 0xc9 },
+	{ OV1063X_AWB_H_LMT_LONG, 0x49 },
+	{ OV1063X_AWB_L_LMT_LONG, 0x30 },
+	{ OV1063X_REG_8BIT(0x558f), 0x67 },
+	{ OV1063X_REG_8BIT(0x5590), 0x3f },
+	{ OV1063X_AWB_DATA_ULMT_LONG, 0xf0 },
+	{ OV1063X_AWB_DATA_LLMT_LONG, 0x10 },
+	{ OV1063X_AWB_M_X_SHORT, 0x6d },
+	{ OV1063X_AWB_M_Y_SHORT, 0x55 },
+	{ OV1063X_AWB_L_K_SHORT, 0xc3 },
+	{ OV1063X_AWB_H_K_SHORT, 0xb5 },
+	{ OV1063X_AWB_H_LMT_SHORT, 0x43 },
+	{ OV1063X_AWB_L_LMT_SHORT, 0x38 },
+	{ OV1063X_REG_8BIT(0x55a8), 0x5f },
+	{ OV1063X_REG_8BIT(0x55a9), 0x4b },
+	{ OV1063X_AWB_DATA_ULMT_SHORT, 0xf0 },
+	{ OV1063X_AWB_DATA_LLMT_SHORT, 0x10 },
+	{ OV1063X_AWB_CT_CTRL1, OV1063X_AWB_CT_CTRL1_GAIN_STEP_NORMAL(1) |
+				OV1063X_AWB_CT_CTRL1_GAIN_STEP_FAST(1) |
+				OV1063X_AWB_CT_CTRL1_SCALE_LONG_2X |
+				0x02 },
+	{ OV1063X_REG_8BIT(0x5300), 0x01 },
+	{ OV1063X_REG_8BIT(0x5301), 0x00 },
+	{ OV1063X_REG_8BIT(0x5302), 0x00 },
+	{ OV1063X_REG_8BIT(0x5303), 0x0e },
+	{ OV1063X_REG_8BIT(0x5304), 0x00 },
+	{ OV1063X_REG_8BIT(0x5305), 0x0e },
+	{ OV1063X_REG_8BIT(0x5306), 0x00 },
+	{ OV1063X_REG_8BIT(0x5307), 0x36 },
+	{ OV1063X_REG_8BIT(0x5308), 0x00 },
+	{ OV1063X_REG_8BIT(0x5309), 0xd9 },
+	{ OV1063X_REG_8BIT(0x530a), 0x00 },
+	{ OV1063X_REG_8BIT(0x530b), 0x0f },
+	{ OV1063X_REG_8BIT(0x530c), 0x00 },
+	{ OV1063X_REG_8BIT(0x530d), 0x2c },
+	{ OV1063X_REG_8BIT(0x530e), 0x00 },
+	{ OV1063X_REG_8BIT(0x530f), 0x59 },
+	{ OV1063X_REG_8BIT(0x5310), 0x00 },
+	{ OV1063X_REG_8BIT(0x5311), 0x7b },
+	{ OV1063X_REG_8BIT(0x5312), 0x00 },
+	{ OV1063X_REG_8BIT(0x5313), 0x22 },
+	{ OV1063X_REG_8BIT(0x5314), 0x00 },
+	{ OV1063X_REG_8BIT(0x5315), 0xd5 },
+	{ OV1063X_REG_8BIT(0x5316), 0x00 },
+	{ OV1063X_REG_8BIT(0x5317), 0x13 },
+	{ OV1063X_REG_8BIT(0x5318), 0x00 },
+	{ OV1063X_REG_8BIT(0x5319), 0x18 },
+	{ OV1063X_REG_8BIT(0x531a), 0x00 },
+	{ OV1063X_REG_8BIT(0x531b), 0x26 },
+	{ OV1063X_REG_8BIT(0x531c), 0x00 },
+	{ OV1063X_REG_8BIT(0x531d), 0xdc },
+	{ OV1063X_REG_8BIT(0x531e), 0x00 },
+	{ OV1063X_REG_8BIT(0x531f), 0x02 },
+	{ OV1063X_REG_8BIT(0x5320), 0x00 },
+	{ OV1063X_REG_8BIT(0x5321), 0x24 },
+	{ OV1063X_REG_8BIT(0x5322), 0x00 },
+	{ OV1063X_REG_8BIT(0x5323), 0x56 },
+	{ OV1063X_REG_8BIT(0x5324), 0x00 },
+	{ OV1063X_REG_8BIT(0x5325), 0x85 },
+	{ OV1063X_REG_8BIT(0x5326), 0x00 },
+	{ OV1063X_REG_8BIT(0x5327), 0x20 },
+	{ OV1063X_AEC_WIN_LEFT_LONG, 320 },
+	{ OV1063X_AEC_WIN_LEFT_SHORT, 320 },
+	{ OV1063X_AEC_WIN_TOP_LONG, 250 },
+	{ OV1063X_AEC_WIN_TOP_SHORT, 250 },
+	{ OV1063X_AEC_WIN_WIDTH_LONG, 640 },
+	{ OV1063X_AEC_WIN_WIDTH_SHORT, 640 },
+	{ OV1063X_AEC_WIN_HEIGHT_LONG, 300 },
+	{ OV1063X_AEC_WIN_HEIGHT_SHORT, 300 },
+	{ OV1063X_AEC_WEIGHT_SHORT(0), 1 },
+	{ OV1063X_AEC_WEIGHT_SHORT(1), 1 },
+	{ OV1063X_AEC_WEIGHT_SHORT(2), 1 },
+	{ OV1063X_AEC_WEIGHT_SHORT(3), 1 },
+	{ OV1063X_AEC_WEIGHT_SHORT(4), 3 },
+	{ OV1063X_AEC_WEIGHT_SHORT(5), 3 },
+	{ OV1063X_AEC_WEIGHT_SHORT(6), 3 },
+	{ OV1063X_AEC_WEIGHT_SHORT(7), 5 },
+	{ OV1063X_AEC_WEIGHT_SHORT(8), 9 },
+	{ OV1063X_AEC_WEIGHT_SHORT(9), 5 },
+	{ OV1063X_AEC_WEIGHT_SHORT(10), 5 },
+	{ OV1063X_AEC_WEIGHT_SHORT(11), 5 },
+	{ OV1063X_AEC_WEIGHT_SHORT(12), 5 },
+	{ OV1063X_AEC_FINAL_SATURATE_THRESH, 128 },
+	{ OV1063X_DNS_NOISE_Y_LIST_LONG(0), 1 },
+	{ OV1063X_DNS_NOISE_Y_LIST_LONG(1), 3 },
+	{ OV1063X_DNS_NOISE_Y_LIST_LONG(2), 6 },
+	{ OV1063X_DNS_NOISE_Y_LIST_LONG(3), 10 },
+	{ OV1063X_DNS_NOISE_Y_LIST_LONG(4), 14 },
+	{ OV1063X_DNS_NOISE_Y_LIST_LONG(5), 18 },
+	{ OV1063X_DNS_NOISE_Y_LIST_LONG(6), 22 },
+	{ OV1063X_DNS_NOISE_UV_LIST_LONG(0), 2 },
+	{ OV1063X_DNS_NOISE_UV_LIST_LONG(1), 4 },
+	{ OV1063X_DNS_NOISE_UV_LIST_LONG(2), 8 },
+	{ OV1063X_DNS_NOISE_UV_LIST_LONG(3), 12 },
+	{ OV1063X_DNS_NOISE_UV_LIST_LONG(4), 18 },
+	{ OV1063X_DNS_NOISE_UV_LIST_LONG(5), 24 },
+	{ OV1063X_DNS_NOISE_UV_LIST_LONG(6), 30 },
+	{ OV1063X_DNS_GBGR_EXTRA_SHORT, 4 },
+	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(0), 1 },
+	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(1), 3 },
+	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(2), 6 },
+	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(3), 10 },
+	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(4), 14 },
+	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(5), 18 },
+	{ OV1063X_DNS_NOISE_Y_LIST_SHORT(6), 22 },
+	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(0), 3 },
+	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(1), 4 },
+	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(2), 8 },
+	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(3), 12 },
+	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(4), 18 },
+	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(5), 24 },
+	{ OV1063X_DNS_NOISE_UV_LIST_SHORT(6), 30 },
+	{ OV1063X_VFIFO_LLEN_FIRS1_SEL, 0x00 }, /* 8-bit YUV mode */
+	{ OV1063X_VFIFO_LINE_LENGTH_MAN, 1905 },
+	{ OV1063X_VFIFO_HSYNC_START_POSITION, 624 },
+	{ OV1063X_VFIFO_HSYNC_CTRL, OV1063X_VFIFO_HSYNC_CTRL_HEADER_WIDTH(0) |
+				    OV1063X_VFIFO_HSYNC_CTRL_TRAILER_WIDTH(0) },
+	{ OV1063X_ROI_CTRL0, OV1063X_ROI_CTRL0_EN_3 |
+			     OV1063X_ROI_CTRL0_EN_2 |
+			     OV1063X_ROI_CTRL0_EN_1 },
+	{ OV1063X_DVP_MOD_SEL, OV1063X_DVP_MOD_SEL_CCIR_F },
+	{ OV1063X_DVP_VSYNC_WIDTH, 1 },
+	{ OV1063X_DVP_HSYVSY_NEG_WIDTH, 0 },
+	{ OV1063X_DVP_VSYNC_MODE, OV1063X_DVP_VSYNC_MODE_VSYNCOUT_SEL(0) },
+	/*
+	 * Non-overlapping HSYNC-VSYNC.
+	 * Therefore do not set the VSYNC delay registers.
+	 */
+	{ OV1063X_DVP_EOF_VSYNC_DELAY, 0 },
+	{ OV1063X_LINE_NUM, 8 },
+	{ OV1063X_BLC_CTRL05, OV1063X_BLC_CTRL05_REMOVE_BLACK_LINE |
+			      OV1063X_BLC_CTRL05_ONE_MAN_OFFSET_MODE },
+	{ OV1063X_START_LINE, 4 },
+	{ OV1063X_BLC_AVG_CTRL1, 0x20 },
+	{ OV1063X_BLC_AVG_CTRL2, 0x22 },
+	{ OV1063X_BLC_OFFSET_TOP_LIMIT, 1948 },
+	{ OV1063X_BLC_CTRL5A, 0x00 },
+	{ OV1063X_FC_R2, 2 },
+	{ OV1063X_SC_CMMN_CORE_CTRL_2, OV1063X_SC_CMMN_CORE_CTRL_CLK_SWITCH },
+	{ OV1063X_STREAM_MODE, OV1063X_STREAM_MODE_ON },
+	{ OV1063X_STREAM_MODE, OV1063X_STREAM_MODE_ON },
+	{ OV1063X_REG_8BIT(0x6f0e), 0x00 },
+	{ OV1063X_REG_8BIT(0x6f0f), 0x00 },
+	{ OV1063X_VFIFO_EMBD_LINE_CTRL, OV1063X_VFIFO_EMBD_LINE_CTRL_SOF_CLR_RAM },
+	{ OV1063X_VFIFO_EMBD_LINE_NUM, 1 },
+	{ OV1063X_REG_8BIT(0x4610), 0x00 },
+	{ OV1063X_REG_8BIT(0x4611), 0x01 },
+	{ OV1063X_REG_8BIT(0x4612), 0x00 },
+	{ OV1063X_REG_8BIT(0x4613), 0x01 },
+	{ OV1063X_VFIFO_LLEN_FIRS1_SEL, 0x00 },
+	{ OV1063X_VFIFO_READ_START, 8 },
+	{ OV1063X_EMB_SIZE_MANU_EN, 0 },
+	{ OV1063X_EMB_SIZE_MANU, 1536 },
+	{ OV1063X_GAIN_AWB_CTRL32, 0 },
+	{ OV1063X_REG_8BIT(0x3510), 0x00 },
+	{ OV1063X_AEC_PK_MAN_DONE, 0 },
+	{ OV1063X_EMB_LINE_EN, 0 },
+	{ OV1063X_REG_8BIT(0x6f0d), 0x00 },
+	{ OV1063X_ISP_RW00, OV1063X_ISP_RW00_COLOR_MATRIX_EN |
+			    OV1063X_ISP_RW00_COLOR_INTERP_EN |
+			    OV1063X_ISP_RW00_DENOISE_EN |
+			    OV1063X_ISP_RW00_WHITE_DPC_EN |
+			    OV1063X_ISP_RW00_BLACK_DPC_EN |
+			    OV1063X_ISP_RW00_AWB_STATS_EN |
+			    OV1063X_ISP_RW00_AWB_GAIN_EN |
+			    OV1063X_ISP_RW00_LSC_EN },
+	{ OV1063X_ISP_RW01, OV1063X_ISP_RW01_DATA_WEIGHT_SYNC_EN |
+			    OV1063X_ISP_RW01_DARK_LEVEL_FILTER_EN |
+			    OV1063X_ISP_RW01_BUFFER_CONTROL_EN |
+			    OV1063X_ISP_RW01_AEC_EN |
+			    OV1063X_ISP_RW01_TONE_MAPPING_EN |
+			    OV1063X_ISP_RW01_NORMALIZE_EN |
+			    OV1063X_ISP_RW01_LONG_SHORT_COMB_EN },
+	{ OV1063X_ISP_RW02, 0xf0 |
+			    OV1063X_ISP_RW02_DIGITAL_GAIN_EN |
+			    OV1063X_ISP_RW02_WINDOW_BORDER_CUT_EN |
+			    OV1063X_ISP_RW02_DITHERING_EN },
+	{ OV1063X_ISP_CTRL3D, 0 },
+	{ OV1063X_AEC_TARGET_NUM, OV1063X_AEC_TARGET_NUM_AA_MODE },
+	{ OV1063X_AEC_LS_SENS_RATIO, 1024 },
+	{ OV1063X_AEC_NONWDR_EN, 0 },
+	{ OV1063X_AEC_NONWDR_SWITCH, 0 },
+	{ OV1063X_AEC_FIXED_RATIO_EN, 0 },
+	{ OV1063X_AEC_GP_MODE_EN, 0 },
+	{ OV1063X_AEC_NIGHT_MODE_EN, 0 },
+	{ OV1063X_AEC_NIGHT_MODE_CTRL, 0 },
+	{ OV1063X_AEC_NONLINEAR_GAIN_EN, 0 },
+	{ OV1063X_AEC_MANU_GAMMA_EN, 0 },
+	{ OV1063X_AEC_HOLD_BAND_EN, 0 },
+	{ OV1063X_AEC_BAND_FILTER_FLAG, OV1063X_AEC_BAND_FILTER_FLAG_0HZ },
+	{ OV1063X_AEC_BAND_FILTER_EN, 0 },
+	{ OV1063X_AEC_BAND_FILTER_SHORT, 0 },
+	{ OV1063X_AEC_LESS_1BAND_EN, 1 },
+	{ OV1063X_AEC_LESS_1BAND_SHORT, 1 },
+	{ OV1063X_AEC_LOG_TARGET(0), 0x8800 },
+	{ OV1063X_AEC_LOG_TARGET(1), 0x8a00 },
+	{ OV1063X_AEC_LOG_TARGET(2), 0x8600 },
+	{ OV1063X_AEC_TARGET_LONG(0), 0x40 },
+	{ OV1063X_AEC_TARGET_LONG(1), 0x50 },
+	{ OV1063X_AEC_TARGET_LONG(2), 0x30 },
+	{ OV1063X_AEC_TARGET_SHORT(0), 0x28 },
+	{ OV1063X_AEC_TARGET_SHORT(1), 0x60 },
+	{ OV1063X_AEC_TARGET_SHORT(2), 0x40 },
+	{ OV1063X_AEC_MAX_SHORT_LE, 0x01380000 },
+	{ OV1063X_AEC_MAX_GAIN_LONG, 255 },
+	{ OV1063X_AEC_MAX_GAIN_SHORT, 64 },
+	{ OV1063X_AEC_MIN_GAIN_LONG, 24 },
+	{ OV1063X_AEC_MIN_GAIN_SHORT, 24 },
+	{ OV1063X_AEC_MAX_EXP_LONG, 11904 },
+	{ OV1063X_AEC_MAX_EXP_SHORT, 11904 },
+	{ OV1063X_AEC_MIN_EXP_LONG, 4 },
+	{ OV1063X_AEC_MIN_EXP_SHORT, 4 },
+	{ OV1063X_AEC_FIXED_RATIO, 0x07 },
+	{ OV1063X_AEC_GP_MODE_RATIO_B2A, 0x20 },
+	{ OV1063X_AEC_GP_MODE_RATIO_C2A, 0x08 },
+	{ OV1063X_AEC_MIN_GAMMA_LIST(0), 512 },
+	{ OV1063X_AEC_MIN_GAMMA_LIST(1), 512 },
+	{ OV1063X_AEC_MIN_GAMMA_LIST(2), 512 },
+	{ OV1063X_AEC_MAX_GAMMA_LIST(0), 308 },
+	{ OV1063X_AEC_MAX_GAMMA_LIST(1), 1024 },
+	{ OV1063X_AEC_MAX_GAMMA_LIST(2), 1536 },
+	{ OV1063X_AEC_DR_LIST(0), 16 },
+	{ OV1063X_AEC_DR_LIST(1), 64 },
+	{ OV1063X_AEC_DR_LIST(2), 128 },
+	{ OV1063X_AEC_BAND_VALUE_60HZ, 3328 },
+	{ OV1063X_AEC_BAND_VALUE_50HZ, 4032 },
+	{ OV1063X_REG_8BIT(0xc4b4), 0x01 },
+	{ OV1063X_REG_8BIT(0xc4b5), 0x01 },
+	{ OV1063X_REG_8BIT(0xc4b6), 0x00 },
+	{ OV1063X_REG_8BIT(0xc4b7), 0x01 },
+	{ OV1063X_REG_8BIT(0xc4b8), 0x00 },
+	{ OV1063X_REG_8BIT(0xc4b9), 0x01 },
+	{ OV1063X_REG_8BIT(0xc4ba), 0x01 },
+	{ OV1063X_REG_8BIT(0xc4bb), 0x00 },
+	{ OV1063X_REG_8BIT(0xc4be), 0x02 },
+	{ OV1063X_REG_8BIT(0xc4bf), 0x33 },
+	{ OV1063X_REG_8BIT(0xc4c8), 0x03 },
+	{ OV1063X_REG_8BIT(0xc4c9), 0xd0 },
+	{ OV1063X_REG_8BIT(0xc4ca), 0x0e },
+	{ OV1063X_REG_8BIT(0xc4cb), 0x00 },
+	{ OV1063X_AWB_SIMPLE_MIN_NUM, 3665 },
+	{ OV1063X_AWB_CT_MIN_NUM, 3665 },
+	{ OV1063X_REG_8BIT(0xc4d0), 0x04 },
+	{ OV1063X_REG_8BIT(0xc4d1), 0x80 },
+	{ OV1063X_REG_8BIT(0xc4e0), 0x04 },
+	{ OV1063X_REG_8BIT(0xc4e1), 0x02 },
+	{ OV1063X_REG_8BIT(0xc4e2), 0x01 },
+	{ OV1063X_REG_8BIT(0xc4e4), 0x10 },
+	{ OV1063X_REG_8BIT(0xc4e5), 0x20 },
+	{ OV1063X_REG_8BIT(0xc4e6), 0x30 },
+	{ OV1063X_REG_8BIT(0xc4e7), 0x40 },
+	{ OV1063X_REG_8BIT(0xc4e8), 0x50 },
+	{ OV1063X_REG_8BIT(0xc4e9), 0x60 },
+	{ OV1063X_REG_8BIT(0xc4ea), 0x70 },
+	{ OV1063X_REG_8BIT(0xc4eb), 0x80 },
+	{ OV1063X_REG_8BIT(0xc4ec), 0x90 },
+	{ OV1063X_REG_8BIT(0xc4ed), 0xa0 },
+	{ OV1063X_REG_8BIT(0xc4ee), 0xb0 },
+	{ OV1063X_REG_8BIT(0xc4ef), 0xc0 },
+	{ OV1063X_REG_8BIT(0xc4f0), 0xd0 },
+	{ OV1063X_REG_8BIT(0xc4f1), 0xe0 },
+	{ OV1063X_REG_8BIT(0xc4f2), 0xf0 },
+	{ OV1063X_REG_8BIT(0xc4f3), 0x80 },
+	{ OV1063X_REG_8BIT(0xc4f4), 0x00 },
+	{ OV1063X_REG_8BIT(0xc4f5), 0x20 },
+	{ OV1063X_REG_8BIT(0xc4f6), 0x02 },
+	{ OV1063X_REG_8BIT(0xc4f7), 0x00 },
+	{ OV1063X_REG_8BIT(0xc4f8), 0x04 },
+	{ OV1063X_REG_8BIT(0xc4f9), 0x0b },
+	{ OV1063X_REG_8BIT(0xc4fa), 0x00 },
+	{ OV1063X_REG_8BIT(0xc4fb), 0x01 },
+	{ OV1063X_REG_8BIT(0xc4fc), 0x01 },
+	{ OV1063X_REG_8BIT(0xc4fd), 0x01 },
+	{ OV1063X_REG_8BIT(0xc4fe), 0x04 },
+	{ OV1063X_REG_8BIT(0xc4ff), 0x02 },
+	{ OV1063X_REG_8BIT(0xc500), 0x68 },
+	{ OV1063X_REG_8BIT(0xc501), 0x74 },
+	{ OV1063X_REG_8BIT(0xc502), 0x70 },
+	{ OV1063X_REG_8BIT(0xc503), 0x80 },
+	{ OV1063X_REG_8BIT(0xc504), 0x05 },
+	{ OV1063X_REG_8BIT(0xc505), 0x80 },
+	{ OV1063X_REG_8BIT(0xc506), 0x03 },
+	{ OV1063X_REG_8BIT(0xc507), 0x80 },
+	{ OV1063X_REG_8BIT(0xc508), 0x01 },
+	{ OV1063X_REG_8BIT(0xc509), 0xc0 },
+	{ OV1063X_REG_8BIT(0xc50a), 0x01 },
+	{ OV1063X_REG_8BIT(0xc50b), 0xa0 },
+	{ OV1063X_REG_8BIT(0xc50c), 0x01 },
+	{ OV1063X_REG_8BIT(0xc50d), 0x2c },
+	{ OV1063X_REG_8BIT(0xc50e), 0x01 },
+	{ OV1063X_REG_8BIT(0xc50f), 0x0a },
+	{ OV1063X_REG_8BIT(0xc510), 0x00 },
+	{ OV1063X_REG_8BIT(0xc511), 0x00 },
+	{ OV1063X_REG_8BIT(0xc512), 0xe5 },
+	{ OV1063X_REG_8BIT(0xc513), 0x14 },
+	{ OV1063X_REG_8BIT(0xc514), 0x04 },
+	{ OV1063X_REG_8BIT(0xc515), 0x00 },
+	{ OV1063X_VTS_ADDR, 840 },
+	{ OV1063X_HTS_ADDR, 1904 },
+	{ OV1063X_REG_8BIT(0xc2e0), 0x00 },
+	{ OV1063X_REG_8BIT(0xc2e1), 0x51 },
+	{ OV1063X_REG_8BIT(0xc2e2), 0x00 },
+	{ OV1063X_REG_8BIT(0xc2e3), 0xd6 },
+	{ OV1063X_REG_8BIT(0xc2e4), 0x01 },
+	{ OV1063X_REG_8BIT(0xc2e5), 0x5e },
+	{ OV1063X_REG_8BIT(0xc2e9), 0x01 },
+	{ OV1063X_REG_8BIT(0xc2ea), 0x7a },
+	{ OV1063X_REG_8BIT(0xc2eb), 0x90 },
+	{ OV1063X_REG_8BIT(0xc2ed), 0x01 },
+	{ OV1063X_REG_8BIT(0xc2ee), 0x7a },
+	{ OV1063X_REG_8BIT(0xc2ef), 0x64 },
+	{ OV1063X_REG_8BIT(0xc308), 0x00 },
+	{ OV1063X_REG_8BIT(0xc309), 0x00 },
+	{ OV1063X_REG_8BIT(0xc30a), 0x00 },
+	{ OV1063X_REG_8BIT(0xc30c), 0x00 },
+	{ OV1063X_REG_8BIT(0xc30d), 0x01 },
+	{ OV1063X_REG_8BIT(0xc30e), 0x00 },
+	{ OV1063X_REG_8BIT(0xc30f), 0x00 },
+	{ OV1063X_REG_8BIT(0xc310), 0x01 },
+	{ OV1063X_REG_8BIT(0xc311), 0x60 },
+	{ OV1063X_REG_8BIT(0xc312), 0xff },
+	{ OV1063X_REG_8BIT(0xc313), 0x08 },
+	{ OV1063X_REG_8BIT(0xc314), 0x01 },
+	{ OV1063X_REG_8BIT(0xc315), 0x7f },
+	{ OV1063X_REG_8BIT(0xc316), 0xff },
+	{ OV1063X_REG_8BIT(0xc317), 0x0b },
+	{ OV1063X_REG_8BIT(0xc318), 0x00 },
+	{ OV1063X_REG_8BIT(0xc319), 0x0c },
+	{ OV1063X_REG_8BIT(0xc31a), 0x00 },
+	{ OV1063X_REG_8BIT(0xc31b), 0xe0 },
+	{ OV1063X_REG_8BIT(0xc31c), 0x00 },
+	{ OV1063X_REG_8BIT(0xc31d), 0x14 },
+	{ OV1063X_REG_8BIT(0xc31e), 0x00 },
+	{ OV1063X_REG_8BIT(0xc31f), 0xc5 },
+	{ OV1063X_REG_8BIT(0xc320), 0xff },
+	{ OV1063X_REG_8BIT(0xc321), 0x4b },
+	{ OV1063X_REG_8BIT(0xc322), 0xff },
+	{ OV1063X_REG_8BIT(0xc323), 0xf0 },
+	{ OV1063X_REG_8BIT(0xc324), 0xff },
+	{ OV1063X_REG_8BIT(0xc325), 0xe8 },
+	{ OV1063X_REG_8BIT(0xc326), 0x00 },
+	{ OV1063X_REG_8BIT(0xc327), 0x46 },
+	{ OV1063X_REG_8BIT(0xc328), 0xff },
+	{ OV1063X_REG_8BIT(0xc329), 0xd2 },
+	{ OV1063X_REG_8BIT(0xc32a), 0xff },
+	{ OV1063X_REG_8BIT(0xc32b), 0xe4 },
+	{ OV1063X_REG_8BIT(0xc32c), 0xff },
+	{ OV1063X_REG_8BIT(0xc32d), 0xbb },
+	{ OV1063X_REG_8BIT(0xc32e), 0x00 },
+	{ OV1063X_REG_8BIT(0xc32f), 0x61 },
+	{ OV1063X_REG_8BIT(0xc330), 0xff },
+	{ OV1063X_REG_8BIT(0xc331), 0xf9 },
+	{ OV1063X_REG_8BIT(0xc332), 0x00 },
+	{ OV1063X_REG_8BIT(0xc333), 0xd9 },
+	{ OV1063X_REG_8BIT(0xc334), 0x00 },
+	{ OV1063X_REG_8BIT(0xc335), 0x2e },
+	{ OV1063X_REG_8BIT(0xc336), 0x00 },
+	{ OV1063X_REG_8BIT(0xc337), 0xb1 },
+	{ OV1063X_REG_8BIT(0xc338), 0xff },
+	{ OV1063X_REG_8BIT(0xc339), 0x64 },
+	{ OV1063X_REG_8BIT(0xc33a), 0xff },
+	{ OV1063X_REG_8BIT(0xc33b), 0xeb },
+	{ OV1063X_REG_8BIT(0xc33c), 0xff },
+	{ OV1063X_REG_8BIT(0xc33d), 0xe8 },
+	{ OV1063X_REG_8BIT(0xc33e), 0x00 },
+	{ OV1063X_REG_8BIT(0xc33f), 0x48 },
+	{ OV1063X_REG_8BIT(0xc340), 0xff },
+	{ OV1063X_REG_8BIT(0xc341), 0xd0 },
+	{ OV1063X_REG_8BIT(0xc342), 0xff },
+	{ OV1063X_REG_8BIT(0xc343), 0xed },
+	{ OV1063X_REG_8BIT(0xc344), 0xff },
+	{ OV1063X_REG_8BIT(0xc345), 0xad },
+	{ OV1063X_REG_8BIT(0xc346), 0x00 },
+	{ OV1063X_REG_8BIT(0xc347), 0x66 },
+	{ OV1063X_REG_8BIT(0xc348), 0x01 },
+	{ OV1063X_REG_8BIT(0xc349), 0x00 },
+	{ OV1063X_REG_8BIT(0x6700), 0x04 },
+	{ OV1063X_REG_8BIT(0x6701), 0x7b },
+	{ OV1063X_REG_8BIT(0x6702), 0xfd },
+	{ OV1063X_REG_8BIT(0x6703), 0xf9 },
+	{ OV1063X_REG_8BIT(0x6704), 0x3d },
+	{ OV1063X_REG_8BIT(0x6705), 0x71 },
+	{ OV1063X_TPM_CTRL0, 0x70 | OV1063X_TPM_CTRL0_CLK_DIV(1) },
+	{ OV1063X_REG_8BIT(0x6708), 0x05 },
+	{ OV1063X_REG_8BIT(0x3822), 0x50 },
+	{ OV1063X_PARI_ADDR_MIN, 0x6f00 },
+	{ OV1063X_PARI_ADDR_MAX, 0x6f00 },
+	{ OV1063X_GROUP_WRITER_COMMAND, OV1063X_GROUP_WRITER_COMMAND_EN },
+};
+
+static const struct ov1063x_reg ov1063x_regs_bt656[] = {
+	{ OV1063X_DVP_MOD_SEL, OV1063X_DVP_MOD_SEL_CCIR_656 },
+	{ OV1063X_FORMAT_YMAX, 1016 },
+	{ OV1063X_FORMAT_YMIN, 8 },
+	{ OV1063X_FORMAT_UMAX, 1016 },
+	{ OV1063X_FORMAT_UMIN, 8 },
+};
+
+static const struct ov1063x_reg ov1063x_regs_bt656_10bit[] = {
+	{ OV1063X_DVP_MOD_SEL, OV1063X_DVP_MOD_SEL_CCIR_656 },
+	{ OV1063X_FORMAT_YMAX, 1022 },
+	{ OV1063X_FORMAT_YMIN, 2 },
+	{ OV1063X_FORMAT_UMAX, 1022 },
+	{ OV1063X_FORMAT_UMIN, 2 },
+};
+
+static const struct ov1063x_reg ov1063x_regs_vert_no_sub[] = {
+	{ OV1063X_TIMING_CTRL1C, 0 },
+	{ OV1063X_VSTART_OFFSET, 12 },
+	{ OV1063X_START_LINE, 4 },
+	{ OV1063X_LINE_NUM, 8 },
+	{ OV1063X_BLC_AVG_CTRL1, 0x20 },
+	{ OV1063X_BLC_AVG_CTRL2, 0x22 },
+	{ OV1063X_REG_8BIT(0x6e47), 0x0c },
+	{ OV1063X_REG_8BIT(0x4610), 0x05 },
+	{ OV1063X_REG_8BIT(0x4613), 0x10 },
+};
+
+static const struct ov1063x_reg ov1063x_regs_vert_sub2[] = {
+	{ OV1063X_TIMING_CTRL1C, OV1063X_TIMING_CTRL1C_VSUB2 },
+	{ OV1063X_VSTART_OFFSET, 6 },
+	{ OV1063X_START_LINE, 2 },
+	{ OV1063X_LINE_NUM, 2 },
+	{ OV1063X_BLC_AVG_CTRL1, 0x10 },
+	{ OV1063X_BLC_AVG_CTRL2, 0x11 },
+	{ OV1063X_REG_8BIT(0x6e47), 0x06 },
+	{ OV1063X_REG_8BIT(0x4610), 0x03 },
+	{ OV1063X_REG_8BIT(0x4613), 0x0a },
+};
+
+/*
+ * Datasheet highlight the following sequence to enable and disable
+ * Test Pattern mode i.e. colobar
+ */
+static const struct ov1063x_reg ov1063x_regs_colorbar_enable[] = {
+	{ OV1063X_GAIN_AWB_CTRL32, OV1063X_GAIN_AWB_CTRL32_MANUAL_EN },
+	{ OV1063X_AEC_CTRLD0, OV1063X_AEC_CTRLD0_R_MAN_EN(1) },
+	{ OV1063X_REG_8BIT(0x5300), 0x01 }, { OV1063X_REG_8BIT(0x5301), 0x00 },
+	{ OV1063X_REG_8BIT(0x5302), 0x00 }, { OV1063X_REG_8BIT(0x5303), 0x00 },
+	{ OV1063X_REG_8BIT(0x5304), 0x00 }, { OV1063X_REG_8BIT(0x5305), 0x00 },
+	{ OV1063X_REG_8BIT(0x5306), 0x00 }, { OV1063X_REG_8BIT(0x5307), 0x00 },
+	{ OV1063X_REG_8BIT(0x5308), 0x01 }, { OV1063X_REG_8BIT(0x5309), 0x00 },
+	{ OV1063X_REG_8BIT(0x530a), 0x00 }, { OV1063X_REG_8BIT(0x530b), 0x00 },
+	{ OV1063X_REG_8BIT(0x530c), 0x00 }, { OV1063X_REG_8BIT(0x530d), 0x00 },
+	{ OV1063X_REG_8BIT(0x530e), 0x00 }, { OV1063X_REG_8BIT(0x530f), 0x00 },
+	{ OV1063X_REG_8BIT(0x5310), 0x01 }, { OV1063X_REG_8BIT(0x5311), 0x00 },
+	{ OV1063X_REG_8BIT(0x5312), 0x00 }, { OV1063X_REG_8BIT(0x5313), 0x00 },
+	{ OV1063X_REG_8BIT(0x5314), 0x01 }, { OV1063X_REG_8BIT(0x5315), 0x00 },
+	{ OV1063X_REG_8BIT(0x5316), 0x00 }, { OV1063X_REG_8BIT(0x5317), 0x00 },
+	{ OV1063X_REG_8BIT(0x5318), 0x00 }, { OV1063X_REG_8BIT(0x5319), 0x00 },
+	{ OV1063X_REG_8BIT(0x531a), 0x00 }, { OV1063X_REG_8BIT(0x531b), 0x00 },
+	{ OV1063X_REG_8BIT(0x531c), 0x01 }, { OV1063X_REG_8BIT(0x531d), 0x00 },
+	{ OV1063X_REG_8BIT(0x531e), 0x00 }, { OV1063X_REG_8BIT(0x531f), 0x00 },
+	{ OV1063X_REG_8BIT(0x5320), 0x00 }, { OV1063X_REG_8BIT(0x5321), 0x00 },
+	{ OV1063X_REG_8BIT(0x5322), 0x00 }, { OV1063X_REG_8BIT(0x5323), 0x00 },
+	{ OV1063X_REG_8BIT(0x5324), 0x01 }, { OV1063X_REG_8BIT(0x5325), 0x00 },
+	{ OV1063X_REG_8BIT(0x5326), 0x00 }, { OV1063X_REG_8BIT(0x5327), 0x00 },
+	{ OV1063X_REG_8BIT(0xc2ea), 0x80 }, { OV1063X_REG_8BIT(0xc2eb), 0x80 },
+	{ OV1063X_ISP_RW00, OV1063X_ISP_RW00_COLOR_INTERP_EN |
+			    OV1063X_ISP_RW00_DENOISE_EN |
+			    OV1063X_ISP_RW00_WHITE_DPC_EN |
+			    OV1063X_ISP_RW00_BLACK_DPC_EN |
+			    OV1063X_ISP_RW00_LSC_EN },
+};
+
+static const struct ov1063x_reg ov1063x_regs_colorbar_disable[] = {
+	{ OV1063X_ISP_CTRL3D, 0 },
+	{ OV1063X_ISP_CTRL3E, 0 },
+	{ OV1063X_GAIN_AWB_CTRL32, 0 },
+	{ OV1063X_AEC_CTRLD0, OV1063X_AEC_CTRLD0_R_MAN_EN(0) },
+	{ OV1063X_REG_8BIT(0x5300), 0x01 }, { OV1063X_REG_8BIT(0x5301), 0x00 },
+	{ OV1063X_REG_8BIT(0x5302), 0x00 }, { OV1063X_REG_8BIT(0x5303), 0x0e },
+	{ OV1063X_REG_8BIT(0x5304), 0x00 }, { OV1063X_REG_8BIT(0x5305), 0x0e },
+	{ OV1063X_REG_8BIT(0x5306), 0x00 }, { OV1063X_REG_8BIT(0x5307), 0x36 },
+	{ OV1063X_REG_8BIT(0x5308), 0x00 }, { OV1063X_REG_8BIT(0x5309), 0xd9 },
+	{ OV1063X_REG_8BIT(0x530a), 0x00 }, { OV1063X_REG_8BIT(0x530b), 0x0f },
+	{ OV1063X_REG_8BIT(0x530c), 0x00 }, { OV1063X_REG_8BIT(0x530d), 0x2c },
+	{ OV1063X_REG_8BIT(0x530e), 0x00 }, { OV1063X_REG_8BIT(0x530f), 0x59 },
+	{ OV1063X_REG_8BIT(0x5310), 0x00 }, { OV1063X_REG_8BIT(0x5311), 0x7b },
+	{ OV1063X_REG_8BIT(0x5312), 0x00 }, { OV1063X_REG_8BIT(0x5313), 0x22 },
+	{ OV1063X_REG_8BIT(0x5314), 0x00 }, { OV1063X_REG_8BIT(0x5315), 0xd5 },
+	{ OV1063X_REG_8BIT(0x5316), 0x00 }, { OV1063X_REG_8BIT(0x5317), 0x13 },
+	{ OV1063X_REG_8BIT(0x5318), 0x00 }, { OV1063X_REG_8BIT(0x5319), 0x18 },
+	{ OV1063X_REG_8BIT(0x531a), 0x00 }, { OV1063X_REG_8BIT(0x531b), 0x26 },
+	{ OV1063X_REG_8BIT(0x531c), 0x00 }, { OV1063X_REG_8BIT(0x531d), 0xdc },
+	{ OV1063X_REG_8BIT(0x531e), 0x00 }, { OV1063X_REG_8BIT(0x531f), 0x02 },
+	{ OV1063X_REG_8BIT(0x5320), 0x00 }, { OV1063X_REG_8BIT(0x5321), 0x24 },
+	{ OV1063X_REG_8BIT(0x5322), 0x00 }, { OV1063X_REG_8BIT(0x5323), 0x56 },
+	{ OV1063X_REG_8BIT(0x5324), 0x00 }, { OV1063X_REG_8BIT(0x5325), 0x85 },
+	{ OV1063X_REG_8BIT(0x5326), 0x00 }, { OV1063X_REG_8BIT(0x5327), 0x20 },
+	{ OV1063X_REG_8BIT(0xc2ea), 0x7a }, { OV1063X_REG_8BIT(0xc2eb), 0x90 },
+	{ OV1063X_ISP_RW00, OV1063X_ISP_RW00_COLOR_MATRIX_EN |
+			    OV1063X_ISP_RW00_COLOR_INTERP_EN |
+			    OV1063X_ISP_RW00_DENOISE_EN |
+			    OV1063X_ISP_RW00_WHITE_DPC_EN |
+			    OV1063X_ISP_RW00_BLACK_DPC_EN |
+			    OV1063X_ISP_RW00_AWB_STATS_EN |
+			    OV1063X_ISP_RW00_AWB_GAIN_EN |
+			    OV1063X_ISP_RW00_LSC_EN },
+};