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@xxxxxx> Signed-off-by: Benoit Parrot <bparrot@xxxxxx> Signed-off-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> --- 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@xxxxxxxxxxxxxxx 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@xxxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxxxx> + */ + +#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@xxxxxxxxxxxxxxxx> + */ + +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 }, +}; -- Regards, Laurent Pinchart