aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/platform/nxp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/nxp')
-rw-r--r--drivers/media/platform/nxp/Kconfig2
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h4
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c315
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h6
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c669
5 files changed, 544 insertions, 452 deletions
diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig
index 5afa373e534f..1ac0a6e91111 100644
--- a/drivers/media/platform/nxp/Kconfig
+++ b/drivers/media/platform/nxp/Kconfig
@@ -11,7 +11,6 @@ config VIDEO_IMX_MIPI_CSIS
select MEDIA_CONTROLLER
select V4L2_FWNODE
select VIDEO_V4L2_SUBDEV_API
- default n
help
Video4Linux2 sub-device driver for the MIPI CSI-2 CSIS receiver
v3.3/v3.6.3 found on some i.MX7 and i.MX8 SoCs.
@@ -21,7 +20,6 @@ config VIDEO_VIU
depends on V4L_PLATFORM_DRIVERS
depends on VIDEO_DEV && (PPC_MPC512x || COMPILE_TEST) && I2C
select VIDEOBUF_DMA_CONTIG
- default y
help
Support for Freescale VIU video driver. This device captures
video data, or overlays video on DIU frame buffer.
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
index ae70d3a0dc24..d838e875616c 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
@@ -102,11 +102,11 @@ enum mxc_jpeg_image_format {
MXC_JPEG_INVALID = -1,
MXC_JPEG_YUV420 = 0x0, /* 2 Plannar, Y=1st plane UV=2nd plane */
MXC_JPEG_YUV422 = 0x1, /* 1 Plannar, YUYV sequence */
- MXC_JPEG_RGB = 0x2, /* RGBRGB packed format */
+ MXC_JPEG_BGR = 0x2, /* BGR packed format */
MXC_JPEG_YUV444 = 0x3, /* 1 Plannar, YUVYUV sequence */
MXC_JPEG_GRAY = 0x4, /* Y8 or Y12 or Single Component */
MXC_JPEG_RESERVED = 0x5,
- MXC_JPEG_ARGB = 0x6,
+ MXC_JPEG_ABGR = 0x6,
};
#include "mxc-jpeg.h"
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index d1ec1f4b506b..f36b512bae51 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -8,7 +8,7 @@
* Baseline and extended sequential jpeg decoding is supported.
* Progressive jpeg decoding is not supported by the IP.
* Supports encode and decode of various formats:
- * YUV444, YUV422, YUV420, RGB, ARGB, Gray
+ * YUV444, YUV422, YUV420, BGR, ABGR, Gray
* YUV420 is the only multi-planar format supported.
* Minimum resolution is 64 x 64, maximum 8192 x 8192.
* To achieve 8192 x 8192, modify in defconfig: CONFIG_CMA_SIZE_MBYTES=320
@@ -73,8 +73,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.flags = MXC_JPEG_FMT_TYPE_ENC,
},
{
- .name = "RGB", /*RGBRGB packed format*/
- .fourcc = V4L2_PIX_FMT_RGB24,
+ .name = "BGR", /*BGR packed format*/
+ .fourcc = V4L2_PIX_FMT_BGR24,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
.nc = 3,
.depth = 24,
@@ -82,10 +82,11 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.h_align = 3,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 8,
},
{
- .name = "ARGB", /* ARGBARGB packed format */
- .fourcc = V4L2_PIX_FMT_ARGB32,
+ .name = "ABGR", /* ABGR packed format */
+ .fourcc = V4L2_PIX_FMT_ABGR32,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
.nc = 4,
.depth = 32,
@@ -93,6 +94,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.h_align = 3,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 8,
},
{
.name = "YUV420", /* 1st plane = Y, 2nd plane = UV */
@@ -104,6 +106,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.h_align = 4,
.v_align = 4,
.flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 8,
},
{
.name = "YUV422", /* YUYV */
@@ -115,6 +118,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.h_align = 4,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 8,
},
{
.name = "YUV444", /* YUVYUV */
@@ -126,6 +130,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.h_align = 3,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 8,
},
{
.name = "Gray", /* Gray (Y8/Y12) or Single Comp */
@@ -137,6 +142,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.h_align = 3,
.v_align = 3,
.flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 8,
},
};
@@ -309,6 +315,9 @@ struct mxc_jpeg_src_buf {
/* mxc-jpeg specific */
bool dht_needed;
bool jpeg_parse_error;
+ const struct mxc_jpeg_fmt *fmt;
+ int w;
+ int h;
};
static inline struct mxc_jpeg_src_buf *vb2_to_mxc_buf(struct vb2_buffer *vb)
@@ -321,6 +330,9 @@ static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-3)");
+static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision);
+static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q);
+
static void _bswap16(u16 *a)
{
*a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8);
@@ -408,10 +420,10 @@ static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(u32 fourcc)
return MXC_JPEG_YUV420;
case V4L2_PIX_FMT_YUV24:
return MXC_JPEG_YUV444;
- case V4L2_PIX_FMT_RGB24:
- return MXC_JPEG_RGB;
- case V4L2_PIX_FMT_ARGB32:
- return MXC_JPEG_ARGB;
+ case V4L2_PIX_FMT_BGR24:
+ return MXC_JPEG_BGR;
+ case V4L2_PIX_FMT_ABGR32:
+ return MXC_JPEG_ABGR;
default:
return MXC_JPEG_INVALID;
}
@@ -684,11 +696,11 @@ static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof,
sof->comp[0].h = 0x2;
break;
case V4L2_PIX_FMT_YUV24:
- case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
default:
sof->components_no = 3;
break;
- case V4L2_PIX_FMT_ARGB32:
+ case V4L2_PIX_FMT_ABGR32:
sof->components_no = 4;
break;
case V4L2_PIX_FMT_GREY:
@@ -716,11 +728,11 @@ static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos,
sos->components_no = 3;
break;
case V4L2_PIX_FMT_YUV24:
- case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
default:
sos->components_no = 3;
break;
- case V4L2_PIX_FMT_ARGB32:
+ case V4L2_PIX_FMT_ABGR32:
sos->components_no = 4;
break;
case V4L2_PIX_FMT_GREY:
@@ -751,8 +763,8 @@ static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr,
memcpy(cfg + offset, jpeg_soi, ARRAY_SIZE(jpeg_soi));
offset += ARRAY_SIZE(jpeg_soi);
- if (fourcc == V4L2_PIX_FMT_RGB24 ||
- fourcc == V4L2_PIX_FMT_ARGB32) {
+ if (fourcc == V4L2_PIX_FMT_BGR24 ||
+ fourcc == V4L2_PIX_FMT_ABGR32) {
memcpy(cfg + offset, jpeg_app14, sizeof(jpeg_app14));
offset += sizeof(jpeg_app14);
} else {
@@ -916,6 +928,67 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
mxc_jpeg_set_desc(cfg_desc_handle, reg, slot);
}
+static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx,
+ struct mxc_jpeg_src_buf *jpeg_src_buf)
+{
+ struct device *dev = ctx->mxc_jpeg->dev;
+ struct mxc_jpeg_q_data *q_data_cap;
+
+ if (!jpeg_src_buf->fmt)
+ return false;
+
+ q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (q_data_cap->fmt != jpeg_src_buf->fmt ||
+ q_data_cap->w != jpeg_src_buf->w ||
+ q_data_cap->h != jpeg_src_buf->h) {
+ dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%c%c%c%c\n",
+ q_data_cap->w, q_data_cap->h,
+ jpeg_src_buf->w, jpeg_src_buf->h,
+ (jpeg_src_buf->fmt->fourcc & 0xff),
+ (jpeg_src_buf->fmt->fourcc >> 8) & 0xff,
+ (jpeg_src_buf->fmt->fourcc >> 16) & 0xff,
+ (jpeg_src_buf->fmt->fourcc >> 24) & 0xff);
+
+ /*
+ * set-up the capture queue with the pixelformat and resolution
+ * detected from the jpeg output stream
+ */
+ q_data_cap->w = jpeg_src_buf->w;
+ q_data_cap->h = jpeg_src_buf->h;
+ q_data_cap->fmt = jpeg_src_buf->fmt;
+ q_data_cap->w_adjusted = q_data_cap->w;
+ q_data_cap->h_adjusted = q_data_cap->h;
+
+ /*
+ * align up the resolution for CAST IP,
+ * but leave the buffer resolution unchanged
+ */
+ v4l_bound_align_image(&q_data_cap->w_adjusted,
+ q_data_cap->w_adjusted, /* adjust up */
+ MXC_JPEG_MAX_WIDTH,
+ q_data_cap->fmt->h_align,
+ &q_data_cap->h_adjusted,
+ q_data_cap->h_adjusted, /* adjust up */
+ MXC_JPEG_MAX_HEIGHT,
+ q_data_cap->fmt->v_align,
+ 0);
+
+ /* setup bytesperline/sizeimage for capture queue */
+ mxc_jpeg_bytesperline(q_data_cap, jpeg_src_buf->fmt->precision);
+ mxc_jpeg_sizeimage(q_data_cap);
+ notify_src_chg(ctx);
+ ctx->source_change = 1;
+ }
+ return ctx->source_change ? true : false;
+}
+
+static int mxc_jpeg_job_ready(void *priv)
+{
+ struct mxc_jpeg_ctx *ctx = priv;
+
+ return ctx->source_change ? 0 : 1;
+}
+
static void mxc_jpeg_device_run(void *priv)
{
struct mxc_jpeg_ctx *ctx = priv;
@@ -963,6 +1036,13 @@ static void mxc_jpeg_device_run(void *priv)
return;
}
+ if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) {
+ if (ctx->source_change || mxc_jpeg_source_change(ctx, jpeg_src_buf)) {
+ spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ return;
+ }
+ }
mxc_jpeg_enable(reg);
mxc_jpeg_set_l_endian(reg, 1);
@@ -1009,6 +1089,7 @@ static void mxc_jpeg_set_last_buffer_dequeued(struct mxc_jpeg_ctx *ctx)
q->last_buffer_dequeued = true;
wake_up(&q->done_wq);
ctx->stopped = 0;
+ ctx->header_parsed = false;
}
static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
@@ -1081,6 +1162,8 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q,
/* Handle CREATE_BUFS situation - *nplanes != 0 */
if (*nplanes) {
+ if (*nplanes != q_data->fmt->colplanes)
+ return -EINVAL;
for (i = 0; i < *nplanes; i++) {
if (sizes[i] < q_data->sizeimage[i])
return -EINVAL;
@@ -1102,6 +1185,8 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, q->type);
int ret;
+ if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(q->type))
+ ctx->source_change = 0;
dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx);
q_data->sequence = 0;
@@ -1175,14 +1260,17 @@ static u32 mxc_jpeg_get_image_format(struct device *dev,
for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++)
if (mxc_formats[i].subsampling == header->frame.subsampling &&
- mxc_formats[i].nc == header->frame.num_components) {
+ mxc_formats[i].nc == header->frame.num_components &&
+ mxc_formats[i].precision == header->frame.precision) {
fourcc = mxc_formats[i].fourcc;
break;
}
if (fourcc == 0) {
- dev_err(dev, "Could not identify image format nc=%d, subsampling=%d\n",
+ dev_err(dev,
+ "Could not identify image format nc=%d, subsampling=%d, precision=%d\n",
header->frame.num_components,
- header->frame.subsampling);
+ header->frame.subsampling,
+ header->frame.precision);
return fourcc;
}
/*
@@ -1190,9 +1278,9 @@ static u32 mxc_jpeg_get_image_format(struct device *dev,
* encoded with 3 components have RGB colorspace, see Recommendation
* ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding
*/
- if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_RGB24) {
+ if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_BGR24) {
if (header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB)
- fourcc = V4L2_PIX_FMT_RGB24;
+ fourcc = V4L2_PIX_FMT_BGR24;
else
fourcc = V4L2_PIX_FMT_YUV24;
}
@@ -1200,26 +1288,29 @@ static u32 mxc_jpeg_get_image_format(struct device *dev,
return fourcc;
}
-static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q,
- u32 precision)
+static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision)
{
/* Bytes distance between the leftmost pixels in two adjacent lines */
if (q->fmt->fourcc == V4L2_PIX_FMT_JPEG) {
/* bytesperline unused for compressed formats */
q->bytesperline[0] = 0;
q->bytesperline[1] = 0;
- } else if (q->fmt->fourcc == V4L2_PIX_FMT_NV12M) {
+ } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420) {
/* When the image format is planar the bytesperline value
* applies to the first plane and is divided by the same factor
* as the width field for the other planes
*/
- q->bytesperline[0] = q->w * (precision / 8) *
- (q->fmt->depth / 8);
+ q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8);
q->bytesperline[1] = q->bytesperline[0];
+ } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) {
+ q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * 2;
+ q->bytesperline[1] = 0;
+ } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_444) {
+ q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * q->fmt->nc;
+ q->bytesperline[1] = 0;
} else {
- /* single plane formats */
- q->bytesperline[0] = q->w * (precision / 8) *
- (q->fmt->depth / 8);
+ /* grayscale */
+ q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8);
q->bytesperline[1] = 0;
}
}
@@ -1245,17 +1336,17 @@ static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q)
}
}
-static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
- u8 *src_addr, u32 size, bool *dht_needed)
+static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb)
{
struct device *dev = ctx->mxc_jpeg->dev;
- struct mxc_jpeg_q_data *q_data_out, *q_data_cap;
- enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- bool src_chg = false;
+ struct mxc_jpeg_q_data *q_data_out;
u32 fourcc;
struct v4l2_jpeg_header header;
struct mxc_jpeg_sof *psof = NULL;
struct mxc_jpeg_sos *psos = NULL;
+ struct mxc_jpeg_src_buf *jpeg_src_buf = vb2_to_mxc_buf(vb);
+ u8 *src_addr = (u8 *)vb2_plane_vaddr(vb, 0);
+ u32 size = vb2_get_plane_payload(vb, 0);
int ret;
memset(&header, 0, sizeof(header));
@@ -1266,7 +1357,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
}
/* if DHT marker present, no need to inject default one */
- *dht_needed = (header.num_dht == 0);
+ jpeg_src_buf->dht_needed = (header.num_dht == 0);
q_data_out = mxc_jpeg_get_q_data(ctx,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
@@ -1274,16 +1365,15 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
dev_warn(dev, "Invalid user resolution 0x0");
dev_warn(dev, "Keeping resolution from JPEG: %dx%d",
header.frame.width, header.frame.height);
- q_data_out->w = header.frame.width;
- q_data_out->h = header.frame.height;
} else if (header.frame.width != q_data_out->w ||
header.frame.height != q_data_out->h) {
dev_err(dev,
"Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)",
header.frame.width, header.frame.height,
q_data_out->w, q_data_out->h);
- return -EINVAL;
}
+ q_data_out->w = header.frame.width;
+ q_data_out->h = header.frame.height;
if (header.frame.width % 8 != 0 || header.frame.height % 8 != 0) {
dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n",
header.frame.width, header.frame.height);
@@ -1316,51 +1406,13 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
if (fourcc == 0)
return -EINVAL;
- /*
- * set-up the capture queue with the pixelformat and resolution
- * detected from the jpeg output stream
- */
- q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type);
- if (q_data_cap->w != header.frame.width ||
- q_data_cap->h != header.frame.height)
- src_chg = true;
- q_data_cap->w = header.frame.width;
- q_data_cap->h = header.frame.height;
- q_data_cap->fmt = mxc_jpeg_find_format(ctx, fourcc);
- q_data_cap->w_adjusted = q_data_cap->w;
- q_data_cap->h_adjusted = q_data_cap->h;
- /*
- * align up the resolution for CAST IP,
- * but leave the buffer resolution unchanged
- */
- v4l_bound_align_image(&q_data_cap->w_adjusted,
- q_data_cap->w_adjusted, /* adjust up */
- MXC_JPEG_MAX_WIDTH,
- q_data_cap->fmt->h_align,
- &q_data_cap->h_adjusted,
- q_data_cap->h_adjusted, /* adjust up */
- MXC_JPEG_MAX_HEIGHT,
- q_data_cap->fmt->v_align,
- 0);
- dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%c%c%c%c\n",
- q_data_cap->w, q_data_cap->h,
- q_data_cap->w_adjusted, q_data_cap->h_adjusted,
- (fourcc & 0xff),
- (fourcc >> 8) & 0xff,
- (fourcc >> 16) & 0xff,
- (fourcc >> 24) & 0xff);
-
- /* setup bytesperline/sizeimage for capture queue */
- mxc_jpeg_bytesperline(q_data_cap, header.frame.precision);
- mxc_jpeg_sizeimage(q_data_cap);
+ jpeg_src_buf->fmt = mxc_jpeg_find_format(ctx, fourcc);
+ jpeg_src_buf->w = header.frame.width;
+ jpeg_src_buf->h = header.frame.height;
+ ctx->header_parsed = true;
- /*
- * if the CAPTURE format was updated with new values, regardless of
- * whether they match the values set by the client or not, signal
- * a source change event
- */
- if (src_chg)
- notify_src_chg(ctx);
+ if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx))
+ mxc_jpeg_source_change(ctx, jpeg_src_buf);
return 0;
}
@@ -1381,10 +1433,7 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb)
jpeg_src_buf = vb2_to_mxc_buf(vb);
jpeg_src_buf->jpeg_parse_error = false;
- ret = mxc_jpeg_parse(ctx,
- (u8 *)vb2_plane_vaddr(vb, 0),
- vb2_get_plane_payload(vb, 0),
- &jpeg_src_buf->dht_needed);
+ ret = mxc_jpeg_parse(ctx, vb);
if (ret)
jpeg_src_buf->jpeg_parse_error = true;
@@ -1422,7 +1471,6 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb)
i, vb2_plane_size(vb, i), sizeimage);
return -EINVAL;
}
- vb2_set_plane_payload(vb, i, sizeimage);
}
return 0;
}
@@ -1440,6 +1488,7 @@ static void mxc_jpeg_buf_finish(struct vb2_buffer *vb)
if (list_empty(&q->done_list)) {
vbuf->flags |= V4L2_BUF_FLAG_LAST;
ctx->stopped = 0;
+ ctx->header_parsed = false;
}
}
@@ -1470,7 +1519,6 @@ static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->mxc_jpeg->lock;
src_vq->dev = ctx->mxc_jpeg->dev;
- src_vq->allow_zero_bytesused = 1; /* keep old userspace apps working */
ret = vb2_queue_init(src_vq);
if (ret)
@@ -1510,7 +1558,7 @@ static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx)
q[i]->h = MXC_JPEG_DEFAULT_HEIGHT;
q[i]->w_adjusted = MXC_JPEG_DEFAULT_WIDTH;
q[i]->h_adjusted = MXC_JPEG_DEFAULT_HEIGHT;
- mxc_jpeg_bytesperline(q[i], 8);
+ mxc_jpeg_bytesperline(q[i], q[i]->fmt->precision);
mxc_jpeg_sizeimage(q[i]);
}
}
@@ -1569,12 +1617,8 @@ free:
static int mxc_jpeg_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file);
-
strscpy(cap->driver, MXC_JPEG_NAME " codec", sizeof(cap->driver));
strscpy(cap->card, MXC_JPEG_NAME " codec", sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
- dev_name(mxc_jpeg->dev));
cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -1585,26 +1629,42 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type);
- if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE)
+ if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) {
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_JPEG_FMT_TYPE_ENC);
- else
+ } else if (!ctx->header_parsed) {
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_JPEG_FMT_TYPE_RAW);
+ } else {
+ /* For the decoder CAPTURE queue, only enumerate the raw formats
+ * supported for the format currently active on OUTPUT
+ * (more precisely what was propagated on capture queue
+ * after jpeg parse on the output buffer)
+ */
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = q_data->fmt->fourcc;
+ strscpy(f->description, q_data->fmt->name, sizeof(f->description));
+ return 0;
+ }
}
static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ u32 type = ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? MXC_JPEG_FMT_TYPE_ENC :
+ MXC_JPEG_FMT_TYPE_RAW;
+ int ret;
+ ret = enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, type);
+ if (ret)
+ return ret;
if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE)
- return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
- MXC_JPEG_FMT_TYPE_ENC);
- else
- return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
- MXC_JPEG_FMT_TYPE_RAW);
+ f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION;
+ return 0;
}
static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fmt,
@@ -1652,7 +1712,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fm
}
/* calculate bytesperline & sizeimage into the tmp_q */
- mxc_jpeg_bytesperline(&tmp_q, 8);
+ mxc_jpeg_bytesperline(&tmp_q, fmt->precision);
mxc_jpeg_sizeimage(&tmp_q);
/* adjust user format according to our calculations */
@@ -1819,12 +1879,40 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
int ret;
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct vb2_queue *dst_vq;
+ struct mxc_jpeg_q_data *q_data_cap;
+ enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ struct v4l2_format fc;
ret = mxc_jpeg_try_fmt_vid_out(file, priv, f);
if (ret)
return ret;
- return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
+ ret = mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
+ if (ret)
+ return ret;
+
+ if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE)
+ return 0;
+
+ dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, cap_type);
+ if (!dst_vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(dst_vq))
+ return 0;
+
+ q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type);
+ if (q_data_cap->w == f->fmt.pix_mp.width && q_data_cap->h == f->fmt.pix_mp.height)
+ return 0;
+ memset(&fc, 0, sizeof(fc));
+ fc.type = cap_type;
+ fc.fmt.pix_mp.pixelformat = q_data_cap->fmt->fourcc;
+ fc.fmt.pix_mp.width = f->fmt.pix_mp.width;
+ fc.fmt.pix_mp.height = f->fmt.pix_mp.height;
+
+ return mxc_jpeg_s_fmt_vid_cap(file, priv, &fc);
}
static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv,
@@ -1962,6 +2050,7 @@ static const struct v4l2_file_operations mxc_jpeg_fops = {
};
static const struct v4l2_m2m_ops mxc_jpeg_m2m_ops = {
+ .job_ready = mxc_jpeg_job_ready,
.device_run = mxc_jpeg_device_run,
};
@@ -2213,9 +2302,33 @@ static int mxc_jpeg_runtime_suspend(struct device *dev)
}
#endif
+#ifdef CONFIG_PM_SLEEP
+static int mxc_jpeg_suspend(struct device *dev)
+{
+ struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
+
+ v4l2_m2m_suspend(jpeg->m2m_dev);
+ return pm_runtime_force_suspend(dev);
+}
+
+static int mxc_jpeg_resume(struct device *dev)
+{
+ struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ return ret;
+
+ v4l2_m2m_resume(jpeg->m2m_dev);
+ return ret;
+}
+#endif
+
static const struct dev_pm_ops mxc_jpeg_pm_ops = {
SET_RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend,
mxc_jpeg_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume)
};
static int mxc_jpeg_remove(struct platform_device *pdev)
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
index f53f004ba851..760eaf5387a1 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
@@ -17,7 +17,7 @@
#define MXC_JPEG_FMT_TYPE_RAW 1
#define MXC_JPEG_DEFAULT_WIDTH 1280
#define MXC_JPEG_DEFAULT_HEIGHT 720
-#define MXC_JPEG_DEFAULT_PFMT V4L2_PIX_FMT_RGB24
+#define MXC_JPEG_DEFAULT_PFMT V4L2_PIX_FMT_BGR24
#define MXC_JPEG_MIN_WIDTH 64
#define MXC_JPEG_MIN_HEIGHT 64
#define MXC_JPEG_MAX_WIDTH 0x2000
@@ -49,6 +49,7 @@ enum mxc_jpeg_mode {
* @h_align: horizontal alignment order (align to 2^h_align)
* @v_align: vertical alignment order (align to 2^v_align)
* @flags: flags describing format applicability
+ * @precision: jpeg sample precision
*/
struct mxc_jpeg_fmt {
const char *name;
@@ -60,6 +61,7 @@ struct mxc_jpeg_fmt {
int h_align;
int v_align;
u32 flags;
+ u8 precision;
};
struct mxc_jpeg_desc {
@@ -93,6 +95,8 @@ struct mxc_jpeg_ctx {
unsigned int stopping;
unsigned int stopped;
unsigned int slot;
+ unsigned int source_change;
+ bool header_parsed;
};
struct mxc_jpeg_slot_data {
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 0a72734db55e..80b1c021d14a 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -243,12 +243,6 @@
#define MIPI_CSI2_DATA_TYPE_RAW14 0x2d
#define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x))
-enum {
- ST_POWERED = 1,
- ST_STREAMING = 2,
- ST_SUSPENDED = 4,
-};
-
struct mipi_csis_event {
bool debug;
u32 mask;
@@ -310,7 +304,7 @@ struct mipi_csis_info {
unsigned int num_clocks;
};
-struct csi_state {
+struct mipi_csis_device {
struct device *dev;
void __iomem *regs;
struct clk_bulk_data *clks;
@@ -328,10 +322,9 @@ struct csi_state {
u32 hs_settle;
u32 clk_settle;
- struct mutex lock; /* Protect csis_fmt, format_mbus and state */
+ 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];
- u32 state;
spinlock_t slock; /* Protect events */
struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
@@ -470,6 +463,34 @@ static const struct csis_pix_format mipi_csis_formats[] = {
.output = MEDIA_BUS_FMT_SRGGB14_1X14,
.data_type = MIPI_CSI2_DATA_TYPE_RAW14,
.width = 14,
+ },
+ /* JPEG */
+ {
+ .code = MEDIA_BUS_FMT_JPEG_1X8,
+ .output = MEDIA_BUS_FMT_JPEG_1X8,
+ /*
+ * Map JPEG_1X8 to the RAW8 datatype.
+ *
+ * The CSI-2 specification suggests in Annex A "JPEG8 Data
+ * Format (informative)" to transmit JPEG data using one of the
+ * Data Types aimed to represent arbitrary data, such as the
+ * "User Defined Data Type 1" (0x30).
+ *
+ * However, when configured with a User Defined Data Type, the
+ * CSIS outputs data in quad pixel mode regardless of the mode
+ * selected in the MIPI_CSIS_ISP_CONFIG_CH register. Neither of
+ * the IP cores connected to the CSIS in i.MX SoCs (CSI bridge
+ * or ISI) support quad pixel mode, so this will never work in
+ * practice.
+ *
+ * Some sensors (such as the OV5640) send JPEG data using the
+ * RAW8 data type. This is usable and works, so map the JPEG
+ * format to RAW8. If the CSIS ends up being integrated in an
+ * SoC that can support quad pixel mode, this will have to be
+ * revisited.
+ */
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
+ .width = 8,
}
};
@@ -487,59 +508,60 @@ static const struct csis_pix_format *find_csis_format(u32 code)
* Hardware configuration
*/
-static inline u32 mipi_csis_read(struct csi_state *state, u32 reg)
+static inline u32 mipi_csis_read(struct mipi_csis_device *csis, u32 reg)
{
- return readl(state->regs + reg);
+ return readl(csis->regs + reg);
}
-static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val)
+static inline void mipi_csis_write(struct mipi_csis_device *csis, u32 reg,
+ u32 val)
{
- writel(val, state->regs + reg);
+ writel(val, csis->regs + reg);
}
-static void mipi_csis_enable_interrupts(struct csi_state *state, bool on)
+static void mipi_csis_enable_interrupts(struct mipi_csis_device *csis, bool on)
{
- mipi_csis_write(state, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0);
- mipi_csis_write(state, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0);
+ mipi_csis_write(csis, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0);
+ mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0);
}
-static void mipi_csis_sw_reset(struct csi_state *state)
+static void mipi_csis_sw_reset(struct mipi_csis_device *csis)
{
- u32 val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+ u32 val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
- mipi_csis_write(state, MIPI_CSIS_CMN_CTRL,
+ mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL,
val | MIPI_CSIS_CMN_CTRL_RESET);
usleep_range(10, 20);
}
-static void mipi_csis_system_enable(struct csi_state *state, int on)
+static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on)
{
u32 val, mask;
- val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+ val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
if (on)
val |= MIPI_CSIS_CMN_CTRL_ENABLE;
else
val &= ~MIPI_CSIS_CMN_CTRL_ENABLE;
- mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
+ mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val);
- val = mipi_csis_read(state, MIPI_CSIS_DPHY_CMN_CTRL);
+ val = mipi_csis_read(csis, MIPI_CSIS_DPHY_CMN_CTRL);
val &= ~MIPI_CSIS_DPHY_CMN_CTRL_ENABLE;
if (on) {
- mask = (1 << (state->bus.num_data_lanes + 1)) - 1;
+ mask = (1 << (csis->bus.num_data_lanes + 1)) - 1;
val |= (mask & MIPI_CSIS_DPHY_CMN_CTRL_ENABLE);
}
- mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, val);
+ mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val);
}
-/* Called with the state.lock mutex held */
-static void __mipi_csis_set_format(struct csi_state *state)
+/* Called with the csis.lock mutex held */
+static void __mipi_csis_set_format(struct mipi_csis_device *csis)
{
- struct v4l2_mbus_framefmt *mf = &state->format_mbus[CSIS_PAD_SINK];
+ struct v4l2_mbus_framefmt *mf = &csis->format_mbus[CSIS_PAD_SINK];
u32 val;
/* Color format */
- val = mipi_csis_read(state, MIPI_CSIS_ISP_CONFIG_CH(0));
+ val = mipi_csis_read(csis, MIPI_CSIS_ISP_CONFIG_CH(0));
val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK
| MIPI_CSIS_ISPCFG_PIXEL_MASK);
@@ -556,28 +578,28 @@ static void __mipi_csis_set_format(struct csi_state *state)
*
* TODO: Verify which other formats require DUAL (or QUAD) modes.
*/
- if (state->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8)
+ if (csis->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8)
val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL;
- val |= MIPI_CSIS_ISPCFG_FMT(state->csis_fmt->data_type);
- mipi_csis_write(state, MIPI_CSIS_ISP_CONFIG_CH(0), val);
+ val |= MIPI_CSIS_ISPCFG_FMT(csis->csis_fmt->data_type);
+ mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val);
/* Pixel resolution */
val = mf->width | (mf->height << 16);
- mipi_csis_write(state, MIPI_CSIS_ISP_RESOL_CH(0), val);
+ mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val);
}
-static int mipi_csis_calculate_params(struct csi_state *state)
+static int mipi_csis_calculate_params(struct mipi_csis_device *csis)
{
s64 link_freq;
u32 lane_rate;
/* Calculate the line rate from the pixel rate. */
- link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler,
- state->csis_fmt->width,
- state->bus.num_data_lanes * 2);
+ link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler,
+ csis->csis_fmt->width,
+ csis->bus.num_data_lanes * 2);
if (link_freq < 0) {
- dev_err(state->dev, "Unable to obtain link frequency: %d\n",
+ dev_err(csis->dev, "Unable to obtain link frequency: %d\n",
(int)link_freq);
return link_freq;
}
@@ -585,7 +607,7 @@ static int mipi_csis_calculate_params(struct csi_state *state)
lane_rate = link_freq * 2;
if (lane_rate < 80000000 || lane_rate > 1500000000) {
- dev_dbg(state->dev, "Out-of-bound lane rate %u\n", lane_rate);
+ dev_dbg(csis->dev, "Out-of-bound lane rate %u\n", lane_rate);
return -EINVAL;
}
@@ -595,57 +617,57 @@ static int mipi_csis_calculate_params(struct csi_state *state)
* (which is documented as corresponding to CSI-2 v0.87 to v1.00) until
* we figure out how to compute it correctly.
*/
- state->hs_settle = (lane_rate - 5000000) / 45000000;
- state->clk_settle = 0;
+ csis->hs_settle = (lane_rate - 5000000) / 45000000;
+ csis->clk_settle = 0;
- dev_dbg(state->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n",
- lane_rate, state->clk_settle, state->hs_settle);
+ dev_dbg(csis->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n",
+ lane_rate, csis->clk_settle, csis->hs_settle);
- if (state->debug.hs_settle < 0xff) {
- dev_dbg(state->dev, "overriding Ths_settle with %u\n",
- state->debug.hs_settle);
- state->hs_settle = state->debug.hs_settle;
+ if (csis->debug.hs_settle < 0xff) {
+ dev_dbg(csis->dev, "overriding Ths_settle with %u\n",
+ csis->debug.hs_settle);
+ csis->hs_settle = csis->debug.hs_settle;
}
- if (state->debug.clk_settle < 4) {
- dev_dbg(state->dev, "overriding Tclk_settle with %u\n",
- state->debug.clk_settle);
- state->clk_settle = state->debug.clk_settle;
+ if (csis->debug.clk_settle < 4) {
+ dev_dbg(csis->dev, "overriding Tclk_settle with %u\n",
+ csis->debug.clk_settle);
+ csis->clk_settle = csis->debug.clk_settle;
}
return 0;
}
-static void mipi_csis_set_params(struct csi_state *state)
+static void mipi_csis_set_params(struct mipi_csis_device *csis)
{
- int lanes = state->bus.num_data_lanes;
+ int lanes = csis->bus.num_data_lanes;
u32 val;
- val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+ val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK;
val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET;
- if (state->info->version == MIPI_CSIS_V3_3)
+ if (csis->info->version == MIPI_CSIS_V3_3)
val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
- mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
+ mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val);
- __mipi_csis_set_format(state);
+ __mipi_csis_set_format(csis);
- mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL,
- MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle) |
- MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(state->clk_settle));
+ mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL,
+ MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) |
+ MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(csis->clk_settle));
val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET)
| (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET)
| (0 << MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET);
- mipi_csis_write(state, MIPI_CSIS_ISP_SYNC_CH(0), val);
+ mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(0), val);
- val = mipi_csis_read(state, MIPI_CSIS_CLK_CTRL);
+ val = mipi_csis_read(csis, MIPI_CSIS_CLK_CTRL);
val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC;
val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15);
val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK;
- mipi_csis_write(state, MIPI_CSIS_CLK_CTRL, val);
+ mipi_csis_write(csis, MIPI_CSIS_CLK_CTRL, val);
- mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_L,
+ mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_L,
MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_715MV |
MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_FREQ_3MHZ |
MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_2V |
@@ -653,95 +675,95 @@ static void mipi_csis_set_params(struct csi_state *state)
MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_715MV |
MIPI_CSIS_DPHY_BCTRL_L_LP_CD_HYS_60MV |
MIPI_CSIS_DPHY_BCTRL_L_B_DPHYCTRL(20000000));
- mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_H, 0);
+ mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_H, 0);
/* Update the shadow register. */
- val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
- mipi_csis_write(state, MIPI_CSIS_CMN_CTRL,
+ val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
+ mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL,
val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW |
MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL);
}
-static int mipi_csis_clk_enable(struct csi_state *state)
+static int mipi_csis_clk_enable(struct mipi_csis_device *csis)
{
- return clk_bulk_prepare_enable(state->info->num_clocks, state->clks);
+ return clk_bulk_prepare_enable(csis->info->num_clocks, csis->clks);
}
-static void mipi_csis_clk_disable(struct csi_state *state)
+static void mipi_csis_clk_disable(struct mipi_csis_device *csis)
{
- clk_bulk_disable_unprepare(state->info->num_clocks, state->clks);
+ clk_bulk_disable_unprepare(csis->info->num_clocks, csis->clks);
}
-static int mipi_csis_clk_get(struct csi_state *state)
+static int mipi_csis_clk_get(struct mipi_csis_device *csis)
{
unsigned int i;
int ret;
- state->clks = devm_kcalloc(state->dev, state->info->num_clocks,
- sizeof(*state->clks), GFP_KERNEL);
+ csis->clks = devm_kcalloc(csis->dev, csis->info->num_clocks,
+ sizeof(*csis->clks), GFP_KERNEL);
- if (!state->clks)
+ if (!csis->clks)
return -ENOMEM;
- for (i = 0; i < state->info->num_clocks; i++)
- state->clks[i].id = mipi_csis_clk_id[i];
+ for (i = 0; i < csis->info->num_clocks; i++)
+ csis->clks[i].id = mipi_csis_clk_id[i];
- ret = devm_clk_bulk_get(state->dev, state->info->num_clocks,
- state->clks);
+ ret = devm_clk_bulk_get(csis->dev, csis->info->num_clocks,
+ csis->clks);
if (ret < 0)
return ret;
/* Set clock rate */
- ret = clk_set_rate(state->clks[MIPI_CSIS_CLK_WRAP].clk,
- state->clk_frequency);
+ ret = clk_set_rate(csis->clks[MIPI_CSIS_CLK_WRAP].clk,
+ csis->clk_frequency);
if (ret < 0)
- dev_err(state->dev, "set rate=%d failed: %d\n",
- state->clk_frequency, ret);
+ dev_err(csis->dev, "set rate=%d failed: %d\n",
+ csis->clk_frequency, ret);
return ret;
}
-static void mipi_csis_start_stream(struct csi_state *state)
+static void mipi_csis_start_stream(struct mipi_csis_device *csis)
{
- mipi_csis_sw_reset(state);
- mipi_csis_set_params(state);
- mipi_csis_system_enable(state, true);
- mipi_csis_enable_interrupts(state, true);
+ mipi_csis_sw_reset(csis);
+ mipi_csis_set_params(csis);
+ mipi_csis_system_enable(csis, true);
+ mipi_csis_enable_interrupts(csis, true);
}
-static void mipi_csis_stop_stream(struct csi_state *state)
+static void mipi_csis_stop_stream(struct mipi_csis_device *csis)
{
- mipi_csis_enable_interrupts(state, false);
- mipi_csis_system_enable(state, false);
+ mipi_csis_enable_interrupts(csis, false);
+ mipi_csis_system_enable(csis, false);
}
static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
{
- struct csi_state *state = dev_id;
+ struct mipi_csis_device *csis = dev_id;
unsigned long flags;
unsigned int i;
u32 status;
u32 dbg_status;
- status = mipi_csis_read(state, MIPI_CSIS_INT_SRC);
- dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC);
+ status = mipi_csis_read(csis, MIPI_CSIS_INT_SRC);
+ dbg_status = mipi_csis_read(csis, MIPI_CSIS_DBG_INTR_SRC);
- spin_lock_irqsave(&state->slock, flags);
+ spin_lock_irqsave(&csis->slock, flags);
/* Update the event/error counters */
- if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug.enable) {
+ if ((status & MIPI_CSIS_INT_SRC_ERRORS) || csis->debug.enable) {
for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
- struct mipi_csis_event *event = &state->events[i];
+ struct mipi_csis_event *event = &csis->events[i];
if ((!event->debug && (status & event->mask)) ||
(event->debug && (dbg_status & event->mask)))
event->counter++;
}
}
- spin_unlock_irqrestore(&state->slock, flags);
+ spin_unlock_irqrestore(&csis->slock, flags);
- mipi_csis_write(state, MIPI_CSIS_INT_SRC, status);
- mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status);
+ mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status);
+ mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_SRC, dbg_status);
return IRQ_HANDLED;
}
@@ -750,47 +772,47 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
* PHY regulator and reset
*/
-static int mipi_csis_phy_enable(struct csi_state *state)
+static int mipi_csis_phy_enable(struct mipi_csis_device *csis)
{
- if (state->info->version != MIPI_CSIS_V3_3)
+ if (csis->info->version != MIPI_CSIS_V3_3)
return 0;
- return regulator_enable(state->mipi_phy_regulator);
+ return regulator_enable(csis->mipi_phy_regulator);
}
-static int mipi_csis_phy_disable(struct csi_state *state)
+static int mipi_csis_phy_disable(struct mipi_csis_device *csis)
{
- if (state->info->version != MIPI_CSIS_V3_3)
+ if (csis->info->version != MIPI_CSIS_V3_3)
return 0;
- return regulator_disable(state->mipi_phy_regulator);
+ return regulator_disable(csis->mipi_phy_regulator);
}
-static void mipi_csis_phy_reset(struct csi_state *state)
+static void mipi_csis_phy_reset(struct mipi_csis_device *csis)
{
- if (state->info->version != MIPI_CSIS_V3_3)
+ if (csis->info->version != MIPI_CSIS_V3_3)
return;
- reset_control_assert(state->mrst);
+ reset_control_assert(csis->mrst);
msleep(20);
- reset_control_deassert(state->mrst);
+ reset_control_deassert(csis->mrst);
}
-static int mipi_csis_phy_init(struct csi_state *state)
+static int mipi_csis_phy_init(struct mipi_csis_device *csis)
{
- if (state->info->version != MIPI_CSIS_V3_3)
+ if (csis->info->version != MIPI_CSIS_V3_3)
return 0;
/* Get MIPI PHY reset and regulator. */
- state->mrst = devm_reset_control_get_exclusive(state->dev, NULL);
- if (IS_ERR(state->mrst))
- return PTR_ERR(state->mrst);
+ csis->mrst = devm_reset_control_get_exclusive(csis->dev, NULL);
+ if (IS_ERR(csis->mrst))
+ return PTR_ERR(csis->mrst);
- state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy");
- if (IS_ERR(state->mipi_phy_regulator))
- return PTR_ERR(state->mipi_phy_regulator);
+ csis->mipi_phy_regulator = devm_regulator_get(csis->dev, "phy");
+ if (IS_ERR(csis->mipi_phy_regulator))
+ return PTR_ERR(csis->mipi_phy_regulator);
- return regulator_set_voltage(state->mipi_phy_regulator, 1000000,
+ return regulator_set_voltage(csis->mipi_phy_regulator, 1000000,
1000000);
}
@@ -798,36 +820,36 @@ static int mipi_csis_phy_init(struct csi_state *state)
* Debug
*/
-static void mipi_csis_clear_counters(struct csi_state *state)
+static void mipi_csis_clear_counters(struct mipi_csis_device *csis)
{
unsigned long flags;
unsigned int i;
- spin_lock_irqsave(&state->slock, flags);
+ spin_lock_irqsave(&csis->slock, flags);
for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++)
- state->events[i].counter = 0;
- spin_unlock_irqrestore(&state->slock, flags);
+ csis->events[i].counter = 0;
+ spin_unlock_irqrestore(&csis->slock, flags);
}
-static void mipi_csis_log_counters(struct csi_state *state, bool non_errors)
+static void mipi_csis_log_counters(struct mipi_csis_device *csis, bool non_errors)
{
unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS
: MIPI_CSIS_NUM_EVENTS - 8;
unsigned long flags;
unsigned int i;
- spin_lock_irqsave(&state->slock, flags);
+ spin_lock_irqsave(&csis->slock, flags);
for (i = 0; i < num_events; ++i) {
- if (state->events[i].counter > 0 || state->debug.enable)
- dev_info(state->dev, "%s events: %d\n",
- state->events[i].name,
- state->events[i].counter);
+ if (csis->events[i].counter > 0 || csis->debug.enable)
+ dev_info(csis->dev, "%s events: %d\n",
+ csis->events[i].name,
+ csis->events[i].counter);
}
- spin_unlock_irqrestore(&state->slock, flags);
+ spin_unlock_irqrestore(&csis->slock, flags);
}
-static int mipi_csis_dump_regs(struct csi_state *state)
+static int mipi_csis_dump_regs(struct mipi_csis_device *csis)
{
static const struct {
u32 offset;
@@ -851,135 +873,134 @@ static int mipi_csis_dump_regs(struct csi_state *state)
unsigned int i;
u32 cfg;
- dev_info(state->dev, "--- REGISTERS ---\n");
+ if (!pm_runtime_get_if_in_use(csis->dev))
+ return 0;
+
+ dev_info(csis->dev, "--- REGISTERS ---\n");
for (i = 0; i < ARRAY_SIZE(registers); i++) {
- cfg = mipi_csis_read(state, registers[i].offset);
- dev_info(state->dev, "%14s: 0x%08x\n", registers[i].name, cfg);
+ cfg = mipi_csis_read(csis, registers[i].offset);
+ dev_info(csis->dev, "%14s: 0x%08x\n", registers[i].name, cfg);
}
+ pm_runtime_put(csis->dev);
+
return 0;
}
static int mipi_csis_dump_regs_show(struct seq_file *m, void *private)
{
- struct csi_state *state = m->private;
+ struct mipi_csis_device *csis = m->private;
- return mipi_csis_dump_regs(state);
+ return mipi_csis_dump_regs(csis);
}
DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs);
-static void mipi_csis_debugfs_init(struct csi_state *state)
+static void mipi_csis_debugfs_init(struct mipi_csis_device *csis)
{
- state->debug.hs_settle = UINT_MAX;
- state->debug.clk_settle = UINT_MAX;
+ csis->debug.hs_settle = UINT_MAX;
+ csis->debug.clk_settle = UINT_MAX;
- state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL);
+ csis->debugfs_root = debugfs_create_dir(dev_name(csis->dev), NULL);
- debugfs_create_bool("debug_enable", 0600, state->debugfs_root,
- &state->debug.enable);
- debugfs_create_file("dump_regs", 0600, state->debugfs_root, state,
+ debugfs_create_bool("debug_enable", 0600, csis->debugfs_root,
+ &csis->debug.enable);
+ debugfs_create_file("dump_regs", 0600, csis->debugfs_root, csis,
&mipi_csis_dump_regs_fops);
- debugfs_create_u32("tclk_settle", 0600, state->debugfs_root,
- &state->debug.clk_settle);
- debugfs_create_u32("ths_settle", 0600, state->debugfs_root,
- &state->debug.hs_settle);
+ debugfs_create_u32("tclk_settle", 0600, csis->debugfs_root,
+ &csis->debug.clk_settle);
+ debugfs_create_u32("ths_settle", 0600, csis->debugfs_root,
+ &csis->debug.hs_settle);
}
-static void mipi_csis_debugfs_exit(struct csi_state *state)
+static void mipi_csis_debugfs_exit(struct mipi_csis_device *csis)
{
- debugfs_remove_recursive(state->debugfs_root);
+ debugfs_remove_recursive(csis->debugfs_root);
}
/* -----------------------------------------------------------------------------
* V4L2 subdev operations
*/
-static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev)
+static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev *sdev)
{
- return container_of(sdev, struct csi_state, sd);
+ return container_of(sdev, struct mipi_csis_device, sd);
}
static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct csi_state *state = mipi_sd_to_csis_state(sd);
+ struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
int ret;
- if (enable) {
- ret = mipi_csis_calculate_params(state);
- if (ret < 0)
- return ret;
+ if (!enable) {
+ mutex_lock(&csis->lock);
- mipi_csis_clear_counters(state);
+ v4l2_subdev_call(csis->src_sd, video, s_stream, 0);
- ret = pm_runtime_resume_and_get(state->dev);
- if (ret < 0)
- return ret;
+ mipi_csis_stop_stream(csis);
+ if (csis->debug.enable)
+ mipi_csis_log_counters(csis, true);
+
+ mutex_unlock(&csis->lock);
- ret = v4l2_subdev_call(state->src_sd, core, s_power, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- goto done;
+ pm_runtime_put(csis->dev);
+
+ return 0;
}
- mutex_lock(&state->lock);
+ ret = mipi_csis_calculate_params(csis);
+ if (ret < 0)
+ return ret;
- if (enable) {
- if (state->state & ST_SUSPENDED) {
- ret = -EBUSY;
- goto unlock;
- }
+ mipi_csis_clear_counters(csis);
- mipi_csis_start_stream(state);
- ret = v4l2_subdev_call(state->src_sd, video, s_stream, 1);
- if (ret < 0)
- goto unlock;
+ ret = pm_runtime_resume_and_get(csis->dev);
+ if (ret < 0)
+ return ret;
- mipi_csis_log_counters(state, true);
+ mutex_lock(&csis->lock);
- state->state |= ST_STREAMING;
- } else {
- v4l2_subdev_call(state->src_sd, video, s_stream, 0);
- ret = v4l2_subdev_call(state->src_sd, core, s_power, 0);
- if (ret == -ENOIOCTLCMD)
- ret = 0;
- mipi_csis_stop_stream(state);
- state->state &= ~ST_STREAMING;
- if (state->debug.enable)
- mipi_csis_log_counters(state, true);
- }
+ mipi_csis_start_stream(csis);
+ ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1);
+ if (ret < 0)
+ goto error;
-unlock:
- mutex_unlock(&state->lock);
+ mipi_csis_log_counters(csis, true);
-done:
- if (!enable || ret < 0)
- pm_runtime_put(state->dev);
+ mutex_unlock(&csis->lock);
+
+ return 0;
+
+error:
+ mipi_csis_stop_stream(csis);
+ mutex_unlock(&csis->lock);
+ pm_runtime_put(csis->dev);
return ret;
}
static struct v4l2_mbus_framefmt *
-mipi_csis_get_format(struct csi_state *state,
+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(&state->sd, sd_state, pad);
+ return v4l2_subdev_get_try_format(&csis->sd, sd_state, pad);
- return &state->format_mbus[pad];
+ return &csis->format_mbus[pad];
}
static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state)
{
- struct csi_state *state = mipi_sd_to_csis_state(sd);
+ 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(state, sd_state, which, CSIS_PAD_SINK);
+ 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;
@@ -993,15 +1014,7 @@ static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace,
fmt_sink->ycbcr_enc);
- /*
- * When called from mipi_csis_subdev_init() to initialize the active
- * configuration, cfg is NULL, which indicates there's no source pad
- * configuration to set.
- */
- if (!sd_state)
- return 0;
-
- fmt_source = mipi_csis_get_format(state, sd_state, which,
+ fmt_source = mipi_csis_get_format(csis, sd_state, which,
CSIS_PAD_SOURCE);
*fmt_source = *fmt_sink;
@@ -1012,15 +1025,15 @@ static int mipi_csis_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
- struct csi_state *state = mipi_sd_to_csis_state(sd);
+ struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
struct v4l2_mbus_framefmt *fmt;
- fmt = mipi_csis_get_format(state, sd_state, sdformat->which,
+ fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
sdformat->pad);
- mutex_lock(&state->lock);
+ mutex_lock(&csis->lock);
sdformat->format = *fmt;
- mutex_unlock(&state->lock);
+ mutex_unlock(&csis->lock);
return 0;
}
@@ -1029,7 +1042,7 @@ 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 csi_state *state = mipi_sd_to_csis_state(sd);
+ struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
/*
* The CSIS can't transcode in any way, the source format is identical
@@ -1041,7 +1054,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- fmt = mipi_csis_get_format(state, sd_state, code->which,
+ fmt = mipi_csis_get_format(csis, sd_state, code->which,
code->pad);
code->code = fmt->code;
return 0;
@@ -1062,7 +1075,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
- struct csi_state *state = mipi_sd_to_csis_state(sd);
+ 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;
@@ -1110,10 +1123,10 @@ 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(state, sd_state, sdformat->which,
+ fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
sdformat->pad);
- mutex_lock(&state->lock);
+ mutex_lock(&csis->lock);
fmt->code = csis_fmt->code;
fmt->width = sdformat->format.width;
@@ -1126,7 +1139,7 @@ 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(state, sd_state, sdformat->which,
+ fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
CSIS_PAD_SOURCE);
*fmt = sdformat->format;
@@ -1135,22 +1148,20 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
/* Store the CSIS format descriptor for active formats. */
if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- state->csis_fmt = csis_fmt;
+ csis->csis_fmt = csis_fmt;
- mutex_unlock(&state->lock);
+ mutex_unlock(&csis->lock);
return 0;
}
static int mipi_csis_log_status(struct v4l2_subdev *sd)
{
- struct csi_state *state = mipi_sd_to_csis_state(sd);
+ struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- mutex_lock(&state->lock);
- mipi_csis_log_counters(state, true);
- if (state->debug.enable && (state->state & ST_POWERED))
- mipi_csis_dump_regs(state);
- mutex_unlock(&state->lock);
+ mipi_csis_log_counters(csis, true);
+ if (csis->debug.enable)
+ mipi_csis_dump_regs(csis);
return 0;
}
@@ -1185,10 +1196,10 @@ static int mipi_csis_link_setup(struct media_entity *entity,
const struct media_pad *remote_pad, u32 flags)
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct csi_state *state = mipi_sd_to_csis_state(sd);
+ struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
struct v4l2_subdev *remote_sd;
- dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name,
+ dev_dbg(csis->dev, "link setup %s -> %s", remote_pad->entity->name,
local_pad->entity->name);
/* We only care about the link to the source. */
@@ -1198,12 +1209,12 @@ static int mipi_csis_link_setup(struct media_entity *entity,
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
if (flags & MEDIA_LNK_FL_ENABLED) {
- if (state->src_sd)
+ if (csis->src_sd)
return -EBUSY;
- state->src_sd = remote_sd;
+ csis->src_sd = remote_sd;
} else {
- state->src_sd = NULL;
+ csis->src_sd = NULL;
}
return 0;
@@ -1219,18 +1230,18 @@ static const struct media_entity_operations mipi_csis_entity_ops = {
* Async subdev notifier
*/
-static struct csi_state *
+static struct mipi_csis_device *
mipi_notifier_to_csis_state(struct v4l2_async_notifier *n)
{
- return container_of(n, struct csi_state, notifier);
+ return container_of(n, struct mipi_csis_device, notifier);
}
static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd)
{
- struct csi_state *state = mipi_notifier_to_csis_state(notifier);
- struct media_pad *sink = &state->sd.entity.pads[CSIS_PAD_SINK];
+ struct mipi_csis_device *csis = mipi_notifier_to_csis_state(notifier);
+ struct media_pad *sink = &csis->sd.entity.pads[CSIS_PAD_SINK];
return v4l2_create_fwnode_links_to_pad(sd, sink, 0);
}
@@ -1239,7 +1250,7 @@ static const struct v4l2_async_notifier_operations mipi_csis_notify_ops = {
.bound = mipi_csis_notify_bound,
};
-static int mipi_csis_async_register(struct csi_state *state)
+static int mipi_csis_async_register(struct mipi_csis_device *csis)
{
struct v4l2_fwnode_endpoint vep = {
.bus_type = V4L2_MBUS_CSI2_DPHY,
@@ -1249,9 +1260,9 @@ static int mipi_csis_async_register(struct csi_state *state)
unsigned int i;
int ret;
- v4l2_async_nf_init(&state->notifier);
+ v4l2_async_nf_init(&csis->notifier);
- ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0,
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0,
FWNODE_GRAPH_ENDPOINT_NEXT);
if (!ep)
return -ENOTCONN;
@@ -1262,19 +1273,19 @@ static int mipi_csis_async_register(struct csi_state *state)
for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) {
if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) {
- dev_err(state->dev,
+ dev_err(csis->dev,
"data lanes reordering is not supported");
ret = -EINVAL;
goto err_parse;
}
}
- state->bus = vep.bus.mipi_csi2;
+ csis->bus = vep.bus.mipi_csi2;
- dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes);
- dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags);
+ dev_dbg(csis->dev, "data lanes: %d\n", csis->bus.num_data_lanes);
+ dev_dbg(csis->dev, "flags: 0x%08x\n", csis->bus.flags);
- asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep,
+ asd = v4l2_async_nf_add_fwnode_remote(&csis->notifier, ep,
struct v4l2_async_subdev);
if (IS_ERR(asd)) {
ret = PTR_ERR(asd);
@@ -1283,13 +1294,13 @@ static int mipi_csis_async_register(struct csi_state *state)
fwnode_handle_put(ep);
- state->notifier.ops = &mipi_csis_notify_ops;
+ csis->notifier.ops = &mipi_csis_notify_ops;
- ret = v4l2_async_subdev_nf_register(&state->sd, &state->notifier);
+ ret = v4l2_async_subdev_nf_register(&csis->sd, &csis->notifier);
if (ret)
return ret;
- return v4l2_async_register_subdev(&state->sd);
+ return v4l2_async_register_subdev(&csis->sd);
err_parse:
fwnode_handle_put(ep);
@@ -1301,97 +1312,63 @@ err_parse:
* Suspend/resume
*/
-static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
+static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct csi_state *state = mipi_sd_to_csis_state(sd);
+ struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
int ret = 0;
- mutex_lock(&state->lock);
- if (state->state & ST_POWERED) {
- mipi_csis_stop_stream(state);
- ret = mipi_csis_phy_disable(state);
- if (ret)
- goto unlock;
- mipi_csis_clk_disable(state);
- state->state &= ~ST_POWERED;
- if (!runtime)
- state->state |= ST_SUSPENDED;
- }
+ mutex_lock(&csis->lock);
+
+ ret = mipi_csis_phy_disable(csis);
+ if (ret)
+ goto unlock;
+
+ mipi_csis_clk_disable(csis);
unlock:
- mutex_unlock(&state->lock);
+ mutex_unlock(&csis->lock);
return ret ? -EAGAIN : 0;
}
-static int mipi_csis_pm_resume(struct device *dev, bool runtime)
+static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct csi_state *state = mipi_sd_to_csis_state(sd);
+ struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
int ret = 0;
- mutex_lock(&state->lock);
- if (!runtime && !(state->state & ST_SUSPENDED))
- goto unlock;
-
- if (!(state->state & ST_POWERED)) {
- ret = mipi_csis_phy_enable(state);
- if (ret)
- goto unlock;
+ mutex_lock(&csis->lock);
- state->state |= ST_POWERED;
- mipi_csis_clk_enable(state);
- }
- if (state->state & ST_STREAMING)
- mipi_csis_start_stream(state);
+ ret = mipi_csis_phy_enable(csis);
+ if (ret)
+ goto unlock;
- state->state &= ~ST_SUSPENDED;
+ mipi_csis_clk_enable(csis);
unlock:
- mutex_unlock(&state->lock);
+ mutex_unlock(&csis->lock);
return ret ? -EAGAIN : 0;
}
-static int __maybe_unused mipi_csis_suspend(struct device *dev)
-{
- return mipi_csis_pm_suspend(dev, false);
-}
-
-static int __maybe_unused mipi_csis_resume(struct device *dev)
-{
- return mipi_csis_pm_resume(dev, false);
-}
-
-static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
-{
- return mipi_csis_pm_suspend(dev, true);
-}
-
-static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
-{
- return mipi_csis_pm_resume(dev, true);
-}
-
static const struct dev_pm_ops mipi_csis_pm_ops = {
SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
NULL)
- SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
};
/* -----------------------------------------------------------------------------
* Probe/remove & platform driver
*/
-static int mipi_csis_subdev_init(struct csi_state *state)
+static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
{
- struct v4l2_subdev *sd = &state->sd;
+ struct v4l2_subdev *sd = &csis->sd;
v4l2_subdev_init(sd, &mipi_csis_subdev_ops);
sd->owner = THIS_MODULE;
snprintf(sd->name, sizeof(sd->name), "csis-%s",
- dev_name(state->dev));
+ dev_name(csis->dev));
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->ctrl_handler = NULL;
@@ -1399,26 +1376,26 @@ static int mipi_csis_subdev_init(struct csi_state *state)
sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
sd->entity.ops = &mipi_csis_entity_ops;
- sd->dev = state->dev;
+ sd->dev = csis->dev;
- state->csis_fmt = &mipi_csis_formats[0];
+ csis->csis_fmt = &mipi_csis_formats[0];
mipi_csis_init_cfg(sd, NULL);
- state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+ csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT;
- state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
+ 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,
- state->pads);
+ csis->pads);
}
-static int mipi_csis_parse_dt(struct csi_state *state)
+static int mipi_csis_parse_dt(struct mipi_csis_device *csis)
{
- struct device_node *node = state->dev->of_node;
+ struct device_node *node = csis->dev->of_node;
if (of_property_read_u32(node, "clock-frequency",
- &state->clk_frequency))
- state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+ &csis->clk_frequency))
+ csis->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
return 0;
}
@@ -1426,102 +1403,102 @@ static int mipi_csis_parse_dt(struct csi_state *state)
static int mipi_csis_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct csi_state *state;
+ struct mipi_csis_device *csis;
int irq;
int ret;
- state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
- if (!state)
+ csis = devm_kzalloc(dev, sizeof(*csis), GFP_KERNEL);
+ if (!csis)
return -ENOMEM;
- mutex_init(&state->lock);
- spin_lock_init(&state->slock);
+ mutex_init(&csis->lock);
+ spin_lock_init(&csis->slock);
- state->dev = dev;
- state->info = of_device_get_match_data(dev);
+ csis->dev = dev;
+ csis->info = of_device_get_match_data(dev);
- memcpy(state->events, mipi_csis_events, sizeof(state->events));
+ memcpy(csis->events, mipi_csis_events, sizeof(csis->events));
/* Parse DT properties. */
- ret = mipi_csis_parse_dt(state);
+ ret = mipi_csis_parse_dt(csis);
if (ret < 0) {
dev_err(dev, "Failed to parse device tree: %d\n", ret);
return ret;
}
/* Acquire resources. */
- state->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(state->regs))
- return PTR_ERR(state->regs);
+ csis->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(csis->regs))
+ return PTR_ERR(csis->regs);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- ret = mipi_csis_phy_init(state);
+ ret = mipi_csis_phy_init(csis);
if (ret < 0)
return ret;
- ret = mipi_csis_clk_get(state);
+ ret = mipi_csis_clk_get(csis);
if (ret < 0)
return ret;
/* Reset PHY and enable the clocks. */
- mipi_csis_phy_reset(state);
+ mipi_csis_phy_reset(csis);
- ret = mipi_csis_clk_enable(state);
+ ret = mipi_csis_clk_enable(csis);
if (ret < 0) {
- dev_err(state->dev, "failed to enable clocks: %d\n", ret);
+ dev_err(csis->dev, "failed to enable clocks: %d\n", ret);
return ret;
}
/* Now that the hardware is initialized, request the interrupt. */
ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
- dev_name(dev), state);
+ dev_name(dev), csis);
if (ret) {
dev_err(dev, "Interrupt request failed\n");
goto disable_clock;
}
/* Initialize and register the subdev. */
- ret = mipi_csis_subdev_init(state);
+ ret = mipi_csis_subdev_init(csis);
if (ret < 0)
goto disable_clock;
- platform_set_drvdata(pdev, &state->sd);
+ platform_set_drvdata(pdev, &csis->sd);
- ret = mipi_csis_async_register(state);
+ ret = mipi_csis_async_register(csis);
if (ret < 0) {
dev_err(dev, "async register failed: %d\n", ret);
goto cleanup;
}
/* Initialize debugfs. */
- mipi_csis_debugfs_init(state);
+ mipi_csis_debugfs_init(csis);
/* Enable runtime PM. */
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev)) {
- ret = mipi_csis_pm_resume(dev, true);
+ ret = mipi_csis_runtime_resume(dev);
if (ret < 0)
goto unregister_all;
}
dev_info(dev, "lanes: %d, freq: %u\n",
- state->bus.num_data_lanes, state->clk_frequency);
+ csis->bus.num_data_lanes, csis->clk_frequency);
return 0;
unregister_all:
- mipi_csis_debugfs_exit(state);
+ mipi_csis_debugfs_exit(csis);
cleanup:
- media_entity_cleanup(&state->sd.entity);
- v4l2_async_nf_unregister(&state->notifier);
- v4l2_async_nf_cleanup(&state->notifier);
- v4l2_async_unregister_subdev(&state->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:
- mipi_csis_clk_disable(state);
- mutex_destroy(&state->lock);
+ mipi_csis_clk_disable(csis);
+ mutex_destroy(&csis->lock);
return ret;
}
@@ -1529,18 +1506,18 @@ disable_clock:
static int mipi_csis_remove(struct platform_device *pdev)
{
struct v4l2_subdev *sd = platform_get_drvdata(pdev);
- struct csi_state *state = mipi_sd_to_csis_state(sd);
+ struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- mipi_csis_debugfs_exit(state);
- v4l2_async_nf_unregister(&state->notifier);
- v4l2_async_nf_cleanup(&state->notifier);
- v4l2_async_unregister_subdev(&state->sd);
+ mipi_csis_debugfs_exit(csis);
+ v4l2_async_nf_unregister(&csis->notifier);
+ v4l2_async_nf_cleanup(&csis->notifier);
+ v4l2_async_unregister_subdev(&csis->sd);
pm_runtime_disable(&pdev->dev);
- mipi_csis_pm_suspend(&pdev->dev, true);
- mipi_csis_clk_disable(state);
- media_entity_cleanup(&state->sd.entity);
- mutex_destroy(&state->lock);
+ mipi_csis_runtime_suspend(&pdev->dev);
+ mipi_csis_clk_disable(csis);
+ media_entity_cleanup(&csis->sd.entity);
+ mutex_destroy(&csis->lock);
pm_runtime_set_suspended(&pdev->dev);
return 0;