summaryrefslogtreecommitdiff
path: root/drivers/media/platform/imx8/mxc-isi-cap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/imx8/mxc-isi-cap.c')
-rw-r--r--drivers/media/platform/imx8/mxc-isi-cap.c380
1 files changed, 371 insertions, 9 deletions
diff --git a/drivers/media/platform/imx8/mxc-isi-cap.c b/drivers/media/platform/imx8/mxc-isi-cap.c
index f5bde4e88605..23314d48d0cd 100644
--- a/drivers/media/platform/imx8/mxc-isi-cap.c
+++ b/drivers/media/platform/imx8/mxc-isi-cap.c
@@ -161,15 +161,50 @@ struct mxc_isi_fmt *mxc_isi_get_src_fmt(struct v4l2_subdev_format *sd_fmt)
{
u32 index;
- /* two fmt RGB32 and YUV444 from pixellink */
- if (sd_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16 ||
- sd_fmt->format.code == MEDIA_BUS_FMT_YVYU8_2X8 ||
- sd_fmt->format.code == MEDIA_BUS_FMT_AYUV8_1X32 ||
- sd_fmt->format.code == MEDIA_BUS_FMT_UYVY8_2X8 ||
- sd_fmt->format.code == MEDIA_BUS_FMT_YUYV8_2X8)
+ /* Treat all yuv fomats equally */
+ switch (sd_fmt->format.code) {
+ case MEDIA_BUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_UV8_1X8:
+ case MEDIA_BUS_FMT_UYVY8_1_5X8:
+ case MEDIA_BUS_FMT_VYUY8_1_5X8:
+ case MEDIA_BUS_FMT_YUYV8_1_5X8:
+ case MEDIA_BUS_FMT_YVYU8_1_5X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_Y10_1X10:
+ case MEDIA_BUS_FMT_UYVY10_2X10:
+ case MEDIA_BUS_FMT_VYUY10_2X10:
+ case MEDIA_BUS_FMT_YUYV10_2X10:
+ case MEDIA_BUS_FMT_YVYU10_2X10:
+ case MEDIA_BUS_FMT_Y12_1X12:
+ case MEDIA_BUS_FMT_UYVY12_2X12:
+ case MEDIA_BUS_FMT_VYUY12_2X12:
+ case MEDIA_BUS_FMT_YUYV12_2X12:
+ case MEDIA_BUS_FMT_YVYU12_2X12:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_VYUY8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YVYU8_1X16:
+ case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ case MEDIA_BUS_FMT_VYUY10_1X20:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YVYU10_1X20:
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_UYVY12_1X24:
+ case MEDIA_BUS_FMT_VYUY12_1X24:
+ case MEDIA_BUS_FMT_YUYV12_1X24:
+ case MEDIA_BUS_FMT_YVYU12_1X24:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ case MEDIA_BUS_FMT_AYUV8_1X32:
index = 1;
- else
+ break;
+ default:
index = 0;
+ }
return &mxc_isi_src_formats[index];
}
@@ -538,6 +573,8 @@ static struct vb2_ops mxc_cap_vb2_qops = {
.stop_streaming = cap_vb2_stop_streaming,
};
+/* To enable ctrls in sensor driver, we need to comment the ISI ctrls */
+#ifndef CONFIG_VIDEO_ECAM
/*
* V4L2 controls handling
*/
@@ -624,6 +661,7 @@ void mxc_isi_ctrls_delete(struct mxc_isi_dev *mxc_isi)
ctrls->alpha = NULL;
}
}
+#endif
static struct media_pad *mxc_isi_get_remote_source_pad(struct mxc_isi_dev *mxc_isi)
{
@@ -860,6 +898,65 @@ static int mxc_isi_cap_try_fmt_mplane(struct file *file, void *fh,
return 0;
}
+static struct media_pad *subdev_get_remote_source_pad(struct v4l2_subdev *subdev)
+{
+ struct media_pad *sink_pad, *source_pad;
+ int i;
+
+ while (1) {
+ source_pad = NULL;
+ for (i = 0; i < subdev->entity.num_pads; i++) {
+ sink_pad = &subdev->entity.pads[i];
+
+ if (sink_pad->flags & MEDIA_PAD_FL_SINK) {
+ source_pad = media_entity_remote_pad(sink_pad);
+ if (source_pad)
+ break;
+ }
+ }
+ /* return first pad point in the loop */
+ return source_pad;
+ }
+
+ return NULL;
+}
+
+static struct v4l2_subdev *mxc_isi_get_sensor_subdev(struct v4l2_subdev *subdev)
+{
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sd;
+
+ /* Firstly find mipi interface, so remote source for the isi */
+ source_pad = subdev_get_remote_source_pad(subdev);
+ if (source_pad == NULL) {
+ v4l2_err(subdev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return NULL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(subdev->v4l2_dev, "Can't find subdev\n");
+ return NULL;
+ }
+
+ /* Then find the actual sensor which should be on the pad of mipi */
+ source_pad = subdev_get_remote_source_pad(sd);
+ if (source_pad == NULL) {
+ v4l2_err(subdev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return NULL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(subdev->v4l2_dev, "Can't find subdev\n");
+ return NULL;
+ }
+
+ return sd;
+}
+
/* Update input frame size and formate */
static int mxc_isi_source_fmt_init(struct mxc_isi_dev *mxc_isi)
{
@@ -871,7 +968,12 @@ static int mxc_isi_source_fmt_init(struct mxc_isi_dev *mxc_isi)
int ret;
/* Get remote source pad */
+#ifndef CONFIG_VIDEO_ECAM
+ source_pad = subdev_get_remote_source_pad(&mxc_isi->isi_cap.sd);
+#else
+ /* To enable ctrls in sensor driver */
source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+#endif
if (source_pad == NULL) {
v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
return -EINVAL;
@@ -884,6 +986,20 @@ static int mxc_isi_source_fmt_init(struct mxc_isi_dev *mxc_isi)
return -EINVAL;
}
+# if 0
+ struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
+ struct v4l2_subdev_format dst_fmt;
+ struct v4l2_subdev *sd;
+
+ dst_fmt.pad = source_pad->index;
+ dst_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ dst_fmt.format.width = dst_f->o_width;
+ dst_fmt.format.height = dst_f->o_height;
+
+ sd = mxc_isi_get_sensor_subdev(&mxc_isi->isi_cap.sd);
+ v4l2_subdev_call(sd, pad, set_fmt, NULL, &dst_fmt);
+# endif
+
src_fmt.pad = source_pad->index;
src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
src_fmt.format.width = dst_f->width;
@@ -1143,6 +1259,7 @@ static int mxc_isi_cap_g_chip_ident(struct file *file, void *fb,
struct device_node *local, *remote, *endpoint;
struct mxc_isi_dev *mxc_isi = video_drvdata(file);
struct video_device *vdev = video_devdata(file);
+ struct v4l2_dbg_chip_ident ci;
struct v4l2_subdev *sd;
struct media_pad *source_pad;
@@ -1153,7 +1270,12 @@ static int mxc_isi_cap_g_chip_ident(struct file *file, void *fb,
}
/* Get remote source pad subdev */
+#ifndef CONFIG_VIDEO_ECAM
+ sd = mxc_isi_get_sensor_subdev(&mxc_isi->isi_cap.sd);
+#else
+ /* To enable ctrls in sensor driver */
sd = media_entity_to_v4l2_subdev(source_pad->entity);
+#endif
if (sd == NULL) {
v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
return -EINVAL;
@@ -1179,9 +1301,19 @@ static int mxc_isi_cap_g_chip_ident(struct file *file, void *fb,
return -ENODEV;
}
- sprintf(chip->match.name, "imx8_%s_%d", remote->name, vdev->num);
+#ifndef CONFIG_VIDEO_ECAM
+ sprintf(chip->match.name, "%s-%d\n", sd->name, vdev->num);
+ /* Just check if the callback of the sensor device returns success,
+ * no need to actually identify the device since we're using the
+ * pads to find it.
+ */
+
+ return v4l2_subdev_call(sd, core, g_chip_ident, &ci);
+#else
+ sprintf(chip->match.name, "imx8_%s_%d", remote->name, vdev->num);
return 0;
+#endif
}
static int mxc_isi_cap_g_parm(struct file *file, void *fh,
@@ -1198,7 +1330,12 @@ static int mxc_isi_cap_g_parm(struct file *file, void *fh,
}
/* Get remote source pad subdev */
+#ifndef CONFIG_VIDEO_ECAM
+ sd = mxc_isi_get_sensor_subdev(&mxc_isi->isi_cap.sd);
+#else
+ /* To enable ctrls in sensor driver */
sd = media_entity_to_v4l2_subdev(source_pad->entity);
+#endif
if (sd == NULL) {
v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
return -EINVAL;
@@ -1220,7 +1357,12 @@ static int mxc_isi_cap_s_parm(struct file *file, void *fh,
}
/* Get remote source pad subdev */
+#ifndef CONFIG_VIDEO_ECAM
+ sd = mxc_isi_get_sensor_subdev(&mxc_isi->isi_cap.sd);
+#else
+ /* To enable ctrls in sensor driver */
sd = media_entity_to_v4l2_subdev(source_pad->entity);
+#endif
if (sd == NULL) {
v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
return -EINVAL;
@@ -1254,7 +1396,12 @@ static int mxc_isi_cap_enum_framesizes(struct file *file, void *priv,
}
/* Get remote source pad subdev */
+#ifndef CONFIG_VIDEO_ECAM
+ sd = mxc_isi_get_sensor_subdev(&mxc_isi->isi_cap.sd);
+#else
+ /* To enable ctrls in sensor driver */
sd = media_entity_to_v4l2_subdev(source_pad->entity);
+#endif
if (sd == NULL) {
v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
return -EINVAL;
@@ -1321,11 +1468,20 @@ static int mxc_isi_cap_enum_frameintervals(struct file *file, void *fh,
}
/* Get remote source pad subdev */
+#ifndef CONFIG_VIDEO_ECAM
+ sd = mxc_isi_get_sensor_subdev(&mxc_isi->isi_cap.sd);
+ if (sd == NULL) {
+ v4l2_err(&mxc_isi->isi_cap.sd, "Can't find sensor subdev\n");
+ return -ENODEV;
+ }
+#else
+ /* To enable ctrls in sensor driver */
sd = media_entity_to_v4l2_subdev(source_pad->entity);
if (sd == NULL) {
v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
return -EINVAL;
}
+#endif
ret = v4l2_subdev_call(sd, pad, enum_frame_interval, NULL, &fie);
if (ret)
@@ -1340,6 +1496,193 @@ static int mxc_isi_cap_enum_frameintervals(struct file *file, void *fh,
return 0;
}
+#ifdef CONFIG_VIDEO_ECAM
+static int mxc_vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *a)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sd, core, queryctrl, a);
+}
+
+static int mxc_vidioc_query_ext_ctrl(struct file *file, void *fh,
+ struct v4l2_query_ext_ctrl *qec)
+{
+ struct v4l2_queryctrl qc = {
+ .id = qec->id
+ };
+ int ret;
+
+ ret = mxc_vidioc_queryctrl(file, fh, &qc);
+
+ if (ret)
+ return ret;
+
+ qec->id = qc.id;
+ qec->type = qc.type;
+ strlcpy(qec->name, qc.name, sizeof(qec->name));
+ qec->maximum = qc.maximum;
+ qec->minimum = qc.minimum;
+ qec->step = qc.step;
+ qec->default_value = qc.default_value;
+ qec->flags = qc.flags;
+ qec->elem_size = 4;
+ qec->elems = 1;
+ qec->nr_of_dims = 0;
+ memset(qec->dims, 0, sizeof(qec->dims));
+ memset(qec->reserved, 0, sizeof(qec->reserved));
+
+ return 0;
+}
+
+
+static int mxc_isi_vidioc_querymenu(struct file *file, void *fh,
+ struct v4l2_querymenu *qm)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+ return v4l2_subdev_call(sd, core, querymenu, qm);
+}
+
+static int mxc_isi_vidioc_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+ return v4l2_subdev_call(sd, core, g_ctrl, a);
+}
+
+static int mxc_isi_vidioc_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+ return v4l2_subdev_call(sd, core, s_ctrl, a);
+}
+
+static int mxc_isi_vidioc_g_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *a)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sd, core, g_ext_ctrls, a);
+}
+
+static int mxc_isi_vidioc_try_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *a)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sd, core, try_ext_ctrls, a);
+
+}
+
+static int mxc_isi_vidioc_s_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *a)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sd, core, s_ext_ctrls, a);
+
+}
+#endif
+
static const struct v4l2_ioctl_ops mxc_isi_capture_ioctl_ops = {
.vidioc_querycap = mxc_isi_cap_querycap,
@@ -1368,6 +1711,16 @@ static const struct v4l2_ioctl_ops mxc_isi_capture_ioctl_ops = {
.vidioc_enum_framesizes = mxc_isi_cap_enum_framesizes,
.vidioc_enum_frameintervals = mxc_isi_cap_enum_frameintervals,
+#ifdef CONFIG_VIDEO_ECAM
+ .vidioc_queryctrl = mxc_vidioc_queryctrl,
+ .vidioc_query_ext_ctrl = mxc_vidioc_query_ext_ctrl,
+ .vidioc_querymenu = mxc_isi_vidioc_querymenu,
+ .vidioc_g_ctrl = mxc_isi_vidioc_g_ctrl,
+ .vidioc_s_ctrl = mxc_isi_vidioc_s_ctrl,
+ .vidioc_g_ext_ctrls = mxc_isi_vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = mxc_isi_vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = mxc_isi_vidioc_try_ext_ctrls
+#endif
};
/* Capture subdev media entity operations */
@@ -1678,22 +2031,28 @@ static int mxc_isi_register_cap_device(struct mxc_isi_dev *mxc_isi,
if (ret)
goto err_free_ctx;
+/* To enable ctrls in sensor driver, we need to comment the ISI ctrls */
+#ifndef CONFIG_VIDEO_ECAM
ret = mxc_isi_ctrls_create(mxc_isi);
if (ret)
goto err_me_cleanup;
+#endif
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
if (ret)
goto err_ctrl_free;
-
+#ifndef CONFIG_VIDEO_ECAM
vdev->ctrl_handler = &mxc_isi->ctrls.handler;
+#endif
v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
vdev->name, video_device_node_name(vdev));
return 0;
err_ctrl_free:
+#ifndef CONFIG_VIDEO_ECAM
mxc_isi_ctrls_delete(mxc_isi);
+#endif
err_me_cleanup:
media_entity_cleanup(&vdev->entity);
err_free_ctx:
@@ -1755,7 +2114,10 @@ static void mxc_isi_subdev_unregistered(struct v4l2_subdev *sd)
vdev = &mxc_isi->isi_cap.vdev;
if (video_is_registered(vdev)) {
video_unregister_device(vdev);
+/* To enable ctrls in sensor driver, we need to comment the ISI ctrls*/
+#ifndef CONFIG_VIDEO_ECAM
mxc_isi_ctrls_delete(mxc_isi);
+#endif
media_entity_cleanup(&vdev->entity);
}