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: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Tested-by: Adam Ford <aford173@gmail.com> #imx8mn-beacon Acked-by: Rui Miguel Silva <rmfrfs@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
2f03d3cb06
commit
11927d0fd0
@ -327,10 +327,6 @@ struct mipi_csis_device {
|
|||||||
u32 hs_settle;
|
u32 hs_settle;
|
||||||
u32 clk_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 */
|
spinlock_t slock; /* Protect events */
|
||||||
struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
|
struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
|
||||||
struct dentry *debugfs_root;
|
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);
|
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,
|
static void __mipi_csis_set_format(struct mipi_csis_device *csis,
|
||||||
const struct v4l2_mbus_framefmt *format,
|
const struct v4l2_mbus_framefmt *format,
|
||||||
const struct csis_pix_format *csis_fmt)
|
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)
|
static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
|
||||||
{
|
{
|
||||||
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
|
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 v4l2_mbus_framefmt *format;
|
||||||
const struct csis_pix_format *csis_fmt = csis->csis_fmt;
|
const struct csis_pix_format *csis_fmt;
|
||||||
|
struct v4l2_subdev_state *state;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!enable) {
|
if (!enable) {
|
||||||
mutex_lock(&csis->lock);
|
|
||||||
|
|
||||||
v4l2_subdev_call(csis->src_sd, video, s_stream, 0);
|
v4l2_subdev_call(csis->src_sd, video, s_stream, 0);
|
||||||
|
|
||||||
mipi_csis_stop_stream(csis);
|
mipi_csis_stop_stream(csis);
|
||||||
if (csis->debug.enable)
|
if (csis->debug.enable)
|
||||||
mipi_csis_log_counters(csis, true);
|
mipi_csis_log_counters(csis, true);
|
||||||
|
|
||||||
mutex_unlock(&csis->lock);
|
|
||||||
|
|
||||||
pm_runtime_put(csis->dev);
|
pm_runtime_put(csis->dev);
|
||||||
|
|
||||||
return 0;
|
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);
|
ret = mipi_csis_calculate_params(csis, csis_fmt);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto err_unlock;
|
||||||
|
|
||||||
mipi_csis_clear_counters(csis);
|
mipi_csis_clear_counters(csis);
|
||||||
|
|
||||||
ret = pm_runtime_resume_and_get(csis->dev);
|
ret = pm_runtime_resume_and_get(csis->dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto err_unlock;
|
||||||
|
|
||||||
mutex_lock(&csis->lock);
|
|
||||||
|
|
||||||
mipi_csis_start_stream(csis, format, csis_fmt);
|
mipi_csis_start_stream(csis, format, csis_fmt);
|
||||||
|
|
||||||
ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1);
|
ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto err_stop;
|
||||||
|
|
||||||
mipi_csis_log_counters(csis, true);
|
mipi_csis_log_counters(csis, true);
|
||||||
|
|
||||||
mutex_unlock(&csis->lock);
|
v4l2_subdev_unlock_state(state);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
err_stop:
|
||||||
mipi_csis_stop_stream(csis);
|
mipi_csis_stop_stream(csis);
|
||||||
mutex_unlock(&csis->lock);
|
|
||||||
pm_runtime_put(csis->dev);
|
pm_runtime_put(csis->dev);
|
||||||
|
err_unlock:
|
||||||
|
v4l2_subdev_unlock_state(state);
|
||||||
|
|
||||||
return ret;
|
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,
|
static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
|
||||||
struct v4l2_subdev_state *sd_state)
|
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_sink;
|
||||||
struct v4l2_mbus_framefmt *fmt_source;
|
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 = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SINK);
|
||||||
fmt_sink = mipi_csis_get_format(csis, sd_state, which, 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->code = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||||
fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH;
|
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,
|
V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace,
|
||||||
fmt_sink->ycbcr_enc);
|
fmt_sink->ycbcr_enc);
|
||||||
|
|
||||||
fmt_source = mipi_csis_get_format(csis, sd_state, which,
|
|
||||||
CSIS_PAD_SOURCE);
|
|
||||||
*fmt_source = *fmt_sink;
|
*fmt_source = *fmt_sink;
|
||||||
|
|
||||||
return 0;
|
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,
|
static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
|
||||||
struct v4l2_subdev_state *sd_state,
|
struct v4l2_subdev_state *sd_state,
|
||||||
struct v4l2_subdev_mbus_code_enum *code)
|
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
|
* The CSIS can't transcode in any way, the source format is identical
|
||||||
* to the sink format.
|
* to the sink format.
|
||||||
@ -1067,8 +1029,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
|
|||||||
if (code->index > 0)
|
if (code->index > 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
fmt = mipi_csis_get_format(csis, sd_state, code->which,
|
fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad);
|
||||||
code->pad);
|
|
||||||
code->code = fmt->code;
|
code->code = fmt->code;
|
||||||
return 0;
|
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_state *sd_state,
|
||||||
struct v4l2_subdev_format *sdformat)
|
struct v4l2_subdev_format *sdformat)
|
||||||
{
|
{
|
||||||
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
|
|
||||||
struct csis_pix_format const *csis_fmt;
|
struct csis_pix_format const *csis_fmt;
|
||||||
struct v4l2_mbus_framefmt *fmt;
|
struct v4l2_mbus_framefmt *fmt;
|
||||||
unsigned int align;
|
unsigned int align;
|
||||||
@ -1098,7 +1058,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
|
|||||||
* modified.
|
* modified.
|
||||||
*/
|
*/
|
||||||
if (sdformat->pad == CSIS_PAD_SOURCE)
|
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)
|
if (sdformat->pad != CSIS_PAD_SINK)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -1136,10 +1096,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
|
|||||||
&sdformat->format.height, 1,
|
&sdformat->format.height, 1,
|
||||||
CSIS_MAX_PIX_HEIGHT, 0, 0);
|
CSIS_MAX_PIX_HEIGHT, 0, 0);
|
||||||
|
|
||||||
fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
|
fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);
|
||||||
sdformat->pad);
|
|
||||||
|
|
||||||
mutex_lock(&csis->lock);
|
|
||||||
|
|
||||||
fmt->code = csis_fmt->code;
|
fmt->code = csis_fmt->code;
|
||||||
fmt->width = sdformat->format.width;
|
fmt->width = sdformat->format.width;
|
||||||
@ -1152,44 +1109,40 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
|
|||||||
sdformat->format = *fmt;
|
sdformat->format = *fmt;
|
||||||
|
|
||||||
/* Propagate the format from sink to source. */
|
/* Propagate the format from sink to source. */
|
||||||
fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
|
fmt = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE);
|
||||||
CSIS_PAD_SOURCE);
|
|
||||||
*fmt = sdformat->format;
|
*fmt = sdformat->format;
|
||||||
|
|
||||||
/* The format on the source pad might change due to unpacking. */
|
/* The format on the source pad might change due to unpacking. */
|
||||||
fmt->code = csis_fmt->output;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
|
static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
|
||||||
struct v4l2_mbus_frame_desc *fd)
|
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];
|
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)
|
if (pad != CSIS_PAD_SOURCE)
|
||||||
return -EINVAL;
|
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->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL;
|
||||||
fd->num_entries = 1;
|
fd->num_entries = 1;
|
||||||
|
|
||||||
memset(entry, 0, sizeof(*entry));
|
memset(entry, 0, sizeof(*entry));
|
||||||
|
|
||||||
mutex_lock(&csis->lock);
|
|
||||||
|
|
||||||
entry->flags = 0;
|
entry->flags = 0;
|
||||||
entry->pixelcode = csis->csis_fmt->code;
|
entry->pixelcode = csis_fmt->code;
|
||||||
entry->bus.csi2.vc = 0;
|
entry->bus.csi2.vc = 0;
|
||||||
entry->bus.csi2.dt = csis->csis_fmt->data_type;
|
entry->bus.csi2.dt = csis_fmt->data_type;
|
||||||
|
|
||||||
mutex_unlock(&csis->lock);
|
|
||||||
|
|
||||||
return 0;
|
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 = {
|
static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = {
|
||||||
.init_cfg = mipi_csis_init_cfg,
|
.init_cfg = mipi_csis_init_cfg,
|
||||||
.enum_mbus_code = mipi_csis_enum_mbus_code,
|
.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,
|
.set_fmt = mipi_csis_set_fmt,
|
||||||
.get_frame_desc = mipi_csis_get_frame_desc,
|
.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)
|
static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
|
||||||
{
|
{
|
||||||
struct v4l2_subdev *sd = &csis->sd;
|
struct v4l2_subdev *sd = &csis->sd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
v4l2_subdev_init(sd, &mipi_csis_subdev_ops);
|
v4l2_subdev_init(sd, &mipi_csis_subdev_ops);
|
||||||
sd->owner = THIS_MODULE;
|
sd->owner = THIS_MODULE;
|
||||||
@ -1419,15 +1373,21 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
|
|||||||
return -ENOENT;
|
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
|
csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
|
||||||
| MEDIA_PAD_FL_MUST_CONNECT;
|
| MEDIA_PAD_FL_MUST_CONNECT;
|
||||||
csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
|
csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
|
||||||
| MEDIA_PAD_FL_MUST_CONNECT;
|
| MEDIA_PAD_FL_MUST_CONNECT;
|
||||||
return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM,
|
ret = media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, csis->pads);
|
||||||
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)
|
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)
|
if (!csis)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
mutex_init(&csis->lock);
|
|
||||||
spin_lock_init(&csis->slock);
|
spin_lock_init(&csis->slock);
|
||||||
|
|
||||||
csis->dev = dev;
|
csis->dev = dev;
|
||||||
@ -1533,6 +1492,7 @@ static int mipi_csis_probe(struct platform_device *pdev)
|
|||||||
err_unregister_all:
|
err_unregister_all:
|
||||||
mipi_csis_debugfs_exit(csis);
|
mipi_csis_debugfs_exit(csis);
|
||||||
err_cleanup:
|
err_cleanup:
|
||||||
|
v4l2_subdev_cleanup(&csis->sd);
|
||||||
media_entity_cleanup(&csis->sd.entity);
|
media_entity_cleanup(&csis->sd.entity);
|
||||||
v4l2_async_nf_unregister(&csis->notifier);
|
v4l2_async_nf_unregister(&csis->notifier);
|
||||||
v4l2_async_nf_cleanup(&csis->notifier);
|
v4l2_async_nf_cleanup(&csis->notifier);
|
||||||
@ -1540,7 +1500,6 @@ err_cleanup:
|
|||||||
err_disable_clock:
|
err_disable_clock:
|
||||||
mipi_csis_clk_disable(csis);
|
mipi_csis_clk_disable(csis);
|
||||||
fwnode_handle_put(csis->sd.fwnode);
|
fwnode_handle_put(csis->sd.fwnode);
|
||||||
mutex_destroy(&csis->lock);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1558,9 +1517,9 @@ static int mipi_csis_remove(struct platform_device *pdev)
|
|||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
mipi_csis_runtime_suspend(&pdev->dev);
|
mipi_csis_runtime_suspend(&pdev->dev);
|
||||||
mipi_csis_clk_disable(csis);
|
mipi_csis_clk_disable(csis);
|
||||||
|
v4l2_subdev_cleanup(&csis->sd);
|
||||||
media_entity_cleanup(&csis->sd.entity);
|
media_entity_cleanup(&csis->sd.entity);
|
||||||
fwnode_handle_put(csis->sd.fwnode);
|
fwnode_handle_put(csis->sd.fwnode);
|
||||||
mutex_destroy(&csis->lock);
|
|
||||||
pm_runtime_set_suspended(&pdev->dev);
|
pm_runtime_set_suspended(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user