+ .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)
+{
+ unsigned int best_pclk = UINT_MAX;
+ unsigned int best_pre_div_x2;
+ unsigned int best_mult;
+ unsigned int best_div;
+ unsigned int best_hts;
+ 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, stored in
+ * registers as the index in this list of 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.
+ */
+
+ /*
+ * 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_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;
+
+ 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_x2 = pre_div_x2;
+ best_mult = mult;
+ best_div = div;
+ }
+ }
+ }
+ }
+
+ 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_x2 < 4 ? best_pre_div_x2 - 2
+ : best_pre_div_x2 / 2;
+ 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 || priv->streaming == OV1063X_STREAM_STARTING) {
+ /*
+ * Only write the full settings when the test pattern was
+ * disabled or when we start streaming, 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 == OV1063X_STREAM_OFF)
+ 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 = OV1063X_STREAM_OFF;
+ 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 = OV1063X_STREAM_STARTING;
+
+ 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);
+
+ priv->streaming = OV1063X_STREAM_ON;
+
+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 = OV1063X_STREAM_OFF;
+ }
+
+ mutex_unlock(priv->hdl.lock);
+
+ return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+__ov1063x_get_pad_format(struct ov1063x_priv *priv,
+ struct v4l2_subdev_state *state,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&priv->subdev, state, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &priv->format;
+ default:
+ return NULL;
+ }
+}
+
+static int ov1063x_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ u32 which = state ? 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, state, 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_state *state,
+ 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_state *state,
+ 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_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov1063x_priv *priv = to_ov1063x(sd);
+
+ fmt->format = *__ov1063x_get_pad_format(priv, state, fmt->pad,
+ fmt->which);
+
+ return 0;
+}
+
+static int ov1063x_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ 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, state, fmt->pad, fmt->which);
+
+ mutex_lock(priv->hdl.lock);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+ priv->streaming != OV1063X_STREAM_OFF) {
+ 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;
+ }
+
+ 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 v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov1063x_priv *priv = to_ov1063x(sd);
+
+ 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");
diff --git a/drivers/media/i2c/ov1063x_regs.h b/drivers/media/i2c/ov1063x_regs.h
new file mode 100644
index 000000000000..7622de5c9069
--- /dev/null
+++ b/drivers/media/i2c/ov1063x_regs.h
@@ -0,0 +1,627 @@
+/* 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, 0x0a | OV1063X_SC_CMMN_CLOCK_SEL_SCLK2X },
+ { 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_TIMING_CTRL24, 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_EMB_START_PCNT, 1 },
+ { OV1063X_EMB_START_LCNT, 1 },
+ { 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, OV1063X_ISP_RW02_OTP_MANUAL_OFFSET_EN |
+ OV1063X_ISP_RW02_OTP_EN |
+ OV1063X_ISP_RW02_INTER_FRAME_CALC |
+ OV1063X_ISP_RW02_CT_AWB_EN |
+ 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_TPM_SLOPE(0), 4 },
+ { OV1063X_TPM_SLOPE(1), 123 },
+ { OV1063X_TPM_OFFSET(0), 253 },
+ { OV1063X_TPM_OFFSET(1), 249 },
+ { OV1063X_TPM_OFFSET(2), 61 },
+ { OV1063X_TPM_OFFSET(3), 113 },
+ { OV1063X_TPM_CTRL6, 0x70 | OV1063X_TPM_CTRL6_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_EMB_START_PCNT, 1281 },
+ { OV1063X_EMB_START_LCNT, 16 },
+};
+
+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_EMB_START_PCNT, 769 },
+ { OV1063X_EMB_START_LCNT, 10 },
+};
+
+/*
+ * 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 },
+};