@@ -73,11 +73,10 @@
#define IMX219_REG_FRM_LENGTH CCI_REG16(0x0160)
#define IMX219_FLL_MAX 0xffff
#define IMX219_VBLANK_MIN 32
+#define IMX219_REG_LINE_LENGTH CCI_REG16(0x0162)
+#define IMX219_LLP_MIN 0x0d78
+#define IMX219_LLP_MAX 0x7ff0
-/* HBLANK control - read only */
-#define IMX219_PPL_DEFAULT 3448
-
-#define IMX219_REG_LINE_LENGTH_A CCI_REG16(0x0162)
#define IMX219_REG_X_ADD_STA_A CCI_REG16(0x0164)
#define IMX219_REG_X_ADD_END_A CCI_REG16(0x0166)
#define IMX219_REG_Y_ADD_STA_A CCI_REG16(0x0168)
@@ -191,7 +190,7 @@ static const struct cci_reg_sequence imx219_common_regs[] = {
{ CCI_REG8(0x479b), 0x0e },
/* Frame Bank Register Group "A" */
- { IMX219_REG_LINE_LENGTH_A, 3448 },
+ { IMX219_REG_LINE_LENGTH, IMX219_LLP_MIN },
{ IMX219_REG_X_ODD_INC_A, 1 },
{ IMX219_REG_Y_ODD_INC_A, 1 },
@@ -420,6 +419,10 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
cci_write(imx219->regmap, IMX219_REG_FRM_LENGTH,
format->height + ctrl->val, &ret);
break;
+ case V4L2_CID_HBLANK:
+ cci_write(imx219->regmap, IMX219_REG_LINE_LENGTH,
+ format->width + ctrl->val, &ret);
+ break;
case V4L2_CID_TEST_PATTERN_RED:
cci_write(imx219->regmap, IMX219_REG_TESTP_RED,
ctrl->val, &ret);
@@ -465,7 +468,7 @@ static int imx219_init_controls(struct imx219 *imx219)
const struct imx219_mode *mode = &supported_modes[0];
struct v4l2_ctrl_handler *ctrl_hdlr;
struct v4l2_fwnode_device_properties props;
- int exposure_max, exposure_def, hblank;
+ int exposure_max, exposure_def;
int i, ret;
ctrl_hdlr = &imx219->ctrl_handler;
@@ -489,17 +492,16 @@ static int imx219_init_controls(struct imx219 *imx219)
if (imx219->link_freq)
imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- /* Initial vblank/hblank/exposure parameters based on current mode */
+ /* Initial blanking and exposure. Limits are updated during set_fmt */
imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
IMX219_FLL_MAX - mode->height, 1,
mode->vts_def - mode->height);
- hblank = IMX219_PPL_DEFAULT - mode->width;
imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
- V4L2_CID_HBLANK, hblank, hblank,
- 1, hblank);
- if (imx219->hblank)
- imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ V4L2_CID_HBLANK,
+ IMX219_LLP_MIN - mode->width,
+ IMX219_LLP_MAX - mode->width, 1,
+ IMX219_LLP_MIN - mode->width);
exposure_max = mode->vts_def - 4;
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
exposure_max : IMX219_EXPOSURE_DEFAULT;
@@ -815,6 +817,10 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
unsigned int bin_h, bin_v;
+ u32 prev_line_len;
+
+ format = v4l2_subdev_state_get_format(state, 0);
+ prev_line_len = format->width + imx219->hblank->val;
mode = v4l2_find_nearest_size(supported_modes,
ARRAY_SIZE(supported_modes),
@@ -822,8 +828,6 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
-
- format = v4l2_subdev_state_get_format(state, 0);
*format = fmt->format;
/*
@@ -859,13 +863,18 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
exposure_max, imx219->exposure->step,
exposure_def);
/*
- * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
- * depends on mode->width only, and is not changeble in any
- * way other than changing the mode.
+ * Retain PPL setting from previous mode so that the
+ * line time does not change on a mode change.
+ * Limits have to be recomputed as the controls define
+ * the blanking only, so PPL values need to have the
+ * mode width subtracted.
*/
- hblank = IMX219_PPL_DEFAULT - mode->width;
- __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
- hblank);
+ hblank = prev_line_len - mode->width;
+ __v4l2_ctrl_modify_range(imx219->hblank,
+ IMX219_LLP_MIN - mode->width,
+ IMX219_LLP_MAX - mode->width, 1,
+ IMX219_LLP_MIN - mode->width);
+ __v4l2_ctrl_s_ctrl(imx219->hblank, hblank);
}
return 0;