Re: [PATCH resend 3/5] media: ov2680: Add vblank control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Hans,

Thanks for re-posting this.

On Mon, Apr 15, 2024 at 11:37:02AM +0200, Hans de Goede wrote:
> Add vblank control to allow changing the framerate /
> higher exposure values.
> 
> Reviewed-by: Kieran Bingham <kieran.bingham@xxxxxxxxxxxxxxxx>
> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx>
> ---
>  drivers/media/i2c/ov2680.c | 47 ++++++++++++++++++++++++++++++++------
>  1 file changed, 40 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
> index 6c3d7862b2aa..d44e1934b25a 100644
> --- a/drivers/media/i2c/ov2680.c
> +++ b/drivers/media/i2c/ov2680.c
> @@ -75,6 +75,8 @@
>  #define OV2680_ACTIVE_START_TOP			8
>  #define OV2680_MIN_CROP_WIDTH			2
>  #define OV2680_MIN_CROP_HEIGHT			2
> +#define OV2680_MIN_VBLANK			4
> +#define OV2680_MAX_VBLANK			0xffff
>  
>  /* Fixed pre-div of 1/2 */
>  #define OV2680_PLL_PREDIV0			2
> @@ -84,7 +86,7 @@
>  
>  /* 66MHz pixel clock: 66MHz / 1704 * 1294 = 30fps */
>  #define OV2680_PIXELS_PER_LINE			1704
> -#define OV2680_LINES_PER_FRAME			1294
> +#define OV2680_LINES_PER_FRAME_30FPS		1294
>  
>  /* Max exposure time is VTS - 8 */
>  #define OV2680_INTEGRATION_TIME_MARGIN		8
> @@ -127,6 +129,7 @@ struct ov2680_ctrls {
>  	struct v4l2_ctrl *test_pattern;
>  	struct v4l2_ctrl *link_freq;
>  	struct v4l2_ctrl *pixel_rate;
> +	struct v4l2_ctrl *vblank;
>  };
>  
>  struct ov2680_mode {
> @@ -394,8 +397,7 @@ static int ov2680_set_mode(struct ov2680_dev *sensor)
>  		  sensor->mode.v_output_size, &ret);
>  	cci_write(sensor->regmap, OV2680_REG_TIMING_HTS,
>  		  OV2680_PIXELS_PER_LINE, &ret);
> -	cci_write(sensor->regmap, OV2680_REG_TIMING_VTS,
> -		  OV2680_LINES_PER_FRAME, &ret);
> +	/* VTS gets set by the vblank ctrl */
>  	cci_write(sensor->regmap, OV2680_REG_ISP_X_WIN, 0, &ret);
>  	cci_write(sensor->regmap, OV2680_REG_ISP_Y_WIN, 0, &ret);
>  	cci_write(sensor->regmap, OV2680_REG_X_INC, inc, &ret);
> @@ -469,6 +471,15 @@ static int ov2680_exposure_set(struct ov2680_dev *sensor, u32 exp)
>  			 NULL);
>  }
>  
> +static void ov2680_exposure_update_range(struct ov2680_dev *sensor)
> +{
> +	int exp_max = sensor->mode.fmt.height + sensor->ctrls.vblank->val -
> +		      OV2680_INTEGRATION_TIME_MARGIN;
> +
> +	__v4l2_ctrl_modify_range(sensor->ctrls.exposure, 0, exp_max,
> +				 1, exp_max);

__v4l2_ctrl_modify_range() may fail.

> +}
> +
>  static int ov2680_stream_enable(struct ov2680_dev *sensor)
>  {
>  	int ret;
> @@ -635,7 +646,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
>  	struct v4l2_mbus_framefmt *try_fmt;
>  	const struct v4l2_rect *crop;
>  	unsigned int width, height;
> -	int ret = 0;
> +	int def, max, ret = 0;
>  
>  	crop = __ov2680_get_pad_crop(sensor, sd_state, format->pad,
>  				     format->which);
> @@ -664,6 +675,15 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
>  	sensor->mode.fmt = format->format;
>  	ov2680_calc_mode(sensor);
>  
> +	/* vblank range is height dependent adjust and reset to default */
> +	max = OV2680_MAX_VBLANK - height;
> +	def = OV2680_LINES_PER_FRAME_30FPS - height;
> +	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV2680_MIN_VBLANK, max,
> +				 1, def);
> +	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, def);

And so may __v4l2_ctrl_s_ctrl().

> +	/* exposure range depends on vts which may have changed */
> +	ov2680_exposure_update_range(sensor);
> +
>  unlock:
>  	mutex_unlock(&sensor->lock);
>  
> @@ -833,6 +853,10 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
>  	struct ov2680_dev *sensor = to_ov2680_dev(sd);
>  	int ret;
>  
> +	/* Update exposure range on vblank changes */
> +	if (ctrl->id == V4L2_CID_VBLANK)
> +		ov2680_exposure_update_range(sensor);
> +
>  	/* Only apply changes to the controls if the device is powered up */
>  	if (!pm_runtime_get_if_in_use(sensor->sd.dev)) {
>  		ov2680_set_bayer_order(sensor, &sensor->mode.fmt);
> @@ -855,6 +879,10 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
>  	case V4L2_CID_TEST_PATTERN:
>  		ret = ov2680_test_pattern_set(sensor, ctrl->val);
>  		break;
> +	case V4L2_CID_VBLANK:
> +		ret = cci_write(sensor->regmap, OV2680_REG_TIMING_VTS,
> +				sensor->mode.fmt.height + ctrl->val, NULL);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  		break;
> @@ -913,8 +941,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
>  	const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops;
>  	struct ov2680_ctrls *ctrls = &sensor->ctrls;
>  	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
> -	int exp_max = OV2680_LINES_PER_FRAME - OV2680_INTEGRATION_TIME_MARGIN;
> -	int ret = 0;
> +	int def, max, ret = 0;
>  
>  	v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_subdev_ops);
>  	sensor->sd.internal_ops = &ov2680_internal_ops;
> @@ -939,8 +966,9 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
>  					ARRAY_SIZE(test_pattern_menu) - 1,
>  					0, 0, test_pattern_menu);
>  
> +	max = OV2680_LINES_PER_FRAME_30FPS - OV2680_INTEGRATION_TIME_MARGIN;
>  	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
> -					    0, exp_max, 1, exp_max);
> +					    0, max, 1, max);
>  
>  	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
>  					0, 1023, 1, 250);
> @@ -951,6 +979,11 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
>  					      0, sensor->pixel_rate,
>  					      1, sensor->pixel_rate);
>  
> +	max = OV2680_MAX_VBLANK - OV2680_DEFAULT_HEIGHT;
> +	def = OV2680_LINES_PER_FRAME_30FPS - OV2680_DEFAULT_HEIGHT;
> +	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
> +					  OV2680_MIN_VBLANK, max, 1, def);
> +
>  	if (hdl->error) {
>  		ret = hdl->error;
>  		goto cleanup_entity;

-- 
Kind regards,

Sakari Ailus




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux