diff options
Diffstat (limited to 'drivers/media/platform/imx8/mxc-isi-cap.c')
-rw-r--r-- | drivers/media/platform/imx8/mxc-isi-cap.c | 380 |
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); } |