diff mbox series

[v2,5/7] media: i2c: imx219: Use subdev active state

Message ID 20230710155203.92366-6-jacopo.mondi@ideasonboard.com
State Accepted
Commit e8a5b1df000e1a23c04dadbe99621441e0889f88
Headers show
Series [v2,1/7] media: i2c: imx219: Rename mbus codes array | expand

Commit Message

Jacopo Mondi July 10, 2023, 3:52 p.m. UTC
Port the imx219 sensor driver to use the subdev active state.

Move all the format configuration to the subdevice state and simplify
the format handling, locking and initialization.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/i2c/imx219.c | 179 ++++++++++---------------------------
 1 file changed, 48 insertions(+), 131 deletions(-)

Comments

Umang Jain July 30, 2023, 9:26 p.m. UTC | #1
Hi Jacopo ,

On 7/10/23 9:22 PM, Jacopo Mondi wrote:
> Port the imx219 sensor driver to use the subdev active state.
>
> Move all the format configuration to the subdevice state and simplify
> the format handling, locking and initialization.
>
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>   drivers/media/i2c/imx219.c | 179 ++++++++++---------------------------
>   1 file changed, 48 insertions(+), 131 deletions(-)
>
> diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
> index 6963e24e1bc2..73e06583d651 100644
> --- a/drivers/media/i2c/imx219.c
> +++ b/drivers/media/i2c/imx219.c
> @@ -460,8 +460,6 @@ struct imx219 {
>   	struct v4l2_subdev sd;
>   	struct media_pad pad;
>   
> -	struct v4l2_mbus_framefmt fmt;
> -
>   	struct clk *xclk; /* system clock to IMX219 */
>   	u32 xclk_freq;
>   
> @@ -481,12 +479,6 @@ struct imx219 {
>   	/* Current mode */
>   	const struct imx219_mode *mode;
>   
> -	/*
> -	 * Mutex for serialized access:
> -	 * Protect sensor module set pad format and start/stop streaming safely.
> -	 */
> -	struct mutex mutex;
> -
>   	/* Streaming on/off */
>   	bool streaming;
>   
> @@ -576,8 +568,6 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
>   {
>   	unsigned int i;
>   
> -	lockdep_assert_held(&imx219->mutex);
> -
>   	for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
>   		if (imx219_mbus_formats[i] == code)
>   			break;
> @@ -591,20 +581,6 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
>   	return imx219_mbus_formats[i];
>   }
>   
> -static void imx219_set_default_format(struct imx219 *imx219)
> -{
> -	struct v4l2_mbus_framefmt *fmt;
> -
> -	fmt = &imx219->fmt;
> -	fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
> -	fmt->colorspace = V4L2_COLORSPACE_RAW;
> -	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
> -	fmt->width = supported_modes[0].width;
> -	fmt->height = supported_modes[0].height;
> -	fmt->field = V4L2_FIELD_NONE;
> -	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
> -}
> -
>   static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
>   {
>   	struct imx219 *imx219 =
> @@ -701,9 +677,6 @@ static int imx219_init_cfg(struct v4l2_subdev *sd,
>   	struct v4l2_mbus_framefmt *format;
>   	struct v4l2_rect *crop;
>   
> -	/* imx219_get_format_code() wants mutex locked. */
> -	mutex_lock(&imx219->mutex);
> -
>   	/* Initialize try_fmt */
>   	format = v4l2_subdev_get_pad_format(sd, state, 0);
>   	format->width = supported_modes[0].width;
> @@ -723,8 +696,6 @@ static int imx219_init_cfg(struct v4l2_subdev *sd,
>   	crop->width = IMX219_PIXEL_ARRAY_WIDTH;
>   	crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
>   
> -	mutex_unlock(&imx219->mutex);
> -
>   	return 0;
>   }
>   
> @@ -737,9 +708,7 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
>   	if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
>   		return -EINVAL;
>   
> -	mutex_lock(&imx219->mutex);
>   	code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
> -	mutex_unlock(&imx219->mutex);
>   
>   	return 0;
>   }
> @@ -754,9 +723,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
>   	if (fse->index >= ARRAY_SIZE(supported_modes))
>   		return -EINVAL;
>   
> -	mutex_lock(&imx219->mutex);
>   	code = imx219_get_format_code(imx219, fse->code);
> -	mutex_unlock(&imx219->mutex);
>   	if (fse->code != code)
>   		return -EINVAL;
>   
> @@ -785,52 +752,16 @@ static void imx219_update_pad_format(struct imx219 *imx219,
>   	imx219_reset_colorspace(&fmt->format);
>   }
>   
> -static int __imx219_get_pad_format(struct imx219 *imx219,
> -				   struct v4l2_subdev_state *sd_state,
> -				   struct v4l2_subdev_format *fmt)
> -{
> -	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> -		struct v4l2_mbus_framefmt *try_fmt =
> -			v4l2_subdev_get_try_format(&imx219->sd, sd_state,
> -						   fmt->pad);
> -		/* update the code which could change due to vflip or hflip: */
> -		try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
> -		fmt->format = *try_fmt;
> -	} else {
> -		imx219_update_pad_format(imx219, imx219->mode, fmt);
> -		fmt->format.code = imx219_get_format_code(imx219,
> -							  imx219->fmt.code);
> -	}
> -
> -	return 0;
> -}
> -
> -static int imx219_get_pad_format(struct v4l2_subdev *sd,
> -				 struct v4l2_subdev_state *sd_state,
> -				 struct v4l2_subdev_format *fmt)
> -{
> -	struct imx219 *imx219 = to_imx219(sd);
> -	int ret;
> -
> -	mutex_lock(&imx219->mutex);
> -	ret = __imx219_get_pad_format(imx219, sd_state, fmt);
> -	mutex_unlock(&imx219->mutex);
> -
> -	return ret;
> -}
> -
>   static int imx219_set_pad_format(struct v4l2_subdev *sd,
>   				 struct v4l2_subdev_state *sd_state,
>   				 struct v4l2_subdev_format *fmt)
>   {
>   	struct imx219 *imx219 = to_imx219(sd);
>   	const struct imx219_mode *mode;
> -	struct v4l2_mbus_framefmt *framefmt;
>   	int exposure_max, exposure_def, hblank;
> +	struct v4l2_mbus_framefmt *format;
>   	unsigned int i;
>   
> -	mutex_lock(&imx219->mutex);
> -
>   	for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
>   		if (imx219_mbus_formats[i] == fmt->format.code)
>   			break;
> @@ -844,13 +775,14 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
>   				      ARRAY_SIZE(supported_modes),
>   				      width, height,
>   				      fmt->format.width, fmt->format.height);
> +
>   	imx219_update_pad_format(imx219, mode, fmt);
> -	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> -		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
> -		*framefmt = fmt->format;
> -	} else if (imx219->mode != mode ||
> -		   imx219->fmt.code != fmt->format.code) {
> -		imx219->fmt = fmt->format;
> +	format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
> +
> +	if (imx219->mode == mode && format->code == fmt->format.code)
> +		return 0;
> +
> +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
>   		imx219->mode = mode;
>   		/* Update limits and set FPS to default */
>   		__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
> @@ -876,14 +808,15 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
>   					 hblank);
>   	}
>   
> -	mutex_unlock(&imx219->mutex);
> +	*format = fmt->format;
>   
>   	return 0;
>   }
>   
> -static int imx219_set_framefmt(struct imx219 *imx219)
> +static int imx219_set_framefmt(struct imx219 *imx219,
> +			       const struct v4l2_mbus_framefmt *format)
>   {
> -	switch (imx219->fmt.code) {
> +	switch (format->code) {
>   	case MEDIA_BUS_FMT_SRGGB8_1X8:
>   	case MEDIA_BUS_FMT_SGRBG8_1X8:
>   	case MEDIA_BUS_FMT_SGBRG8_1X8:
> @@ -902,7 +835,8 @@ static int imx219_set_framefmt(struct imx219 *imx219)
>   	return -EINVAL;
>   }
>   
> -static int imx219_set_binning(struct imx219 *imx219)
> +static int imx219_set_binning(struct imx219 *imx219,
> +			      const struct v4l2_mbus_framefmt *format)
>   {
>   	if (!imx219->mode->binning) {
>   		return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
> @@ -910,7 +844,7 @@ static int imx219_set_binning(struct imx219 *imx219)
>   					IMX219_BINNING_NONE);
>   	}
>   
> -	switch (imx219->fmt.code) {
> +	switch (format->code) {
>   	case MEDIA_BUS_FMT_SRGGB8_1X8:
>   	case MEDIA_BUS_FMT_SGRBG8_1X8:
>   	case MEDIA_BUS_FMT_SGBRG8_1X8:
> @@ -931,34 +865,13 @@ static int imx219_set_binning(struct imx219 *imx219)
>   	return -EINVAL;
>   }
>   
> -static const struct v4l2_rect *
> -__imx219_get_pad_crop(struct imx219 *imx219,
> -		      struct v4l2_subdev_state *sd_state,
> -		      unsigned int pad, enum v4l2_subdev_format_whence which)
> -{
> -	switch (which) {
> -	case V4L2_SUBDEV_FORMAT_TRY:
> -		return v4l2_subdev_get_try_crop(&imx219->sd, sd_state, pad);
> -	case V4L2_SUBDEV_FORMAT_ACTIVE:
> -		return &imx219->mode->crop;
> -	}
> -
> -	return NULL;
> -}
> -
>   static int imx219_get_selection(struct v4l2_subdev *sd,
>   				struct v4l2_subdev_state *sd_state,
>   				struct v4l2_subdev_selection *sel)
>   {
>   	switch (sel->target) {
>   	case V4L2_SEL_TGT_CROP: {
> -		struct imx219 *imx219 = to_imx219(sd);
> -
> -		mutex_lock(&imx219->mutex);
> -		sel->r = *__imx219_get_pad_crop(imx219, sd_state, sel->pad,
> -						sel->which);
> -		mutex_unlock(&imx219->mutex);
> -
> +		sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
>   		return 0;
>   	}
>   
> @@ -990,9 +903,11 @@ static int imx219_configure_lanes(struct imx219 *imx219)
>   				IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE);
>   };
>   
> -static int imx219_start_streaming(struct imx219 *imx219)
> +static int imx219_start_streaming(struct imx219 *imx219,
> +				  struct v4l2_subdev_state *state)
>   {
>   	struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
> +	const struct v4l2_mbus_framefmt *format;
>   	const struct imx219_reg_list *reg_list;
>   	int ret;
>   
> @@ -1022,14 +937,15 @@ static int imx219_start_streaming(struct imx219 *imx219)
>   		goto err_rpm_put;
>   	}
>   
> -	ret = imx219_set_framefmt(imx219);
> +	format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0);
> +	ret = imx219_set_framefmt(imx219, format);
>   	if (ret) {
>   		dev_err(&client->dev, "%s failed to set frame format: %d\n",
>   			__func__, ret);
>   		goto err_rpm_put;
>   	}
>   
> -	ret = imx219_set_binning(imx219);
> +	ret = imx219_set_binning(imx219, format);
>   	if (ret) {
>   		dev_err(&client->dev, "%s failed to set binning: %d\n",
>   			__func__, ret);
> @@ -1078,35 +994,30 @@ static void imx219_stop_streaming(struct imx219 *imx219)
>   static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
>   {
>   	struct imx219 *imx219 = to_imx219(sd);
> +	struct v4l2_subdev_state *state;
>   	int ret = 0;
>   
> -	mutex_lock(&imx219->mutex);
> -	if (imx219->streaming == enable) {
> -		mutex_unlock(&imx219->mutex);
> -		return 0;
> -	}
> +	state = v4l2_subdev_lock_and_get_active_state(sd);
> +
> +	if (imx219->streaming == enable)
> +		goto unlock;
>   
>   	if (enable) {
>   		/*
>   		 * Apply default & customized values
>   		 * and then start streaming.
>   		 */
> -		ret = imx219_start_streaming(imx219);
> +		ret = imx219_start_streaming(imx219, state);
>   		if (ret)
> -			goto err_unlock;
> +			goto unlock;
>   	} else {
>   		imx219_stop_streaming(imx219);
>   	}
>   
>   	imx219->streaming = enable;
>   
> -	mutex_unlock(&imx219->mutex);
> -
> -	return ret;
> -
> -err_unlock:
> -	mutex_unlock(&imx219->mutex);
> -
> +unlock:
> +	v4l2_subdev_unlock_state(state);
>   	return ret;
>   }
>   
> @@ -1171,10 +1082,13 @@ static int __maybe_unused imx219_resume(struct device *dev)
>   {
>   	struct v4l2_subdev *sd = dev_get_drvdata(dev);
>   	struct imx219 *imx219 = to_imx219(sd);
> +	struct v4l2_subdev_state *state;
>   	int ret;
>   
>   	if (imx219->streaming) {
> -		ret = imx219_start_streaming(imx219);
> +		state = v4l2_subdev_lock_and_get_active_state(sd);
> +		ret = imx219_start_streaming(imx219, state);
> +		v4l2_subdev_unlock_state(state);
>   		if (ret)
>   			goto error;
>   	}
> @@ -1237,7 +1151,7 @@ static const struct v4l2_subdev_video_ops imx219_video_ops = {
>   static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
>   	.init_cfg = imx219_init_cfg,
>   	.enum_mbus_code = imx219_enum_mbus_code,
> -	.get_fmt = imx219_get_pad_format,
> +	.get_fmt = v4l2_subdev_get_fmt,
>   	.set_fmt = imx219_set_pad_format,
>   	.get_selection = imx219_get_selection,
>   	.enum_frame_size = imx219_enum_frame_size,
> @@ -1270,9 +1184,6 @@ static int imx219_init_controls(struct imx219 *imx219)
>   	if (ret)
>   		return ret;
>   
> -	mutex_init(&imx219->mutex);
> -	ctrl_hdlr->lock = &imx219->mutex;
> -
>   	/* By default, PIXEL_RATE is read only */
>   	imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
>   					       V4L2_CID_PIXEL_RATE,
> @@ -1369,7 +1280,6 @@ static int imx219_init_controls(struct imx219 *imx219)
>   
>   error:
>   	v4l2_ctrl_handler_free(ctrl_hdlr);
> -	mutex_destroy(&imx219->mutex);
>   
>   	return ret;
>   }
> @@ -1377,7 +1287,6 @@ static int imx219_init_controls(struct imx219 *imx219)
>   static void imx219_free_controls(struct imx219 *imx219)
>   {
>   	v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
> -	mutex_destroy(&imx219->mutex);
>   }
>   
>   static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
> @@ -1514,19 +1423,23 @@ static int imx219_probe(struct i2c_client *client)
>   	/* Initialize source pad */
>   	imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
>   
> -	/* Initialize default format */
> -	imx219_set_default_format(imx219);
> -
>   	ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
>   	if (ret) {
>   		dev_err(dev, "failed to init entity pads: %d\n", ret);
>   		goto error_handler_free;
>   	}
>   
> +	imx219->sd.state_lock = imx219->ctrl_handler.lock;
> +	ret = v4l2_subdev_init_finalize(&imx219->sd);
> +	if (ret < 0) {
> +		dev_err(dev, "subdev init error: %d\n", ret);

maybe dev_err_probe ? other than that,

Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>

> +		goto error_media_entity;
> +	}
> +
>   	ret = v4l2_async_register_subdev_sensor(&imx219->sd);
>   	if (ret < 0) {
>   		dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
> -		goto error_media_entity;
> +		goto error_subdev_cleanup;
>   	}
>   
>   	/* Enable runtime PM and turn off the device */
> @@ -1536,6 +1449,9 @@ static int imx219_probe(struct i2c_client *client)
>   
>   	return 0;
>   
> +error_subdev_cleanup:
> +	v4l2_subdev_cleanup(&imx219->sd);
> +
>   error_media_entity:
>   	media_entity_cleanup(&imx219->sd.entity);
>   
> @@ -1554,6 +1470,7 @@ static void imx219_remove(struct i2c_client *client)
>   	struct imx219 *imx219 = to_imx219(sd);
>   
>   	v4l2_async_unregister_subdev(sd);
> +	v4l2_subdev_cleanup(sd);
>   	media_entity_cleanup(&sd->entity);
>   	imx219_free_controls(imx219);
>
Jacopo Mondi July 31, 2023, 7:35 a.m. UTC | #2
Hi Umang

On Mon, Jul 31, 2023 at 02:56:06AM +0530, Umang Jain wrote:
> Hi Jacopo ,
>
> On 7/10/23 9:22 PM, Jacopo Mondi wrote:
> > Port the imx219 sensor driver to use the subdev active state.
> >
> > Move all the format configuration to the subdevice state and simplify
> > the format handling, locking and initialization.
> >
> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >   drivers/media/i2c/imx219.c | 179 ++++++++++---------------------------
> >   1 file changed, 48 insertions(+), 131 deletions(-)
> >
> > diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
> > index 6963e24e1bc2..73e06583d651 100644
> > --- a/drivers/media/i2c/imx219.c
> > +++ b/drivers/media/i2c/imx219.c
> > @@ -460,8 +460,6 @@ struct imx219 {
> >   	struct v4l2_subdev sd;
> >   	struct media_pad pad;
> > -	struct v4l2_mbus_framefmt fmt;
> > -
> >   	struct clk *xclk; /* system clock to IMX219 */
> >   	u32 xclk_freq;
> > @@ -481,12 +479,6 @@ struct imx219 {
> >   	/* Current mode */
> >   	const struct imx219_mode *mode;
> > -	/*
> > -	 * Mutex for serialized access:
> > -	 * Protect sensor module set pad format and start/stop streaming safely.
> > -	 */
> > -	struct mutex mutex;
> > -
> >   	/* Streaming on/off */
> >   	bool streaming;
> > @@ -576,8 +568,6 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
> >   {
> >   	unsigned int i;
> > -	lockdep_assert_held(&imx219->mutex);
> > -
> >   	for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
> >   		if (imx219_mbus_formats[i] == code)
> >   			break;
> > @@ -591,20 +581,6 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
> >   	return imx219_mbus_formats[i];
> >   }
> > -static void imx219_set_default_format(struct imx219 *imx219)
> > -{
> > -	struct v4l2_mbus_framefmt *fmt;
> > -
> > -	fmt = &imx219->fmt;
> > -	fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
> > -	fmt->colorspace = V4L2_COLORSPACE_RAW;
> > -	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
> > -	fmt->width = supported_modes[0].width;
> > -	fmt->height = supported_modes[0].height;
> > -	fmt->field = V4L2_FIELD_NONE;
> > -	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
> > -}
> > -
> >   static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
> >   {
> >   	struct imx219 *imx219 =
> > @@ -701,9 +677,6 @@ static int imx219_init_cfg(struct v4l2_subdev *sd,
> >   	struct v4l2_mbus_framefmt *format;
> >   	struct v4l2_rect *crop;
> > -	/* imx219_get_format_code() wants mutex locked. */
> > -	mutex_lock(&imx219->mutex);
> > -
> >   	/* Initialize try_fmt */
> >   	format = v4l2_subdev_get_pad_format(sd, state, 0);
> >   	format->width = supported_modes[0].width;
> > @@ -723,8 +696,6 @@ static int imx219_init_cfg(struct v4l2_subdev *sd,
> >   	crop->width = IMX219_PIXEL_ARRAY_WIDTH;
> >   	crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
> > -	mutex_unlock(&imx219->mutex);
> > -
> >   	return 0;
> >   }
> > @@ -737,9 +708,7 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
> >   	if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
> >   		return -EINVAL;
> > -	mutex_lock(&imx219->mutex);
> >   	code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
> > -	mutex_unlock(&imx219->mutex);
> >   	return 0;
> >   }
> > @@ -754,9 +723,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
> >   	if (fse->index >= ARRAY_SIZE(supported_modes))
> >   		return -EINVAL;
> > -	mutex_lock(&imx219->mutex);
> >   	code = imx219_get_format_code(imx219, fse->code);
> > -	mutex_unlock(&imx219->mutex);
> >   	if (fse->code != code)
> >   		return -EINVAL;
> > @@ -785,52 +752,16 @@ static void imx219_update_pad_format(struct imx219 *imx219,
> >   	imx219_reset_colorspace(&fmt->format);
> >   }
> > -static int __imx219_get_pad_format(struct imx219 *imx219,
> > -				   struct v4l2_subdev_state *sd_state,
> > -				   struct v4l2_subdev_format *fmt)
> > -{
> > -	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> > -		struct v4l2_mbus_framefmt *try_fmt =
> > -			v4l2_subdev_get_try_format(&imx219->sd, sd_state,
> > -						   fmt->pad);
> > -		/* update the code which could change due to vflip or hflip: */
> > -		try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
> > -		fmt->format = *try_fmt;
> > -	} else {
> > -		imx219_update_pad_format(imx219, imx219->mode, fmt);
> > -		fmt->format.code = imx219_get_format_code(imx219,
> > -							  imx219->fmt.code);
> > -	}
> > -
> > -	return 0;
> > -}
> > -
> > -static int imx219_get_pad_format(struct v4l2_subdev *sd,
> > -				 struct v4l2_subdev_state *sd_state,
> > -				 struct v4l2_subdev_format *fmt)
> > -{
> > -	struct imx219 *imx219 = to_imx219(sd);
> > -	int ret;
> > -
> > -	mutex_lock(&imx219->mutex);
> > -	ret = __imx219_get_pad_format(imx219, sd_state, fmt);
> > -	mutex_unlock(&imx219->mutex);
> > -
> > -	return ret;
> > -}
> > -
> >   static int imx219_set_pad_format(struct v4l2_subdev *sd,
> >   				 struct v4l2_subdev_state *sd_state,
> >   				 struct v4l2_subdev_format *fmt)
> >   {
> >   	struct imx219 *imx219 = to_imx219(sd);
> >   	const struct imx219_mode *mode;
> > -	struct v4l2_mbus_framefmt *framefmt;
> >   	int exposure_max, exposure_def, hblank;
> > +	struct v4l2_mbus_framefmt *format;
> >   	unsigned int i;
> > -	mutex_lock(&imx219->mutex);
> > -
> >   	for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
> >   		if (imx219_mbus_formats[i] == fmt->format.code)
> >   			break;
> > @@ -844,13 +775,14 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
> >   				      ARRAY_SIZE(supported_modes),
> >   				      width, height,
> >   				      fmt->format.width, fmt->format.height);
> > +
> >   	imx219_update_pad_format(imx219, mode, fmt);
> > -	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> > -		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
> > -		*framefmt = fmt->format;
> > -	} else if (imx219->mode != mode ||
> > -		   imx219->fmt.code != fmt->format.code) {
> > -		imx219->fmt = fmt->format;
> > +	format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
> > +
> > +	if (imx219->mode == mode && format->code == fmt->format.code)
> > +		return 0;
> > +
> > +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> >   		imx219->mode = mode;
> >   		/* Update limits and set FPS to default */
> >   		__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
> > @@ -876,14 +808,15 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
> >   					 hblank);
> >   	}
> > -	mutex_unlock(&imx219->mutex);
> > +	*format = fmt->format;
> >   	return 0;
> >   }
> > -static int imx219_set_framefmt(struct imx219 *imx219)
> > +static int imx219_set_framefmt(struct imx219 *imx219,
> > +			       const struct v4l2_mbus_framefmt *format)
> >   {
> > -	switch (imx219->fmt.code) {
> > +	switch (format->code) {
> >   	case MEDIA_BUS_FMT_SRGGB8_1X8:
> >   	case MEDIA_BUS_FMT_SGRBG8_1X8:
> >   	case MEDIA_BUS_FMT_SGBRG8_1X8:
> > @@ -902,7 +835,8 @@ static int imx219_set_framefmt(struct imx219 *imx219)
> >   	return -EINVAL;
> >   }
> > -static int imx219_set_binning(struct imx219 *imx219)
> > +static int imx219_set_binning(struct imx219 *imx219,
> > +			      const struct v4l2_mbus_framefmt *format)
> >   {
> >   	if (!imx219->mode->binning) {
> >   		return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
> > @@ -910,7 +844,7 @@ static int imx219_set_binning(struct imx219 *imx219)
> >   					IMX219_BINNING_NONE);
> >   	}
> > -	switch (imx219->fmt.code) {
> > +	switch (format->code) {
> >   	case MEDIA_BUS_FMT_SRGGB8_1X8:
> >   	case MEDIA_BUS_FMT_SGRBG8_1X8:
> >   	case MEDIA_BUS_FMT_SGBRG8_1X8:
> > @@ -931,34 +865,13 @@ static int imx219_set_binning(struct imx219 *imx219)
> >   	return -EINVAL;
> >   }
> > -static const struct v4l2_rect *
> > -__imx219_get_pad_crop(struct imx219 *imx219,
> > -		      struct v4l2_subdev_state *sd_state,
> > -		      unsigned int pad, enum v4l2_subdev_format_whence which)
> > -{
> > -	switch (which) {
> > -	case V4L2_SUBDEV_FORMAT_TRY:
> > -		return v4l2_subdev_get_try_crop(&imx219->sd, sd_state, pad);
> > -	case V4L2_SUBDEV_FORMAT_ACTIVE:
> > -		return &imx219->mode->crop;
> > -	}
> > -
> > -	return NULL;
> > -}
> > -
> >   static int imx219_get_selection(struct v4l2_subdev *sd,
> >   				struct v4l2_subdev_state *sd_state,
> >   				struct v4l2_subdev_selection *sel)
> >   {
> >   	switch (sel->target) {
> >   	case V4L2_SEL_TGT_CROP: {
> > -		struct imx219 *imx219 = to_imx219(sd);
> > -
> > -		mutex_lock(&imx219->mutex);
> > -		sel->r = *__imx219_get_pad_crop(imx219, sd_state, sel->pad,
> > -						sel->which);
> > -		mutex_unlock(&imx219->mutex);
> > -
> > +		sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
> >   		return 0;
> >   	}
> > @@ -990,9 +903,11 @@ static int imx219_configure_lanes(struct imx219 *imx219)
> >   				IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE);
> >   };
> > -static int imx219_start_streaming(struct imx219 *imx219)
> > +static int imx219_start_streaming(struct imx219 *imx219,
> > +				  struct v4l2_subdev_state *state)
> >   {
> >   	struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
> > +	const struct v4l2_mbus_framefmt *format;
> >   	const struct imx219_reg_list *reg_list;
> >   	int ret;
> > @@ -1022,14 +937,15 @@ static int imx219_start_streaming(struct imx219 *imx219)
> >   		goto err_rpm_put;
> >   	}
> > -	ret = imx219_set_framefmt(imx219);
> > +	format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0);
> > +	ret = imx219_set_framefmt(imx219, format);
> >   	if (ret) {
> >   		dev_err(&client->dev, "%s failed to set frame format: %d\n",
> >   			__func__, ret);
> >   		goto err_rpm_put;
> >   	}
> > -	ret = imx219_set_binning(imx219);
> > +	ret = imx219_set_binning(imx219, format);
> >   	if (ret) {
> >   		dev_err(&client->dev, "%s failed to set binning: %d\n",
> >   			__func__, ret);
> > @@ -1078,35 +994,30 @@ static void imx219_stop_streaming(struct imx219 *imx219)
> >   static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
> >   {
> >   	struct imx219 *imx219 = to_imx219(sd);
> > +	struct v4l2_subdev_state *state;
> >   	int ret = 0;
> > -	mutex_lock(&imx219->mutex);
> > -	if (imx219->streaming == enable) {
> > -		mutex_unlock(&imx219->mutex);
> > -		return 0;
> > -	}
> > +	state = v4l2_subdev_lock_and_get_active_state(sd);
> > +
> > +	if (imx219->streaming == enable)
> > +		goto unlock;
> >   	if (enable) {
> >   		/*
> >   		 * Apply default & customized values
> >   		 * and then start streaming.
> >   		 */
> > -		ret = imx219_start_streaming(imx219);
> > +		ret = imx219_start_streaming(imx219, state);
> >   		if (ret)
> > -			goto err_unlock;
> > +			goto unlock;
> >   	} else {
> >   		imx219_stop_streaming(imx219);
> >   	}
> >   	imx219->streaming = enable;
> > -	mutex_unlock(&imx219->mutex);
> > -
> > -	return ret;
> > -
> > -err_unlock:
> > -	mutex_unlock(&imx219->mutex);
> > -
> > +unlock:
> > +	v4l2_subdev_unlock_state(state);
> >   	return ret;
> >   }
> > @@ -1171,10 +1082,13 @@ static int __maybe_unused imx219_resume(struct device *dev)
> >   {
> >   	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> >   	struct imx219 *imx219 = to_imx219(sd);
> > +	struct v4l2_subdev_state *state;
> >   	int ret;
> >   	if (imx219->streaming) {
> > -		ret = imx219_start_streaming(imx219);
> > +		state = v4l2_subdev_lock_and_get_active_state(sd);
> > +		ret = imx219_start_streaming(imx219, state);
> > +		v4l2_subdev_unlock_state(state);
> >   		if (ret)
> >   			goto error;
> >   	}
> > @@ -1237,7 +1151,7 @@ static const struct v4l2_subdev_video_ops imx219_video_ops = {
> >   static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
> >   	.init_cfg = imx219_init_cfg,
> >   	.enum_mbus_code = imx219_enum_mbus_code,
> > -	.get_fmt = imx219_get_pad_format,
> > +	.get_fmt = v4l2_subdev_get_fmt,
> >   	.set_fmt = imx219_set_pad_format,
> >   	.get_selection = imx219_get_selection,
> >   	.enum_frame_size = imx219_enum_frame_size,
> > @@ -1270,9 +1184,6 @@ static int imx219_init_controls(struct imx219 *imx219)
> >   	if (ret)
> >   		return ret;
> > -	mutex_init(&imx219->mutex);
> > -	ctrl_hdlr->lock = &imx219->mutex;
> > -
> >   	/* By default, PIXEL_RATE is read only */
> >   	imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
> >   					       V4L2_CID_PIXEL_RATE,
> > @@ -1369,7 +1280,6 @@ static int imx219_init_controls(struct imx219 *imx219)
> >   error:
> >   	v4l2_ctrl_handler_free(ctrl_hdlr);
> > -	mutex_destroy(&imx219->mutex);
> >   	return ret;
> >   }
> > @@ -1377,7 +1287,6 @@ static int imx219_init_controls(struct imx219 *imx219)
> >   static void imx219_free_controls(struct imx219 *imx219)
> >   {
> >   	v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
> > -	mutex_destroy(&imx219->mutex);
> >   }
> >   static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
> > @@ -1514,19 +1423,23 @@ static int imx219_probe(struct i2c_client *client)
> >   	/* Initialize source pad */
> >   	imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
> > -	/* Initialize default format */
> > -	imx219_set_default_format(imx219);
> > -
> >   	ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
> >   	if (ret) {
> >   		dev_err(dev, "failed to init entity pads: %d\n", ret);
> >   		goto error_handler_free;
> >   	}
> > +	imx219->sd.state_lock = imx219->ctrl_handler.lock;
> > +	ret = v4l2_subdev_init_finalize(&imx219->sd);
> > +	if (ret < 0) {
> > +		dev_err(dev, "subdev init error: %d\n", ret);
>
> maybe dev_err_probe ? other than that,

Is there anything that might cause a deferred probe in the
v4l2_subdev_init_finalize() call path ? I can only see a call to
the init_cfg() operation where one could potentially hit a deferred
probe, but this driver's implementation doesn't (and other shouldn't
anyway).

>
> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
>
> > +		goto error_media_entity;
> > +	}
> > +
> >   	ret = v4l2_async_register_subdev_sensor(&imx219->sd);
> >   	if (ret < 0) {
> >   		dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
> > -		goto error_media_entity;
> > +		goto error_subdev_cleanup;
> >   	}
> >   	/* Enable runtime PM and turn off the device */
> > @@ -1536,6 +1449,9 @@ static int imx219_probe(struct i2c_client *client)
> >   	return 0;
> > +error_subdev_cleanup:
> > +	v4l2_subdev_cleanup(&imx219->sd);
> > +
> >   error_media_entity:
> >   	media_entity_cleanup(&imx219->sd.entity);
> > @@ -1554,6 +1470,7 @@ static void imx219_remove(struct i2c_client *client)
> >   	struct imx219 *imx219 = to_imx219(sd);
> >   	v4l2_async_unregister_subdev(sd);
> > +	v4l2_subdev_cleanup(sd);
> >   	media_entity_cleanup(&sd->entity);
> >   	imx219_free_controls(imx219);
>
Umang Jain Aug. 1, 2023, 7:46 a.m. UTC | #3
Hi Jacopo.

On 7/31/23 1:05 PM, Jacopo Mondi wrote:
> Hi Umang
>
> On Mon, Jul 31, 2023 at 02:56:06AM +0530, Umang Jain wrote:
>> Hi Jacopo ,
>>
>> On 7/10/23 9:22 PM, Jacopo Mondi wrote:
>>> Port the imx219 sensor driver to use the subdev active state.
>>>
>>> Move all the format configuration to the subdevice state and simplify
>>> the format handling, locking and initialization.
>>>
>>> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
>>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>> ---
>>>    drivers/media/i2c/imx219.c | 179 ++++++++++---------------------------
>>>    1 file changed, 48 insertions(+), 131 deletions(-)
>>>
>>> diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
>>> index 6963e24e1bc2..73e06583d651 100644
>>> --- a/drivers/media/i2c/imx219.c
>>> +++ b/drivers/media/i2c/imx219.c
>>> @@ -460,8 +460,6 @@ struct imx219 {
>>>    	struct v4l2_subdev sd;
>>>    	struct media_pad pad;
>>> -	struct v4l2_mbus_framefmt fmt;
>>> -
>>>    	struct clk *xclk; /* system clock to IMX219 */
>>>    	u32 xclk_freq;
>>> @@ -481,12 +479,6 @@ struct imx219 {
>>>    	/* Current mode */
>>>    	const struct imx219_mode *mode;
>>> -	/*
>>> -	 * Mutex for serialized access:
>>> -	 * Protect sensor module set pad format and start/stop streaming safely.
>>> -	 */
>>> -	struct mutex mutex;
>>> -
>>>    	/* Streaming on/off */
>>>    	bool streaming;
>>> @@ -576,8 +568,6 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
>>>    {
>>>    	unsigned int i;
>>> -	lockdep_assert_held(&imx219->mutex);
>>> -
>>>    	for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
>>>    		if (imx219_mbus_formats[i] == code)
>>>    			break;
>>> @@ -591,20 +581,6 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
>>>    	return imx219_mbus_formats[i];
>>>    }
>>> -static void imx219_set_default_format(struct imx219 *imx219)
>>> -{
>>> -	struct v4l2_mbus_framefmt *fmt;
>>> -
>>> -	fmt = &imx219->fmt;
>>> -	fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
>>> -	fmt->colorspace = V4L2_COLORSPACE_RAW;
>>> -	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
>>> -	fmt->width = supported_modes[0].width;
>>> -	fmt->height = supported_modes[0].height;
>>> -	fmt->field = V4L2_FIELD_NONE;
>>> -	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
>>> -}
>>> -
>>>    static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
>>>    {
>>>    	struct imx219 *imx219 =
>>> @@ -701,9 +677,6 @@ static int imx219_init_cfg(struct v4l2_subdev *sd,
>>>    	struct v4l2_mbus_framefmt *format;
>>>    	struct v4l2_rect *crop;
>>> -	/* imx219_get_format_code() wants mutex locked. */
>>> -	mutex_lock(&imx219->mutex);
>>> -
>>>    	/* Initialize try_fmt */
>>>    	format = v4l2_subdev_get_pad_format(sd, state, 0);
>>>    	format->width = supported_modes[0].width;
>>> @@ -723,8 +696,6 @@ static int imx219_init_cfg(struct v4l2_subdev *sd,
>>>    	crop->width = IMX219_PIXEL_ARRAY_WIDTH;
>>>    	crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
>>> -	mutex_unlock(&imx219->mutex);
>>> -
>>>    	return 0;
>>>    }
>>> @@ -737,9 +708,7 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
>>>    	if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
>>>    		return -EINVAL;
>>> -	mutex_lock(&imx219->mutex);
>>>    	code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
>>> -	mutex_unlock(&imx219->mutex);
>>>    	return 0;
>>>    }
>>> @@ -754,9 +723,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
>>>    	if (fse->index >= ARRAY_SIZE(supported_modes))
>>>    		return -EINVAL;
>>> -	mutex_lock(&imx219->mutex);
>>>    	code = imx219_get_format_code(imx219, fse->code);
>>> -	mutex_unlock(&imx219->mutex);
>>>    	if (fse->code != code)
>>>    		return -EINVAL;
>>> @@ -785,52 +752,16 @@ static void imx219_update_pad_format(struct imx219 *imx219,
>>>    	imx219_reset_colorspace(&fmt->format);
>>>    }
>>> -static int __imx219_get_pad_format(struct imx219 *imx219,
>>> -				   struct v4l2_subdev_state *sd_state,
>>> -				   struct v4l2_subdev_format *fmt)
>>> -{
>>> -	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
>>> -		struct v4l2_mbus_framefmt *try_fmt =
>>> -			v4l2_subdev_get_try_format(&imx219->sd, sd_state,
>>> -						   fmt->pad);
>>> -		/* update the code which could change due to vflip or hflip: */
>>> -		try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
>>> -		fmt->format = *try_fmt;
>>> -	} else {
>>> -		imx219_update_pad_format(imx219, imx219->mode, fmt);
>>> -		fmt->format.code = imx219_get_format_code(imx219,
>>> -							  imx219->fmt.code);
>>> -	}
>>> -
>>> -	return 0;
>>> -}
>>> -
>>> -static int imx219_get_pad_format(struct v4l2_subdev *sd,
>>> -				 struct v4l2_subdev_state *sd_state,
>>> -				 struct v4l2_subdev_format *fmt)
>>> -{
>>> -	struct imx219 *imx219 = to_imx219(sd);
>>> -	int ret;
>>> -
>>> -	mutex_lock(&imx219->mutex);
>>> -	ret = __imx219_get_pad_format(imx219, sd_state, fmt);
>>> -	mutex_unlock(&imx219->mutex);
>>> -
>>> -	return ret;
>>> -}
>>> -
>>>    static int imx219_set_pad_format(struct v4l2_subdev *sd,
>>>    				 struct v4l2_subdev_state *sd_state,
>>>    				 struct v4l2_subdev_format *fmt)
>>>    {
>>>    	struct imx219 *imx219 = to_imx219(sd);
>>>    	const struct imx219_mode *mode;
>>> -	struct v4l2_mbus_framefmt *framefmt;
>>>    	int exposure_max, exposure_def, hblank;
>>> +	struct v4l2_mbus_framefmt *format;
>>>    	unsigned int i;
>>> -	mutex_lock(&imx219->mutex);
>>> -
>>>    	for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
>>>    		if (imx219_mbus_formats[i] == fmt->format.code)
>>>    			break;
>>> @@ -844,13 +775,14 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
>>>    				      ARRAY_SIZE(supported_modes),
>>>    				      width, height,
>>>    				      fmt->format.width, fmt->format.height);
>>> +
>>>    	imx219_update_pad_format(imx219, mode, fmt);
>>> -	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
>>> -		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
>>> -		*framefmt = fmt->format;
>>> -	} else if (imx219->mode != mode ||
>>> -		   imx219->fmt.code != fmt->format.code) {
>>> -		imx219->fmt = fmt->format;
>>> +	format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
>>> +
>>> +	if (imx219->mode == mode && format->code == fmt->format.code)
>>> +		return 0;
>>> +
>>> +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
>>>    		imx219->mode = mode;
>>>    		/* Update limits and set FPS to default */
>>>    		__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
>>> @@ -876,14 +808,15 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
>>>    					 hblank);
>>>    	}
>>> -	mutex_unlock(&imx219->mutex);
>>> +	*format = fmt->format;
>>>    	return 0;
>>>    }
>>> -static int imx219_set_framefmt(struct imx219 *imx219)
>>> +static int imx219_set_framefmt(struct imx219 *imx219,
>>> +			       const struct v4l2_mbus_framefmt *format)
>>>    {
>>> -	switch (imx219->fmt.code) {
>>> +	switch (format->code) {
>>>    	case MEDIA_BUS_FMT_SRGGB8_1X8:
>>>    	case MEDIA_BUS_FMT_SGRBG8_1X8:
>>>    	case MEDIA_BUS_FMT_SGBRG8_1X8:
>>> @@ -902,7 +835,8 @@ static int imx219_set_framefmt(struct imx219 *imx219)
>>>    	return -EINVAL;
>>>    }
>>> -static int imx219_set_binning(struct imx219 *imx219)
>>> +static int imx219_set_binning(struct imx219 *imx219,
>>> +			      const struct v4l2_mbus_framefmt *format)
>>>    {
>>>    	if (!imx219->mode->binning) {
>>>    		return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
>>> @@ -910,7 +844,7 @@ static int imx219_set_binning(struct imx219 *imx219)
>>>    					IMX219_BINNING_NONE);
>>>    	}
>>> -	switch (imx219->fmt.code) {
>>> +	switch (format->code) {
>>>    	case MEDIA_BUS_FMT_SRGGB8_1X8:
>>>    	case MEDIA_BUS_FMT_SGRBG8_1X8:
>>>    	case MEDIA_BUS_FMT_SGBRG8_1X8:
>>> @@ -931,34 +865,13 @@ static int imx219_set_binning(struct imx219 *imx219)
>>>    	return -EINVAL;
>>>    }
>>> -static const struct v4l2_rect *
>>> -__imx219_get_pad_crop(struct imx219 *imx219,
>>> -		      struct v4l2_subdev_state *sd_state,
>>> -		      unsigned int pad, enum v4l2_subdev_format_whence which)
>>> -{
>>> -	switch (which) {
>>> -	case V4L2_SUBDEV_FORMAT_TRY:
>>> -		return v4l2_subdev_get_try_crop(&imx219->sd, sd_state, pad);
>>> -	case V4L2_SUBDEV_FORMAT_ACTIVE:
>>> -		return &imx219->mode->crop;
>>> -	}
>>> -
>>> -	return NULL;
>>> -}
>>> -
>>>    static int imx219_get_selection(struct v4l2_subdev *sd,
>>>    				struct v4l2_subdev_state *sd_state,
>>>    				struct v4l2_subdev_selection *sel)
>>>    {
>>>    	switch (sel->target) {
>>>    	case V4L2_SEL_TGT_CROP: {
>>> -		struct imx219 *imx219 = to_imx219(sd);
>>> -
>>> -		mutex_lock(&imx219->mutex);
>>> -		sel->r = *__imx219_get_pad_crop(imx219, sd_state, sel->pad,
>>> -						sel->which);
>>> -		mutex_unlock(&imx219->mutex);
>>> -
>>> +		sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
>>>    		return 0;
>>>    	}
>>> @@ -990,9 +903,11 @@ static int imx219_configure_lanes(struct imx219 *imx219)
>>>    				IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE);
>>>    };
>>> -static int imx219_start_streaming(struct imx219 *imx219)
>>> +static int imx219_start_streaming(struct imx219 *imx219,
>>> +				  struct v4l2_subdev_state *state)
>>>    {
>>>    	struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
>>> +	const struct v4l2_mbus_framefmt *format;
>>>    	const struct imx219_reg_list *reg_list;
>>>    	int ret;
>>> @@ -1022,14 +937,15 @@ static int imx219_start_streaming(struct imx219 *imx219)
>>>    		goto err_rpm_put;
>>>    	}
>>> -	ret = imx219_set_framefmt(imx219);
>>> +	format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0);
>>> +	ret = imx219_set_framefmt(imx219, format);
>>>    	if (ret) {
>>>    		dev_err(&client->dev, "%s failed to set frame format: %d\n",
>>>    			__func__, ret);
>>>    		goto err_rpm_put;
>>>    	}
>>> -	ret = imx219_set_binning(imx219);
>>> +	ret = imx219_set_binning(imx219, format);
>>>    	if (ret) {
>>>    		dev_err(&client->dev, "%s failed to set binning: %d\n",
>>>    			__func__, ret);
>>> @@ -1078,35 +994,30 @@ static void imx219_stop_streaming(struct imx219 *imx219)
>>>    static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
>>>    {
>>>    	struct imx219 *imx219 = to_imx219(sd);
>>> +	struct v4l2_subdev_state *state;
>>>    	int ret = 0;
>>> -	mutex_lock(&imx219->mutex);
>>> -	if (imx219->streaming == enable) {
>>> -		mutex_unlock(&imx219->mutex);
>>> -		return 0;
>>> -	}
>>> +	state = v4l2_subdev_lock_and_get_active_state(sd);
>>> +
>>> +	if (imx219->streaming == enable)
>>> +		goto unlock;
>>>    	if (enable) {
>>>    		/*
>>>    		 * Apply default & customized values
>>>    		 * and then start streaming.
>>>    		 */
>>> -		ret = imx219_start_streaming(imx219);
>>> +		ret = imx219_start_streaming(imx219, state);
>>>    		if (ret)
>>> -			goto err_unlock;
>>> +			goto unlock;
>>>    	} else {
>>>    		imx219_stop_streaming(imx219);
>>>    	}
>>>    	imx219->streaming = enable;
>>> -	mutex_unlock(&imx219->mutex);
>>> -
>>> -	return ret;
>>> -
>>> -err_unlock:
>>> -	mutex_unlock(&imx219->mutex);
>>> -
>>> +unlock:
>>> +	v4l2_subdev_unlock_state(state);
>>>    	return ret;
>>>    }
>>> @@ -1171,10 +1082,13 @@ static int __maybe_unused imx219_resume(struct device *dev)
>>>    {
>>>    	struct v4l2_subdev *sd = dev_get_drvdata(dev);
>>>    	struct imx219 *imx219 = to_imx219(sd);
>>> +	struct v4l2_subdev_state *state;
>>>    	int ret;
>>>    	if (imx219->streaming) {
>>> -		ret = imx219_start_streaming(imx219);
>>> +		state = v4l2_subdev_lock_and_get_active_state(sd);
>>> +		ret = imx219_start_streaming(imx219, state);
>>> +		v4l2_subdev_unlock_state(state);
>>>    		if (ret)
>>>    			goto error;
>>>    	}
>>> @@ -1237,7 +1151,7 @@ static const struct v4l2_subdev_video_ops imx219_video_ops = {
>>>    static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
>>>    	.init_cfg = imx219_init_cfg,
>>>    	.enum_mbus_code = imx219_enum_mbus_code,
>>> -	.get_fmt = imx219_get_pad_format,
>>> +	.get_fmt = v4l2_subdev_get_fmt,
>>>    	.set_fmt = imx219_set_pad_format,
>>>    	.get_selection = imx219_get_selection,
>>>    	.enum_frame_size = imx219_enum_frame_size,
>>> @@ -1270,9 +1184,6 @@ static int imx219_init_controls(struct imx219 *imx219)
>>>    	if (ret)
>>>    		return ret;
>>> -	mutex_init(&imx219->mutex);
>>> -	ctrl_hdlr->lock = &imx219->mutex;
>>> -
>>>    	/* By default, PIXEL_RATE is read only */
>>>    	imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
>>>    					       V4L2_CID_PIXEL_RATE,
>>> @@ -1369,7 +1280,6 @@ static int imx219_init_controls(struct imx219 *imx219)
>>>    error:
>>>    	v4l2_ctrl_handler_free(ctrl_hdlr);
>>> -	mutex_destroy(&imx219->mutex);
>>>    	return ret;
>>>    }
>>> @@ -1377,7 +1287,6 @@ static int imx219_init_controls(struct imx219 *imx219)
>>>    static void imx219_free_controls(struct imx219 *imx219)
>>>    {
>>>    	v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
>>> -	mutex_destroy(&imx219->mutex);
>>>    }
>>>    static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
>>> @@ -1514,19 +1423,23 @@ static int imx219_probe(struct i2c_client *client)
>>>    	/* Initialize source pad */
>>>    	imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
>>> -	/* Initialize default format */
>>> -	imx219_set_default_format(imx219);
>>> -
>>>    	ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
>>>    	if (ret) {
>>>    		dev_err(dev, "failed to init entity pads: %d\n", ret);
>>>    		goto error_handler_free;
>>>    	}
>>> +	imx219->sd.state_lock = imx219->ctrl_handler.lock;
>>> +	ret = v4l2_subdev_init_finalize(&imx219->sd);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "subdev init error: %d\n", ret);
>> maybe dev_err_probe ? other than that,
> Is there anything that might cause a deferred probe in the
> v4l2_subdev_init_finalize() call path ? I can only see a call to
> the init_cfg() operation where one could potentially hit a deferred
> probe, but this driver's implementation doesn't (and other shouldn't
> anyway).
>
You are correct!  I don't see any op causing deffered probe too.
Sorry for the noise!
>> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
>>
>>> +		goto error_media_entity;
>>> +	}
>>> +
>>>    	ret = v4l2_async_register_subdev_sensor(&imx219->sd);
>>>    	if (ret < 0) {
>>>    		dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
>>> -		goto error_media_entity;
>>> +		goto error_subdev_cleanup;
>>>    	}
>>>    	/* Enable runtime PM and turn off the device */
>>> @@ -1536,6 +1449,9 @@ static int imx219_probe(struct i2c_client *client)
>>>    	return 0;
>>> +error_subdev_cleanup:
>>> +	v4l2_subdev_cleanup(&imx219->sd);
>>> +
>>>    error_media_entity:
>>>    	media_entity_cleanup(&imx219->sd.entity);
>>> @@ -1554,6 +1470,7 @@ static void imx219_remove(struct i2c_client *client)
>>>    	struct imx219 *imx219 = to_imx219(sd);
>>>    	v4l2_async_unregister_subdev(sd);
>>> +	v4l2_subdev_cleanup(sd);
>>>    	media_entity_cleanup(&sd->entity);
>>>    	imx219_free_controls(imx219);
diff mbox series

Patch

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index 6963e24e1bc2..73e06583d651 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -460,8 +460,6 @@  struct imx219 {
 	struct v4l2_subdev sd;
 	struct media_pad pad;
 
-	struct v4l2_mbus_framefmt fmt;
-
 	struct clk *xclk; /* system clock to IMX219 */
 	u32 xclk_freq;
 
@@ -481,12 +479,6 @@  struct imx219 {
 	/* Current mode */
 	const struct imx219_mode *mode;
 
-	/*
-	 * Mutex for serialized access:
-	 * Protect sensor module set pad format and start/stop streaming safely.
-	 */
-	struct mutex mutex;
-
 	/* Streaming on/off */
 	bool streaming;
 
@@ -576,8 +568,6 @@  static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
 {
 	unsigned int i;
 
-	lockdep_assert_held(&imx219->mutex);
-
 	for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
 		if (imx219_mbus_formats[i] == code)
 			break;
@@ -591,20 +581,6 @@  static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
 	return imx219_mbus_formats[i];
 }
 
-static void imx219_set_default_format(struct imx219 *imx219)
-{
-	struct v4l2_mbus_framefmt *fmt;
-
-	fmt = &imx219->fmt;
-	fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
-	fmt->colorspace = V4L2_COLORSPACE_RAW;
-	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-	fmt->width = supported_modes[0].width;
-	fmt->height = supported_modes[0].height;
-	fmt->field = V4L2_FIELD_NONE;
-	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
-}
-
 static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct imx219 *imx219 =
@@ -701,9 +677,6 @@  static int imx219_init_cfg(struct v4l2_subdev *sd,
 	struct v4l2_mbus_framefmt *format;
 	struct v4l2_rect *crop;
 
-	/* imx219_get_format_code() wants mutex locked. */
-	mutex_lock(&imx219->mutex);
-
 	/* Initialize try_fmt */
 	format = v4l2_subdev_get_pad_format(sd, state, 0);
 	format->width = supported_modes[0].width;
@@ -723,8 +696,6 @@  static int imx219_init_cfg(struct v4l2_subdev *sd,
 	crop->width = IMX219_PIXEL_ARRAY_WIDTH;
 	crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
 
-	mutex_unlock(&imx219->mutex);
-
 	return 0;
 }
 
@@ -737,9 +708,7 @@  static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
 	if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
 		return -EINVAL;
 
-	mutex_lock(&imx219->mutex);
 	code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
-	mutex_unlock(&imx219->mutex);
 
 	return 0;
 }
@@ -754,9 +723,7 @@  static int imx219_enum_frame_size(struct v4l2_subdev *sd,
 	if (fse->index >= ARRAY_SIZE(supported_modes))
 		return -EINVAL;
 
-	mutex_lock(&imx219->mutex);
 	code = imx219_get_format_code(imx219, fse->code);
-	mutex_unlock(&imx219->mutex);
 	if (fse->code != code)
 		return -EINVAL;
 
@@ -785,52 +752,16 @@  static void imx219_update_pad_format(struct imx219 *imx219,
 	imx219_reset_colorspace(&fmt->format);
 }
 
-static int __imx219_get_pad_format(struct imx219 *imx219,
-				   struct v4l2_subdev_state *sd_state,
-				   struct v4l2_subdev_format *fmt)
-{
-	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-		struct v4l2_mbus_framefmt *try_fmt =
-			v4l2_subdev_get_try_format(&imx219->sd, sd_state,
-						   fmt->pad);
-		/* update the code which could change due to vflip or hflip: */
-		try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
-		fmt->format = *try_fmt;
-	} else {
-		imx219_update_pad_format(imx219, imx219->mode, fmt);
-		fmt->format.code = imx219_get_format_code(imx219,
-							  imx219->fmt.code);
-	}
-
-	return 0;
-}
-
-static int imx219_get_pad_format(struct v4l2_subdev *sd,
-				 struct v4l2_subdev_state *sd_state,
-				 struct v4l2_subdev_format *fmt)
-{
-	struct imx219 *imx219 = to_imx219(sd);
-	int ret;
-
-	mutex_lock(&imx219->mutex);
-	ret = __imx219_get_pad_format(imx219, sd_state, fmt);
-	mutex_unlock(&imx219->mutex);
-
-	return ret;
-}
-
 static int imx219_set_pad_format(struct v4l2_subdev *sd,
 				 struct v4l2_subdev_state *sd_state,
 				 struct v4l2_subdev_format *fmt)
 {
 	struct imx219 *imx219 = to_imx219(sd);
 	const struct imx219_mode *mode;
-	struct v4l2_mbus_framefmt *framefmt;
 	int exposure_max, exposure_def, hblank;
+	struct v4l2_mbus_framefmt *format;
 	unsigned int i;
 
-	mutex_lock(&imx219->mutex);
-
 	for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
 		if (imx219_mbus_formats[i] == fmt->format.code)
 			break;
@@ -844,13 +775,14 @@  static int imx219_set_pad_format(struct v4l2_subdev *sd,
 				      ARRAY_SIZE(supported_modes),
 				      width, height,
 				      fmt->format.width, fmt->format.height);
+
 	imx219_update_pad_format(imx219, mode, fmt);
-	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
-		*framefmt = fmt->format;
-	} else if (imx219->mode != mode ||
-		   imx219->fmt.code != fmt->format.code) {
-		imx219->fmt = fmt->format;
+	format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
+
+	if (imx219->mode == mode && format->code == fmt->format.code)
+		return 0;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
 		imx219->mode = mode;
 		/* Update limits and set FPS to default */
 		__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
@@ -876,14 +808,15 @@  static int imx219_set_pad_format(struct v4l2_subdev *sd,
 					 hblank);
 	}
 
-	mutex_unlock(&imx219->mutex);
+	*format = fmt->format;
 
 	return 0;
 }
 
-static int imx219_set_framefmt(struct imx219 *imx219)
+static int imx219_set_framefmt(struct imx219 *imx219,
+			       const struct v4l2_mbus_framefmt *format)
 {
-	switch (imx219->fmt.code) {
+	switch (format->code) {
 	case MEDIA_BUS_FMT_SRGGB8_1X8:
 	case MEDIA_BUS_FMT_SGRBG8_1X8:
 	case MEDIA_BUS_FMT_SGBRG8_1X8:
@@ -902,7 +835,8 @@  static int imx219_set_framefmt(struct imx219 *imx219)
 	return -EINVAL;
 }
 
-static int imx219_set_binning(struct imx219 *imx219)
+static int imx219_set_binning(struct imx219 *imx219,
+			      const struct v4l2_mbus_framefmt *format)
 {
 	if (!imx219->mode->binning) {
 		return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
@@ -910,7 +844,7 @@  static int imx219_set_binning(struct imx219 *imx219)
 					IMX219_BINNING_NONE);
 	}
 
-	switch (imx219->fmt.code) {
+	switch (format->code) {
 	case MEDIA_BUS_FMT_SRGGB8_1X8:
 	case MEDIA_BUS_FMT_SGRBG8_1X8:
 	case MEDIA_BUS_FMT_SGBRG8_1X8:
@@ -931,34 +865,13 @@  static int imx219_set_binning(struct imx219 *imx219)
 	return -EINVAL;
 }
 
-static const struct v4l2_rect *
-__imx219_get_pad_crop(struct imx219 *imx219,
-		      struct v4l2_subdev_state *sd_state,
-		      unsigned int pad, enum v4l2_subdev_format_whence which)
-{
-	switch (which) {
-	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_crop(&imx219->sd, sd_state, pad);
-	case V4L2_SUBDEV_FORMAT_ACTIVE:
-		return &imx219->mode->crop;
-	}
-
-	return NULL;
-}
-
 static int imx219_get_selection(struct v4l2_subdev *sd,
 				struct v4l2_subdev_state *sd_state,
 				struct v4l2_subdev_selection *sel)
 {
 	switch (sel->target) {
 	case V4L2_SEL_TGT_CROP: {
-		struct imx219 *imx219 = to_imx219(sd);
-
-		mutex_lock(&imx219->mutex);
-		sel->r = *__imx219_get_pad_crop(imx219, sd_state, sel->pad,
-						sel->which);
-		mutex_unlock(&imx219->mutex);
-
+		sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
 		return 0;
 	}
 
@@ -990,9 +903,11 @@  static int imx219_configure_lanes(struct imx219 *imx219)
 				IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE);
 };
 
-static int imx219_start_streaming(struct imx219 *imx219)
+static int imx219_start_streaming(struct imx219 *imx219,
+				  struct v4l2_subdev_state *state)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+	const struct v4l2_mbus_framefmt *format;
 	const struct imx219_reg_list *reg_list;
 	int ret;
 
@@ -1022,14 +937,15 @@  static int imx219_start_streaming(struct imx219 *imx219)
 		goto err_rpm_put;
 	}
 
-	ret = imx219_set_framefmt(imx219);
+	format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0);
+	ret = imx219_set_framefmt(imx219, format);
 	if (ret) {
 		dev_err(&client->dev, "%s failed to set frame format: %d\n",
 			__func__, ret);
 		goto err_rpm_put;
 	}
 
-	ret = imx219_set_binning(imx219);
+	ret = imx219_set_binning(imx219, format);
 	if (ret) {
 		dev_err(&client->dev, "%s failed to set binning: %d\n",
 			__func__, ret);
@@ -1078,35 +994,30 @@  static void imx219_stop_streaming(struct imx219 *imx219)
 static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct imx219 *imx219 = to_imx219(sd);
+	struct v4l2_subdev_state *state;
 	int ret = 0;
 
-	mutex_lock(&imx219->mutex);
-	if (imx219->streaming == enable) {
-		mutex_unlock(&imx219->mutex);
-		return 0;
-	}
+	state = v4l2_subdev_lock_and_get_active_state(sd);
+
+	if (imx219->streaming == enable)
+		goto unlock;
 
 	if (enable) {
 		/*
 		 * Apply default & customized values
 		 * and then start streaming.
 		 */
-		ret = imx219_start_streaming(imx219);
+		ret = imx219_start_streaming(imx219, state);
 		if (ret)
-			goto err_unlock;
+			goto unlock;
 	} else {
 		imx219_stop_streaming(imx219);
 	}
 
 	imx219->streaming = enable;
 
-	mutex_unlock(&imx219->mutex);
-
-	return ret;
-
-err_unlock:
-	mutex_unlock(&imx219->mutex);
-
+unlock:
+	v4l2_subdev_unlock_state(state);
 	return ret;
 }
 
@@ -1171,10 +1082,13 @@  static int __maybe_unused imx219_resume(struct device *dev)
 {
 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
 	struct imx219 *imx219 = to_imx219(sd);
+	struct v4l2_subdev_state *state;
 	int ret;
 
 	if (imx219->streaming) {
-		ret = imx219_start_streaming(imx219);
+		state = v4l2_subdev_lock_and_get_active_state(sd);
+		ret = imx219_start_streaming(imx219, state);
+		v4l2_subdev_unlock_state(state);
 		if (ret)
 			goto error;
 	}
@@ -1237,7 +1151,7 @@  static const struct v4l2_subdev_video_ops imx219_video_ops = {
 static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
 	.init_cfg = imx219_init_cfg,
 	.enum_mbus_code = imx219_enum_mbus_code,
-	.get_fmt = imx219_get_pad_format,
+	.get_fmt = v4l2_subdev_get_fmt,
 	.set_fmt = imx219_set_pad_format,
 	.get_selection = imx219_get_selection,
 	.enum_frame_size = imx219_enum_frame_size,
@@ -1270,9 +1184,6 @@  static int imx219_init_controls(struct imx219 *imx219)
 	if (ret)
 		return ret;
 
-	mutex_init(&imx219->mutex);
-	ctrl_hdlr->lock = &imx219->mutex;
-
 	/* By default, PIXEL_RATE is read only */
 	imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
 					       V4L2_CID_PIXEL_RATE,
@@ -1369,7 +1280,6 @@  static int imx219_init_controls(struct imx219 *imx219)
 
 error:
 	v4l2_ctrl_handler_free(ctrl_hdlr);
-	mutex_destroy(&imx219->mutex);
 
 	return ret;
 }
@@ -1377,7 +1287,6 @@  static int imx219_init_controls(struct imx219 *imx219)
 static void imx219_free_controls(struct imx219 *imx219)
 {
 	v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
-	mutex_destroy(&imx219->mutex);
 }
 
 static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
@@ -1514,19 +1423,23 @@  static int imx219_probe(struct i2c_client *client)
 	/* Initialize source pad */
 	imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
 
-	/* Initialize default format */
-	imx219_set_default_format(imx219);
-
 	ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
 	if (ret) {
 		dev_err(dev, "failed to init entity pads: %d\n", ret);
 		goto error_handler_free;
 	}
 
+	imx219->sd.state_lock = imx219->ctrl_handler.lock;
+	ret = v4l2_subdev_init_finalize(&imx219->sd);
+	if (ret < 0) {
+		dev_err(dev, "subdev init error: %d\n", ret);
+		goto error_media_entity;
+	}
+
 	ret = v4l2_async_register_subdev_sensor(&imx219->sd);
 	if (ret < 0) {
 		dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
-		goto error_media_entity;
+		goto error_subdev_cleanup;
 	}
 
 	/* Enable runtime PM and turn off the device */
@@ -1536,6 +1449,9 @@  static int imx219_probe(struct i2c_client *client)
 
 	return 0;
 
+error_subdev_cleanup:
+	v4l2_subdev_cleanup(&imx219->sd);
+
 error_media_entity:
 	media_entity_cleanup(&imx219->sd.entity);
 
@@ -1554,6 +1470,7 @@  static void imx219_remove(struct i2c_client *client)
 	struct imx219 *imx219 = to_imx219(sd);
 
 	v4l2_async_unregister_subdev(sd);
+	v4l2_subdev_cleanup(sd);
 	media_entity_cleanup(&sd->entity);
 	imx219_free_controls(imx219);