1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver for Renesas R-Car VIN
5 * Copyright (C) 2016 Renesas Electronics Corp.
6 * Copyright (C) 2011-2013 Renesas Solutions Corp.
7 * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
8 * Copyright (C) 2008 Magnus Damm
10 * Based on the soc-camera rcar_vin driver
13 #include <linux/pm_runtime.h>
15 #include <media/v4l2-event.h>
16 #include <media/v4l2-ioctl.h>
17 #include <media/v4l2-mc.h>
18 #include <media/v4l2-rect.h>
22 #define RVIN_DEFAULT_FORMAT V4L2_PIX_FMT_YUYV
23 #define RVIN_DEFAULT_WIDTH 800
24 #define RVIN_DEFAULT_HEIGHT 600
25 #define RVIN_DEFAULT_FIELD V4L2_FIELD_NONE
26 #define RVIN_DEFAULT_COLORSPACE V4L2_COLORSPACE_SRGB
28 /* -----------------------------------------------------------------------------
32 static const struct rvin_video_format rvin_formats[] = {
34 .fourcc = V4L2_PIX_FMT_NV16,
38 .fourcc = V4L2_PIX_FMT_YUYV,
42 .fourcc = V4L2_PIX_FMT_UYVY,
46 .fourcc = V4L2_PIX_FMT_RGB565,
50 .fourcc = V4L2_PIX_FMT_XRGB555,
54 .fourcc = V4L2_PIX_FMT_XBGR32,
58 .fourcc = V4L2_PIX_FMT_ARGB555,
62 .fourcc = V4L2_PIX_FMT_ABGR32,
67 const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
72 if (vin->info->model == RCAR_M1 && pixelformat == V4L2_PIX_FMT_XBGR32)
75 for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
76 if (rvin_formats[i].fourcc == pixelformat)
77 return rvin_formats + i;
82 static u32 rvin_format_bytesperline(struct rvin_dev *vin,
83 struct v4l2_pix_format *pix)
85 const struct rvin_video_format *fmt;
87 fmt = rvin_format_from_pixel(vin, pix->pixelformat);
92 return pix->width * fmt->bpp;
95 static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix)
97 if (pix->pixelformat == V4L2_PIX_FMT_NV16)
98 return pix->bytesperline * pix->height * 2;
100 return pix->bytesperline * pix->height;
103 static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
107 if (!rvin_format_from_pixel(vin, pix->pixelformat))
108 pix->pixelformat = RVIN_DEFAULT_FORMAT;
110 switch (pix->field) {
112 case V4L2_FIELD_BOTTOM:
113 case V4L2_FIELD_NONE:
114 case V4L2_FIELD_INTERLACED_TB:
115 case V4L2_FIELD_INTERLACED_BT:
116 case V4L2_FIELD_INTERLACED:
118 case V4L2_FIELD_ALTERNATE:
120 * Driver does not (yet) support outputting ALTERNATE to a
121 * userspace. It does support outputting INTERLACED so use
122 * the VIN hardware to combine the two fields.
124 pix->field = V4L2_FIELD_INTERLACED;
128 pix->field = RVIN_DEFAULT_FIELD;
132 /* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */
133 walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1;
135 /* Limit to VIN capabilities */
136 v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign,
137 &pix->height, 4, vin->info->max_height, 2, 0);
139 pix->bytesperline = rvin_format_bytesperline(vin, pix);
140 pix->sizeimage = rvin_format_sizeimage(pix);
142 vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n",
143 pix->width, pix->height, pix->bytesperline, pix->sizeimage);
146 /* -----------------------------------------------------------------------------
150 static int rvin_reset_format(struct rvin_dev *vin)
152 struct v4l2_subdev_format fmt = {
153 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
154 .pad = vin->parallel->source_pad,
158 ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
162 v4l2_fill_pix_format(&vin->format, &fmt.format);
164 rvin_format_align(vin, &vin->format);
167 vin->source.left = 0;
168 vin->source.width = vin->format.width;
169 vin->source.height = vin->format.height;
171 vin->crop = vin->source;
172 vin->compose = vin->source;
177 static int rvin_try_format(struct rvin_dev *vin, u32 which,
178 struct v4l2_pix_format *pix,
179 struct v4l2_rect *crop, struct v4l2_rect *compose)
181 struct v4l2_subdev *sd = vin_to_source(vin);
182 struct v4l2_subdev_pad_config *pad_cfg;
183 struct v4l2_subdev_format format = {
185 .pad = vin->parallel->source_pad,
187 enum v4l2_field field;
191 pad_cfg = v4l2_subdev_alloc_pad_config(sd);
195 if (!rvin_format_from_pixel(vin, pix->pixelformat))
196 pix->pixelformat = RVIN_DEFAULT_FORMAT;
198 v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code);
200 /* Allow the video device to override field and to scale */
203 height = pix->height;
205 ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
206 if (ret < 0 && ret != -ENOIOCTLCMD)
209 v4l2_fill_pix_format(pix, &format.format);
214 crop->width = pix->width;
215 crop->height = pix->height;
218 * If source is ALTERNATE the driver will use the VIN hardware
219 * to INTERLACE it. The crop height then needs to be doubled.
221 if (pix->field == V4L2_FIELD_ALTERNATE)
225 if (field != V4L2_FIELD_ANY)
229 pix->height = height;
231 rvin_format_align(vin, pix);
236 compose->width = pix->width;
237 compose->height = pix->height;
240 v4l2_subdev_free_pad_config(pad_cfg);
245 static int rvin_querycap(struct file *file, void *priv,
246 struct v4l2_capability *cap)
248 struct rvin_dev *vin = video_drvdata(file);
250 strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
251 strscpy(cap->card, "R_Car_VIN", sizeof(cap->card));
252 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
257 static int rvin_try_fmt_vid_cap(struct file *file, void *priv,
258 struct v4l2_format *f)
260 struct rvin_dev *vin = video_drvdata(file);
262 return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL,
266 static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
267 struct v4l2_format *f)
269 struct rvin_dev *vin = video_drvdata(file);
270 struct v4l2_rect crop, compose;
273 if (vb2_is_busy(&vin->queue))
276 ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
281 vin->format = f->fmt.pix;
283 vin->compose = compose;
289 static int rvin_g_fmt_vid_cap(struct file *file, void *priv,
290 struct v4l2_format *f)
292 struct rvin_dev *vin = video_drvdata(file);
294 f->fmt.pix = vin->format;
299 static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
300 struct v4l2_fmtdesc *f)
302 if (f->index >= ARRAY_SIZE(rvin_formats))
305 f->pixelformat = rvin_formats[f->index].fourcc;
310 static int rvin_g_selection(struct file *file, void *fh,
311 struct v4l2_selection *s)
313 struct rvin_dev *vin = video_drvdata(file);
315 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
319 case V4L2_SEL_TGT_CROP_BOUNDS:
320 case V4L2_SEL_TGT_CROP_DEFAULT:
321 s->r.left = s->r.top = 0;
322 s->r.width = vin->source.width;
323 s->r.height = vin->source.height;
325 case V4L2_SEL_TGT_CROP:
328 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
329 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
330 s->r.left = s->r.top = 0;
331 s->r.width = vin->format.width;
332 s->r.height = vin->format.height;
334 case V4L2_SEL_TGT_COMPOSE:
344 static int rvin_s_selection(struct file *file, void *fh,
345 struct v4l2_selection *s)
347 struct rvin_dev *vin = video_drvdata(file);
348 const struct rvin_video_format *fmt;
349 struct v4l2_rect r = s->r;
350 struct v4l2_rect max_rect;
351 struct v4l2_rect min_rect = {
356 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
359 v4l2_rect_set_min_size(&r, &min_rect);
362 case V4L2_SEL_TGT_CROP:
363 /* Can't crop outside of source input */
364 max_rect.top = max_rect.left = 0;
365 max_rect.width = vin->source.width;
366 max_rect.height = vin->source.height;
367 v4l2_rect_map_inside(&r, &max_rect);
369 v4l_bound_align_image(&r.width, 6, vin->source.width, 0,
370 &r.height, 2, vin->source.height, 0, 0);
372 r.top = clamp_t(s32, r.top, 0, vin->source.height - r.height);
373 r.left = clamp_t(s32, r.left, 0, vin->source.width - r.width);
375 vin->crop = s->r = r;
377 vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
378 r.width, r.height, r.left, r.top,
379 vin->source.width, vin->source.height);
381 case V4L2_SEL_TGT_COMPOSE:
382 /* Make sure compose rect fits inside output format */
383 max_rect.top = max_rect.left = 0;
384 max_rect.width = vin->format.width;
385 max_rect.height = vin->format.height;
386 v4l2_rect_map_inside(&r, &max_rect);
389 * Composing is done by adding a offset to the buffer address,
390 * the HW wants this address to be aligned to HW_BUFFER_MASK.
391 * Make sure the top and left values meets this requirement.
393 while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
396 fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
397 while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
400 vin->compose = s->r = r;
402 vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n",
403 r.width, r.height, r.left, r.top,
404 vin->format.width, vin->format.height);
410 /* HW supports modifying configuration while running */
411 rvin_crop_scale_comp(vin);
416 static int rvin_g_pixelaspect(struct file *file, void *priv,
417 int type, struct v4l2_fract *f)
419 struct rvin_dev *vin = video_drvdata(file);
420 struct v4l2_subdev *sd = vin_to_source(vin);
422 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
425 return v4l2_subdev_call(sd, video, g_pixelaspect, f);
428 static int rvin_enum_input(struct file *file, void *priv,
429 struct v4l2_input *i)
431 struct rvin_dev *vin = video_drvdata(file);
432 struct v4l2_subdev *sd = vin_to_source(vin);
438 ret = v4l2_subdev_call(sd, video, g_input_status, &i->status);
439 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
442 i->type = V4L2_INPUT_TYPE_CAMERA;
444 if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) {
445 i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
448 i->capabilities = V4L2_IN_CAP_STD;
449 i->std = vin->vdev.tvnorms;
452 strscpy(i->name, "Camera", sizeof(i->name));
457 static int rvin_g_input(struct file *file, void *priv, unsigned int *i)
463 static int rvin_s_input(struct file *file, void *priv, unsigned int i)
470 static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a)
472 struct rvin_dev *vin = video_drvdata(file);
473 struct v4l2_subdev *sd = vin_to_source(vin);
475 return v4l2_subdev_call(sd, video, querystd, a);
478 static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a)
480 struct rvin_dev *vin = video_drvdata(file);
483 ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a);
489 /* Changing the standard will change the width/height */
490 return rvin_reset_format(vin);
493 static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a)
495 struct rvin_dev *vin = video_drvdata(file);
497 if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap))
505 static int rvin_subscribe_event(struct v4l2_fh *fh,
506 const struct v4l2_event_subscription *sub)
509 case V4L2_EVENT_SOURCE_CHANGE:
510 return v4l2_event_subscribe(fh, sub, 4, NULL);
512 return v4l2_ctrl_subscribe_event(fh, sub);
515 static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
516 struct v4l2_enum_dv_timings *timings)
518 struct rvin_dev *vin = video_drvdata(file);
519 struct v4l2_subdev *sd = vin_to_source(vin);
525 timings->pad = vin->parallel->sink_pad;
527 ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
534 static int rvin_s_dv_timings(struct file *file, void *priv_fh,
535 struct v4l2_dv_timings *timings)
537 struct rvin_dev *vin = video_drvdata(file);
538 struct v4l2_subdev *sd = vin_to_source(vin);
541 ret = v4l2_subdev_call(sd, video, s_dv_timings, timings);
545 /* Changing the timings will change the width/height */
546 return rvin_reset_format(vin);
549 static int rvin_g_dv_timings(struct file *file, void *priv_fh,
550 struct v4l2_dv_timings *timings)
552 struct rvin_dev *vin = video_drvdata(file);
553 struct v4l2_subdev *sd = vin_to_source(vin);
555 return v4l2_subdev_call(sd, video, g_dv_timings, timings);
558 static int rvin_query_dv_timings(struct file *file, void *priv_fh,
559 struct v4l2_dv_timings *timings)
561 struct rvin_dev *vin = video_drvdata(file);
562 struct v4l2_subdev *sd = vin_to_source(vin);
564 return v4l2_subdev_call(sd, video, query_dv_timings, timings);
567 static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
568 struct v4l2_dv_timings_cap *cap)
570 struct rvin_dev *vin = video_drvdata(file);
571 struct v4l2_subdev *sd = vin_to_source(vin);
577 cap->pad = vin->parallel->sink_pad;
579 ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
586 static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
588 struct rvin_dev *vin = video_drvdata(file);
589 struct v4l2_subdev *sd = vin_to_source(vin);
595 edid->pad = vin->parallel->sink_pad;
597 ret = v4l2_subdev_call(sd, pad, get_edid, edid);
604 static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
606 struct rvin_dev *vin = video_drvdata(file);
607 struct v4l2_subdev *sd = vin_to_source(vin);
613 edid->pad = vin->parallel->sink_pad;
615 ret = v4l2_subdev_call(sd, pad, set_edid, edid);
622 static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
623 .vidioc_querycap = rvin_querycap,
624 .vidioc_try_fmt_vid_cap = rvin_try_fmt_vid_cap,
625 .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap,
626 .vidioc_s_fmt_vid_cap = rvin_s_fmt_vid_cap,
627 .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
629 .vidioc_g_selection = rvin_g_selection,
630 .vidioc_s_selection = rvin_s_selection,
632 .vidioc_g_pixelaspect = rvin_g_pixelaspect,
634 .vidioc_enum_input = rvin_enum_input,
635 .vidioc_g_input = rvin_g_input,
636 .vidioc_s_input = rvin_s_input,
638 .vidioc_dv_timings_cap = rvin_dv_timings_cap,
639 .vidioc_enum_dv_timings = rvin_enum_dv_timings,
640 .vidioc_g_dv_timings = rvin_g_dv_timings,
641 .vidioc_s_dv_timings = rvin_s_dv_timings,
642 .vidioc_query_dv_timings = rvin_query_dv_timings,
644 .vidioc_g_edid = rvin_g_edid,
645 .vidioc_s_edid = rvin_s_edid,
647 .vidioc_querystd = rvin_querystd,
648 .vidioc_g_std = rvin_g_std,
649 .vidioc_s_std = rvin_s_std,
651 .vidioc_reqbufs = vb2_ioctl_reqbufs,
652 .vidioc_create_bufs = vb2_ioctl_create_bufs,
653 .vidioc_querybuf = vb2_ioctl_querybuf,
654 .vidioc_qbuf = vb2_ioctl_qbuf,
655 .vidioc_dqbuf = vb2_ioctl_dqbuf,
656 .vidioc_expbuf = vb2_ioctl_expbuf,
657 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
658 .vidioc_streamon = vb2_ioctl_streamon,
659 .vidioc_streamoff = vb2_ioctl_streamoff,
661 .vidioc_log_status = v4l2_ctrl_log_status,
662 .vidioc_subscribe_event = rvin_subscribe_event,
663 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
666 /* -----------------------------------------------------------------------------
667 * V4L2 Media Controller
670 static void rvin_mc_try_format(struct rvin_dev *vin,
671 struct v4l2_pix_format *pix)
674 * The V4L2 specification clearly documents the colorspace fields
675 * as being set by drivers for capture devices. Using the values
676 * supplied by userspace thus wouldn't comply with the API. Until
677 * the API is updated force fixed values.
679 pix->colorspace = RVIN_DEFAULT_COLORSPACE;
680 pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
681 pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
682 pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
685 rvin_format_align(vin, pix);
688 static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
689 struct v4l2_format *f)
691 struct rvin_dev *vin = video_drvdata(file);
693 rvin_mc_try_format(vin, &f->fmt.pix);
698 static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
699 struct v4l2_format *f)
701 struct rvin_dev *vin = video_drvdata(file);
703 if (vb2_is_busy(&vin->queue))
706 rvin_mc_try_format(vin, &f->fmt.pix);
708 vin->format = f->fmt.pix;
712 vin->crop.width = vin->format.width;
713 vin->crop.height = vin->format.height;
714 vin->compose = vin->crop;
719 static int rvin_mc_enum_input(struct file *file, void *priv,
720 struct v4l2_input *i)
725 i->type = V4L2_INPUT_TYPE_CAMERA;
726 strscpy(i->name, "Camera", sizeof(i->name));
731 static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
732 .vidioc_querycap = rvin_querycap,
733 .vidioc_try_fmt_vid_cap = rvin_mc_try_fmt_vid_cap,
734 .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap,
735 .vidioc_s_fmt_vid_cap = rvin_mc_s_fmt_vid_cap,
736 .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
738 .vidioc_enum_input = rvin_mc_enum_input,
739 .vidioc_g_input = rvin_g_input,
740 .vidioc_s_input = rvin_s_input,
742 .vidioc_reqbufs = vb2_ioctl_reqbufs,
743 .vidioc_create_bufs = vb2_ioctl_create_bufs,
744 .vidioc_querybuf = vb2_ioctl_querybuf,
745 .vidioc_qbuf = vb2_ioctl_qbuf,
746 .vidioc_dqbuf = vb2_ioctl_dqbuf,
747 .vidioc_expbuf = vb2_ioctl_expbuf,
748 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
749 .vidioc_streamon = vb2_ioctl_streamon,
750 .vidioc_streamoff = vb2_ioctl_streamoff,
752 .vidioc_log_status = v4l2_ctrl_log_status,
753 .vidioc_subscribe_event = rvin_subscribe_event,
754 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
757 /* -----------------------------------------------------------------------------
761 static int rvin_power_parallel(struct rvin_dev *vin, bool on)
763 struct v4l2_subdev *sd = vin_to_source(vin);
764 int power = on ? 1 : 0;
767 ret = v4l2_subdev_call(sd, core, s_power, power);
768 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
774 static int rvin_open(struct file *file)
776 struct rvin_dev *vin = video_drvdata(file);
779 ret = pm_runtime_get_sync(vin->dev);
783 ret = mutex_lock_interruptible(&vin->lock);
787 file->private_data = vin;
789 ret = v4l2_fh_open(file);
793 if (vin->info->use_mc)
794 ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
795 else if (v4l2_fh_is_singular_file(file))
796 ret = rvin_power_parallel(vin, true);
801 ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler);
805 mutex_unlock(&vin->lock);
809 if (vin->info->use_mc)
810 v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
811 else if (v4l2_fh_is_singular_file(file))
812 rvin_power_parallel(vin, false);
814 v4l2_fh_release(file);
816 mutex_unlock(&vin->lock);
818 pm_runtime_put(vin->dev);
823 static int rvin_release(struct file *file)
825 struct rvin_dev *vin = video_drvdata(file);
829 mutex_lock(&vin->lock);
831 /* Save the singular status before we call the clean-up helper */
832 fh_singular = v4l2_fh_is_singular_file(file);
834 /* the release helper will cleanup any on-going streaming */
835 ret = _vb2_fop_release(file, NULL);
837 if (vin->info->use_mc) {
838 v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
841 rvin_power_parallel(vin, false);
844 mutex_unlock(&vin->lock);
846 pm_runtime_put(vin->dev);
851 static const struct v4l2_file_operations rvin_fops = {
852 .owner = THIS_MODULE,
853 .unlocked_ioctl = video_ioctl2,
855 .release = rvin_release,
856 .poll = vb2_fop_poll,
857 .mmap = vb2_fop_mmap,
858 .read = vb2_fop_read,
861 void rvin_v4l2_unregister(struct rvin_dev *vin)
863 if (!video_is_registered(&vin->vdev))
866 v4l2_info(&vin->v4l2_dev, "Removing %s\n",
867 video_device_node_name(&vin->vdev));
869 /* Checks internally if vdev have been init or not */
870 video_unregister_device(&vin->vdev);
873 static void rvin_notify(struct v4l2_subdev *sd,
874 unsigned int notification, void *arg)
876 struct rvin_dev *vin =
877 container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev);
879 switch (notification) {
880 case V4L2_DEVICE_NOTIFY_EVENT:
881 v4l2_event_queue(&vin->vdev, arg);
888 int rvin_v4l2_register(struct rvin_dev *vin)
890 struct video_device *vdev = &vin->vdev;
893 vin->v4l2_dev.notify = rvin_notify;
896 vdev->v4l2_dev = &vin->v4l2_dev;
897 vdev->queue = &vin->queue;
898 snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id);
899 vdev->release = video_device_release_empty;
900 vdev->lock = &vin->lock;
901 vdev->fops = &rvin_fops;
902 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
905 /* Set a default format */
906 vin->format.pixelformat = RVIN_DEFAULT_FORMAT;
907 vin->format.width = RVIN_DEFAULT_WIDTH;
908 vin->format.height = RVIN_DEFAULT_HEIGHT;
909 vin->format.field = RVIN_DEFAULT_FIELD;
910 vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
912 if (vin->info->use_mc) {
913 vdev->ioctl_ops = &rvin_mc_ioctl_ops;
915 vdev->ioctl_ops = &rvin_ioctl_ops;
916 rvin_reset_format(vin);
919 rvin_format_align(vin, &vin->format);
921 ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1);
923 vin_err(vin, "Failed to register video device\n");
927 video_set_drvdata(&vin->vdev, vin);
929 v4l2_info(&vin->v4l2_dev, "Device registered as %s\n",
930 video_device_node_name(&vin->vdev));