aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/platform/nxp/imx-mipi-csis.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/nxp/imx-mipi-csis.c')
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c252
1 files changed, 106 insertions, 146 deletions
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 905072871ed2..be2768a47995 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -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,10 +555,10 @@ 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)
+static void __mipi_csis_set_format(struct mipi_csis_device *csis,
+ const struct v4l2_mbus_framefmt *format,
+ const struct csis_pix_format *csis_fmt)
{
- struct v4l2_mbus_framefmt *mf = &csis->format_mbus[CSIS_PAD_SINK];
u32 val;
/* Color format */
@@ -583,25 +579,26 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis)
*
* TODO: Verify which other formats require DUAL (or QUAD) modes.
*/
- if (csis->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8)
+ if (csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8)
val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL;
- val |= MIPI_CSIS_ISPCFG_FMT(csis->csis_fmt->data_type);
+ val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type);
mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val);
/* Pixel resolution */
- val = mf->width | (mf->height << 16);
+ val = format->width | (format->height << 16);
mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val);
}
-static int mipi_csis_calculate_params(struct mipi_csis_device *csis)
+static int mipi_csis_calculate_params(struct mipi_csis_device *csis,
+ const struct csis_pix_format *csis_fmt)
{
s64 link_freq;
u32 lane_rate;
/* Calculate the line rate from the pixel rate. */
link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler,
- csis->csis_fmt->width,
+ csis_fmt->width,
csis->bus.num_data_lanes * 2);
if (link_freq < 0) {
dev_err(csis->dev, "Unable to obtain link frequency: %d\n",
@@ -643,7 +640,9 @@ static int mipi_csis_calculate_params(struct mipi_csis_device *csis)
return 0;
}
-static void mipi_csis_set_params(struct mipi_csis_device *csis)
+static void mipi_csis_set_params(struct mipi_csis_device *csis,
+ const struct v4l2_mbus_framefmt *format,
+ const struct csis_pix_format *csis_fmt)
{
int lanes = csis->bus.num_data_lanes;
u32 val;
@@ -655,7 +654,7 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis)
val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val);
- __mipi_csis_set_format(csis);
+ __mipi_csis_set_format(csis, format, csis_fmt);
mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL,
MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) |
@@ -728,10 +727,12 @@ static int mipi_csis_clk_get(struct mipi_csis_device *csis)
return ret;
}
-static void mipi_csis_start_stream(struct mipi_csis_device *csis)
+static void mipi_csis_start_stream(struct mipi_csis_device *csis,
+ const struct v4l2_mbus_framefmt *format,
+ const struct csis_pix_format *csis_fmt)
{
mipi_csis_sw_reset(csis);
- mipi_csis_set_params(csis);
+ mipi_csis_set_params(csis, format, csis_fmt);
mipi_csis_system_enable(csis, true);
mipi_csis_enable_interrupts(csis, true);
}
@@ -935,120 +936,63 @@ 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;
+ 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;
}
- ret = mipi_csis_calculate_params(csis);
+ 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;
+ goto err_unlock;
- mutex_lock(&csis->lock);
+ mipi_csis_start_stream(csis, format, csis_fmt);
- mipi_csis_start_stream(csis);
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->code = MEDIA_BUS_FMT_UYVY8_1X16;
- fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH;
- fmt_sink->height = MIPI_CSIS_DEF_PIX_HEIGHT;
- fmt_sink->field = V4L2_FIELD_NONE;
-
- fmt_sink->colorspace = V4L2_COLORSPACE_SMPTE170M;
- fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace);
- fmt_sink->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt_sink->colorspace);
- fmt_sink->quantization =
- 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.
@@ -1059,8 +1003,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;
}
@@ -1080,7 +1023,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;
@@ -1090,7 +1032,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;
@@ -1128,14 +1070,12 @@ 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;
fmt->height = sdformat->format.height;
+ fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = sdformat->format.colorspace;
fmt->quantization = sdformat->format.quantization;
fmt->xfer_func = sdformat->format.xfer_func;
@@ -1144,48 +1084,68 @@ 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);
+
+ if (!csis_fmt)
+ return -EPIPE;
+
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;
}
+static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_subdev_format fmt = {
+ .pad = CSIS_PAD_SINK,
+ };
+
+ fmt.format.code = mipi_csis_formats[0].code;
+ fmt.format.width = MIPI_CSIS_DEF_PIX_WIDTH;
+ fmt.format.height = MIPI_CSIS_DEF_PIX_HEIGHT;
+
+ fmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt.format.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt.format.colorspace);
+ fmt.format.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt.format.colorspace);
+ fmt.format.quantization =
+ V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt.format.colorspace,
+ fmt.format.ycbcr_enc);
+
+ return mipi_csis_set_fmt(sd, sd_state, &fmt);
+}
+
static int mipi_csis_log_status(struct v4l2_subdev *sd)
{
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
@@ -1208,7 +1168,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,
};
@@ -1348,40 +1308,34 @@ static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- int ret = 0;
-
- mutex_lock(&csis->lock);
+ int ret;
ret = mipi_csis_phy_disable(csis);
if (ret)
- goto unlock;
+ return -EAGAIN;
mipi_csis_clk_disable(csis);
-unlock:
- mutex_unlock(&csis->lock);
-
- return ret ? -EAGAIN : 0;
+ return 0;
}
static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- int ret = 0;
-
- mutex_lock(&csis->lock);
+ int ret;
ret = mipi_csis_phy_enable(csis);
if (ret)
- goto unlock;
-
- mipi_csis_clk_enable(csis);
+ return -EAGAIN;
-unlock:
- mutex_unlock(&csis->lock);
+ ret = mipi_csis_clk_enable(csis);
+ if (ret) {
+ mipi_csis_phy_disable(csis);
+ return ret;
+ }
- return ret ? -EAGAIN : 0;
+ return 0;
}
static const struct dev_pm_ops mipi_csis_pm_ops = {
@@ -1396,6 +1350,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;
@@ -1417,15 +1372,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)
@@ -1450,7 +1411,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;
@@ -1496,20 +1456,20 @@ static int mipi_csis_probe(struct platform_device *pdev)
dev_name(dev), csis);
if (ret) {
dev_err(dev, "Interrupt request failed\n");
- goto disable_clock;
+ goto err_disable_clock;
}
/* Initialize and register the subdev. */
ret = mipi_csis_subdev_init(csis);
if (ret < 0)
- goto disable_clock;
+ goto err_disable_clock;
platform_set_drvdata(pdev, &csis->sd);
ret = mipi_csis_async_register(csis);
if (ret < 0) {
dev_err(dev, "async register failed: %d\n", ret);
- goto cleanup;
+ goto err_cleanup;
}
/* Initialize debugfs. */
@@ -1520,7 +1480,7 @@ static int mipi_csis_probe(struct platform_device *pdev)
if (!pm_runtime_enabled(dev)) {
ret = mipi_csis_runtime_resume(dev);
if (ret < 0)
- goto unregister_all;
+ goto err_unregister_all;
}
dev_info(dev, "lanes: %d, freq: %u\n",
@@ -1528,17 +1488,17 @@ static int mipi_csis_probe(struct platform_device *pdev)
return 0;
-unregister_all:
+err_unregister_all:
mipi_csis_debugfs_exit(csis);
-cleanup:
+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);
v4l2_async_unregister_subdev(&csis->sd);
-disable_clock:
+err_disable_clock:
mipi_csis_clk_disable(csis);
fwnode_handle_put(csis->sd.fwnode);
- mutex_destroy(&csis->lock);
return ret;
}
@@ -1556,9 +1516,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;