Commit 11927d0f authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

media: imx-mipi-csis: Use V4L2 subdev active state



Use the V4L2 subdev active state API to store the active format. This
simplifies the driver not only by dropping the mipi_csis_device csis_fmt
and format_mbus fields, but it also allows dropping the device lock,
replaced with the state lock.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Adam Ford <aford173@gmail.com> #imx8mn-beacon
Acked-by: default avatarRui Miguel Silva <rmfrfs@gmail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 2f03d3cb
Loading
Loading
Loading
Loading
+47 −88
Original line number Diff line number Diff line
@@ -327,10 +327,6 @@ struct mipi_csis_device {
	u32 hs_settle;
	u32 clk_settle;

	struct mutex lock;	/* Protect csis_fmt and format_mbus */
	const struct csis_pix_format *csis_fmt;
	struct v4l2_mbus_framefmt format_mbus[CSIS_PADS_NUM];

	spinlock_t slock;	/* Protect events */
	struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
	struct dentry *debugfs_root;
@@ -559,7 +555,6 @@ static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on)
	mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val);
}

/* Called with the csis.lock mutex held */
static void __mipi_csis_set_format(struct mipi_csis_device *csis,
				   const struct v4l2_mbus_framefmt *format,
				   const struct csis_pix_format *csis_fmt)
@@ -941,79 +936,67 @@ static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev *sdev)
static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
{
	struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
	const struct v4l2_mbus_framefmt *format = &csis->format_mbus[CSIS_PAD_SINK];
	const struct csis_pix_format *csis_fmt = csis->csis_fmt;
	const struct v4l2_mbus_framefmt *format;
	const struct csis_pix_format *csis_fmt;
	struct v4l2_subdev_state *state;
	int ret;

	if (!enable) {
		mutex_lock(&csis->lock);

		v4l2_subdev_call(csis->src_sd, video, s_stream, 0);

		mipi_csis_stop_stream(csis);
		if (csis->debug.enable)
			mipi_csis_log_counters(csis, true);

		mutex_unlock(&csis->lock);

		pm_runtime_put(csis->dev);

		return 0;
	}

	state = v4l2_subdev_lock_and_get_active_state(sd);

	format = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SINK);
	csis_fmt = find_csis_format(format->code);

	ret = mipi_csis_calculate_params(csis, csis_fmt);
	if (ret < 0)
		return ret;
		goto err_unlock;

	mipi_csis_clear_counters(csis);

	ret = pm_runtime_resume_and_get(csis->dev);
	if (ret < 0)
		return ret;

	mutex_lock(&csis->lock);
		goto err_unlock;

	mipi_csis_start_stream(csis, format, csis_fmt);

	ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1);
	if (ret < 0)
		goto error;
		goto err_stop;

	mipi_csis_log_counters(csis, true);

	mutex_unlock(&csis->lock);
	v4l2_subdev_unlock_state(state);

	return 0;

error:
err_stop:
	mipi_csis_stop_stream(csis);
	mutex_unlock(&csis->lock);
	pm_runtime_put(csis->dev);
err_unlock:
	v4l2_subdev_unlock_state(state);

	return ret;
}

static struct v4l2_mbus_framefmt *
mipi_csis_get_format(struct mipi_csis_device *csis,
		     struct v4l2_subdev_state *sd_state,
		     enum v4l2_subdev_format_whence which,
		     unsigned int pad)
{
	if (which == V4L2_SUBDEV_FORMAT_TRY)
		return v4l2_subdev_get_try_format(&csis->sd, sd_state, pad);

	return &csis->format_mbus[pad];
}

static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
			      struct v4l2_subdev_state *sd_state)
{
	struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
	struct v4l2_mbus_framefmt *fmt_sink;
	struct v4l2_mbus_framefmt *fmt_source;
	enum v4l2_subdev_format_whence which;

	which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
	fmt_sink = mipi_csis_get_format(csis, sd_state, which, CSIS_PAD_SINK);
	fmt_sink = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SINK);
	fmt_source = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE);

	fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16;
	fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH;
@@ -1027,36 +1010,15 @@ static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
		V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace,
					      fmt_sink->ycbcr_enc);

	fmt_source = mipi_csis_get_format(csis, sd_state, which,
					  CSIS_PAD_SOURCE);
	*fmt_source = *fmt_sink;

	return 0;
}

static int mipi_csis_get_fmt(struct v4l2_subdev *sd,
			     struct v4l2_subdev_state *sd_state,
			     struct v4l2_subdev_format *sdformat)
{
	struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
	struct v4l2_mbus_framefmt *fmt;

	fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
				   sdformat->pad);

	mutex_lock(&csis->lock);
	sdformat->format = *fmt;
	mutex_unlock(&csis->lock);

	return 0;
}

static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
				    struct v4l2_subdev_state *sd_state,
				    struct v4l2_subdev_mbus_code_enum *code)
{
	struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);

	/*
	 * The CSIS can't transcode in any way, the source format is identical
	 * to the sink format.
@@ -1067,8 +1029,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
		if (code->index > 0)
			return -EINVAL;

		fmt = mipi_csis_get_format(csis, sd_state, code->which,
					   code->pad);
		fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad);
		code->code = fmt->code;
		return 0;
	}
@@ -1088,7 +1049,6 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
			     struct v4l2_subdev_state *sd_state,
			     struct v4l2_subdev_format *sdformat)
{
	struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
	struct csis_pix_format const *csis_fmt;
	struct v4l2_mbus_framefmt *fmt;
	unsigned int align;
@@ -1098,7 +1058,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
	 * modified.
	 */
	if (sdformat->pad == CSIS_PAD_SOURCE)
		return mipi_csis_get_fmt(sd, sd_state, sdformat);
		return v4l2_subdev_get_fmt(sd, sd_state, sdformat);

	if (sdformat->pad != CSIS_PAD_SINK)
		return -EINVAL;
@@ -1136,10 +1096,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
			      &sdformat->format.height, 1,
			      CSIS_MAX_PIX_HEIGHT, 0, 0);

	fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
				   sdformat->pad);

	mutex_lock(&csis->lock);
	fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);

	fmt->code = csis_fmt->code;
	fmt->width = sdformat->format.width;
@@ -1152,44 +1109,40 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
	sdformat->format = *fmt;

	/* Propagate the format from sink to source. */
	fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
				   CSIS_PAD_SOURCE);
	fmt = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE);
	*fmt = sdformat->format;

	/* The format on the source pad might change due to unpacking. */
	fmt->code = csis_fmt->output;

	/* Store the CSIS format descriptor for active formats. */
	if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
		csis->csis_fmt = csis_fmt;

	mutex_unlock(&csis->lock);

	return 0;
}

static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
				    struct v4l2_mbus_frame_desc *fd)
{
	struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
	struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[0];
	const struct csis_pix_format *csis_fmt;
	const struct v4l2_mbus_framefmt *fmt;
	struct v4l2_subdev_state *state;

	if (pad != CSIS_PAD_SOURCE)
		return -EINVAL;

	state = v4l2_subdev_lock_and_get_active_state(sd);
	fmt = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SOURCE);
	csis_fmt = find_csis_format(fmt->code);
	v4l2_subdev_unlock_state(state);

	fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL;
	fd->num_entries = 1;

	memset(entry, 0, sizeof(*entry));

	mutex_lock(&csis->lock);

	entry->flags = 0;
	entry->pixelcode = csis->csis_fmt->code;
	entry->pixelcode = csis_fmt->code;
	entry->bus.csi2.vc = 0;
	entry->bus.csi2.dt = csis->csis_fmt->data_type;

	mutex_unlock(&csis->lock);
	entry->bus.csi2.dt = csis_fmt->data_type;

	return 0;
}
@@ -1216,7 +1169,7 @@ static const struct v4l2_subdev_video_ops mipi_csis_video_ops = {
static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = {
	.init_cfg		= mipi_csis_init_cfg,
	.enum_mbus_code		= mipi_csis_enum_mbus_code,
	.get_fmt		= mipi_csis_get_fmt,
	.get_fmt		= v4l2_subdev_get_fmt,
	.set_fmt		= mipi_csis_set_fmt,
	.get_frame_desc		= mipi_csis_get_frame_desc,
};
@@ -1398,6 +1351,7 @@ static const struct dev_pm_ops mipi_csis_pm_ops = {
static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
{
	struct v4l2_subdev *sd = &csis->sd;
	int ret;

	v4l2_subdev_init(sd, &mipi_csis_subdev_ops);
	sd->owner = THIS_MODULE;
@@ -1419,15 +1373,21 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
		return -ENOENT;
	}

	csis->csis_fmt = &mipi_csis_formats[0];
	mipi_csis_init_cfg(sd, NULL);

	csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
					 | MEDIA_PAD_FL_MUST_CONNECT;
	csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
					   | MEDIA_PAD_FL_MUST_CONNECT;
	return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM,
				      csis->pads);
	ret = media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, csis->pads);
	if (ret)
		return ret;

	ret = v4l2_subdev_init_finalize(sd);
	if (ret) {
		media_entity_cleanup(&sd->entity);
		return ret;
	}

	return 0;
}

static int mipi_csis_parse_dt(struct mipi_csis_device *csis)
@@ -1452,7 +1412,6 @@ static int mipi_csis_probe(struct platform_device *pdev)
	if (!csis)
		return -ENOMEM;

	mutex_init(&csis->lock);
	spin_lock_init(&csis->slock);

	csis->dev = dev;
@@ -1533,6 +1492,7 @@ static int mipi_csis_probe(struct platform_device *pdev)
err_unregister_all:
	mipi_csis_debugfs_exit(csis);
err_cleanup:
	v4l2_subdev_cleanup(&csis->sd);
	media_entity_cleanup(&csis->sd.entity);
	v4l2_async_nf_unregister(&csis->notifier);
	v4l2_async_nf_cleanup(&csis->notifier);
@@ -1540,7 +1500,6 @@ static int mipi_csis_probe(struct platform_device *pdev)
err_disable_clock:
	mipi_csis_clk_disable(csis);
	fwnode_handle_put(csis->sd.fwnode);
	mutex_destroy(&csis->lock);

	return ret;
}
@@ -1558,9 +1517,9 @@ static int mipi_csis_remove(struct platform_device *pdev)
	pm_runtime_disable(&pdev->dev);
	mipi_csis_runtime_suspend(&pdev->dev);
	mipi_csis_clk_disable(csis);
	v4l2_subdev_cleanup(&csis->sd);
	media_entity_cleanup(&csis->sd.entity);
	fwnode_handle_put(csis->sd.fwnode);
	mutex_destroy(&csis->lock);
	pm_runtime_set_suspended(&pdev->dev);

	return 0;