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
,
59 const struct rvin_video_format
*rvin_format_from_pixel(u32 pixelformat
)
63 for (i
= 0; i
< ARRAY_SIZE(rvin_formats
); i
++)
64 if (rvin_formats
[i
].fourcc
== pixelformat
)
65 return rvin_formats
+ i
;
70 static u32
rvin_format_bytesperline(struct v4l2_pix_format
*pix
)
72 const struct rvin_video_format
*fmt
;
74 fmt
= rvin_format_from_pixel(pix
->pixelformat
);
79 return pix
->width
* fmt
->bpp
;
82 static u32
rvin_format_sizeimage(struct v4l2_pix_format
*pix
)
84 if (pix
->pixelformat
== V4L2_PIX_FMT_NV16
)
85 return pix
->bytesperline
* pix
->height
* 2;
87 return pix
->bytesperline
* pix
->height
;
90 static void rvin_format_align(struct rvin_dev
*vin
, struct v4l2_pix_format
*pix
)
94 if (!rvin_format_from_pixel(pix
->pixelformat
) ||
95 (vin
->info
->model
== RCAR_M1
&&
96 pix
->pixelformat
== V4L2_PIX_FMT_XBGR32
))
97 pix
->pixelformat
= RVIN_DEFAULT_FORMAT
;
101 case V4L2_FIELD_BOTTOM
:
102 case V4L2_FIELD_NONE
:
103 case V4L2_FIELD_INTERLACED_TB
:
104 case V4L2_FIELD_INTERLACED_BT
:
105 case V4L2_FIELD_INTERLACED
:
107 case V4L2_FIELD_ALTERNATE
:
109 * Driver does not (yet) support outputting ALTERNATE to a
110 * userspace. It does support outputting INTERLACED so use
111 * the VIN hardware to combine the two fields.
113 pix
->field
= V4L2_FIELD_INTERLACED
;
117 pix
->field
= RVIN_DEFAULT_FIELD
;
121 /* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */
122 walign
= vin
->format
.pixelformat
== V4L2_PIX_FMT_NV16
? 5 : 1;
124 /* Limit to VIN capabilities */
125 v4l_bound_align_image(&pix
->width
, 2, vin
->info
->max_width
, walign
,
126 &pix
->height
, 4, vin
->info
->max_height
, 2, 0);
128 pix
->bytesperline
= rvin_format_bytesperline(pix
);
129 pix
->sizeimage
= rvin_format_sizeimage(pix
);
131 vin_dbg(vin
, "Format %ux%u bpl: %u size: %u\n",
132 pix
->width
, pix
->height
, pix
->bytesperline
, pix
->sizeimage
);
135 /* -----------------------------------------------------------------------------
139 static int rvin_reset_format(struct rvin_dev
*vin
)
141 struct v4l2_subdev_format fmt
= {
142 .which
= V4L2_SUBDEV_FORMAT_ACTIVE
,
143 .pad
= vin
->parallel
->source_pad
,
147 ret
= v4l2_subdev_call(vin_to_source(vin
), pad
, get_fmt
, NULL
, &fmt
);
151 v4l2_fill_pix_format(&vin
->format
, &fmt
.format
);
153 rvin_format_align(vin
, &vin
->format
);
156 vin
->source
.left
= 0;
157 vin
->source
.width
= vin
->format
.width
;
158 vin
->source
.height
= vin
->format
.height
;
160 vin
->crop
= vin
->source
;
161 vin
->compose
= vin
->source
;
166 static int rvin_try_format(struct rvin_dev
*vin
, u32 which
,
167 struct v4l2_pix_format
*pix
,
168 struct v4l2_rect
*crop
, struct v4l2_rect
*compose
)
170 struct v4l2_subdev
*sd
= vin_to_source(vin
);
171 struct v4l2_subdev_pad_config
*pad_cfg
;
172 struct v4l2_subdev_format format
= {
174 .pad
= vin
->parallel
->source_pad
,
176 enum v4l2_field field
;
180 pad_cfg
= v4l2_subdev_alloc_pad_config(sd
);
184 if (!rvin_format_from_pixel(pix
->pixelformat
) ||
185 (vin
->info
->model
== RCAR_M1
&&
186 pix
->pixelformat
== V4L2_PIX_FMT_XBGR32
))
187 pix
->pixelformat
= RVIN_DEFAULT_FORMAT
;
189 v4l2_fill_mbus_format(&format
.format
, pix
, vin
->mbus_code
);
191 /* Allow the video device to override field and to scale */
194 height
= pix
->height
;
196 ret
= v4l2_subdev_call(sd
, pad
, set_fmt
, pad_cfg
, &format
);
197 if (ret
< 0 && ret
!= -ENOIOCTLCMD
)
200 v4l2_fill_pix_format(pix
, &format
.format
);
205 crop
->width
= pix
->width
;
206 crop
->height
= pix
->height
;
209 * If source is ALTERNATE the driver will use the VIN hardware
210 * to INTERLACE it. The crop height then needs to be doubled.
212 if (pix
->field
== V4L2_FIELD_ALTERNATE
)
216 if (field
!= V4L2_FIELD_ANY
)
220 pix
->height
= height
;
222 rvin_format_align(vin
, pix
);
227 compose
->width
= pix
->width
;
228 compose
->height
= pix
->height
;
231 v4l2_subdev_free_pad_config(pad_cfg
);
236 static int rvin_querycap(struct file
*file
, void *priv
,
237 struct v4l2_capability
*cap
)
239 struct rvin_dev
*vin
= video_drvdata(file
);
241 strlcpy(cap
->driver
, KBUILD_MODNAME
, sizeof(cap
->driver
));
242 strlcpy(cap
->card
, "R_Car_VIN", sizeof(cap
->card
));
243 snprintf(cap
->bus_info
, sizeof(cap
->bus_info
), "platform:%s",
248 static int rvin_try_fmt_vid_cap(struct file
*file
, void *priv
,
249 struct v4l2_format
*f
)
251 struct rvin_dev
*vin
= video_drvdata(file
);
253 return rvin_try_format(vin
, V4L2_SUBDEV_FORMAT_TRY
, &f
->fmt
.pix
, NULL
,
257 static int rvin_s_fmt_vid_cap(struct file
*file
, void *priv
,
258 struct v4l2_format
*f
)
260 struct rvin_dev
*vin
= video_drvdata(file
);
261 struct v4l2_rect crop
, compose
;
264 if (vb2_is_busy(&vin
->queue
))
267 ret
= rvin_try_format(vin
, V4L2_SUBDEV_FORMAT_ACTIVE
, &f
->fmt
.pix
,
272 vin
->format
= f
->fmt
.pix
;
274 vin
->compose
= compose
;
280 static int rvin_g_fmt_vid_cap(struct file
*file
, void *priv
,
281 struct v4l2_format
*f
)
283 struct rvin_dev
*vin
= video_drvdata(file
);
285 f
->fmt
.pix
= vin
->format
;
290 static int rvin_enum_fmt_vid_cap(struct file
*file
, void *priv
,
291 struct v4l2_fmtdesc
*f
)
293 if (f
->index
>= ARRAY_SIZE(rvin_formats
))
296 f
->pixelformat
= rvin_formats
[f
->index
].fourcc
;
301 static int rvin_g_selection(struct file
*file
, void *fh
,
302 struct v4l2_selection
*s
)
304 struct rvin_dev
*vin
= video_drvdata(file
);
306 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
310 case V4L2_SEL_TGT_CROP_BOUNDS
:
311 case V4L2_SEL_TGT_CROP_DEFAULT
:
312 s
->r
.left
= s
->r
.top
= 0;
313 s
->r
.width
= vin
->source
.width
;
314 s
->r
.height
= vin
->source
.height
;
316 case V4L2_SEL_TGT_CROP
:
319 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
320 case V4L2_SEL_TGT_COMPOSE_DEFAULT
:
321 s
->r
.left
= s
->r
.top
= 0;
322 s
->r
.width
= vin
->format
.width
;
323 s
->r
.height
= vin
->format
.height
;
325 case V4L2_SEL_TGT_COMPOSE
:
335 static int rvin_s_selection(struct file
*file
, void *fh
,
336 struct v4l2_selection
*s
)
338 struct rvin_dev
*vin
= video_drvdata(file
);
339 const struct rvin_video_format
*fmt
;
340 struct v4l2_rect r
= s
->r
;
341 struct v4l2_rect max_rect
;
342 struct v4l2_rect min_rect
= {
347 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
350 v4l2_rect_set_min_size(&r
, &min_rect
);
353 case V4L2_SEL_TGT_CROP
:
354 /* Can't crop outside of source input */
355 max_rect
.top
= max_rect
.left
= 0;
356 max_rect
.width
= vin
->source
.width
;
357 max_rect
.height
= vin
->source
.height
;
358 v4l2_rect_map_inside(&r
, &max_rect
);
360 v4l_bound_align_image(&r
.width
, 6, vin
->source
.width
, 0,
361 &r
.height
, 2, vin
->source
.height
, 0, 0);
363 r
.top
= clamp_t(s32
, r
.top
, 0, vin
->source
.height
- r
.height
);
364 r
.left
= clamp_t(s32
, r
.left
, 0, vin
->source
.width
- r
.width
);
366 vin
->crop
= s
->r
= r
;
368 vin_dbg(vin
, "Cropped %dx%d@%d:%d of %dx%d\n",
369 r
.width
, r
.height
, r
.left
, r
.top
,
370 vin
->source
.width
, vin
->source
.height
);
372 case V4L2_SEL_TGT_COMPOSE
:
373 /* Make sure compose rect fits inside output format */
374 max_rect
.top
= max_rect
.left
= 0;
375 max_rect
.width
= vin
->format
.width
;
376 max_rect
.height
= vin
->format
.height
;
377 v4l2_rect_map_inside(&r
, &max_rect
);
380 * Composing is done by adding a offset to the buffer address,
381 * the HW wants this address to be aligned to HW_BUFFER_MASK.
382 * Make sure the top and left values meets this requirement.
384 while ((r
.top
* vin
->format
.bytesperline
) & HW_BUFFER_MASK
)
387 fmt
= rvin_format_from_pixel(vin
->format
.pixelformat
);
388 while ((r
.left
* fmt
->bpp
) & HW_BUFFER_MASK
)
391 vin
->compose
= s
->r
= r
;
393 vin_dbg(vin
, "Compose %dx%d@%d:%d in %dx%d\n",
394 r
.width
, r
.height
, r
.left
, r
.top
,
395 vin
->format
.width
, vin
->format
.height
);
401 /* HW supports modifying configuration while running */
402 rvin_crop_scale_comp(vin
);
407 static int rvin_cropcap(struct file
*file
, void *priv
,
408 struct v4l2_cropcap
*crop
)
410 struct rvin_dev
*vin
= video_drvdata(file
);
411 struct v4l2_subdev
*sd
= vin_to_source(vin
);
413 if (crop
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
416 return v4l2_subdev_call(sd
, video
, g_pixelaspect
, &crop
->pixelaspect
);
419 static int rvin_enum_input(struct file
*file
, void *priv
,
420 struct v4l2_input
*i
)
422 struct rvin_dev
*vin
= video_drvdata(file
);
423 struct v4l2_subdev
*sd
= vin_to_source(vin
);
429 ret
= v4l2_subdev_call(sd
, video
, g_input_status
, &i
->status
);
430 if (ret
< 0 && ret
!= -ENOIOCTLCMD
&& ret
!= -ENODEV
)
433 i
->type
= V4L2_INPUT_TYPE_CAMERA
;
435 if (v4l2_subdev_has_op(sd
, pad
, dv_timings_cap
)) {
436 i
->capabilities
= V4L2_IN_CAP_DV_TIMINGS
;
439 i
->capabilities
= V4L2_IN_CAP_STD
;
440 i
->std
= vin
->vdev
.tvnorms
;
443 strlcpy(i
->name
, "Camera", sizeof(i
->name
));
448 static int rvin_g_input(struct file
*file
, void *priv
, unsigned int *i
)
454 static int rvin_s_input(struct file
*file
, void *priv
, unsigned int i
)
461 static int rvin_querystd(struct file
*file
, void *priv
, v4l2_std_id
*a
)
463 struct rvin_dev
*vin
= video_drvdata(file
);
464 struct v4l2_subdev
*sd
= vin_to_source(vin
);
466 return v4l2_subdev_call(sd
, video
, querystd
, a
);
469 static int rvin_s_std(struct file
*file
, void *priv
, v4l2_std_id a
)
471 struct rvin_dev
*vin
= video_drvdata(file
);
474 ret
= v4l2_subdev_call(vin_to_source(vin
), video
, s_std
, a
);
480 /* Changing the standard will change the width/height */
481 return rvin_reset_format(vin
);
484 static int rvin_g_std(struct file
*file
, void *priv
, v4l2_std_id
*a
)
486 struct rvin_dev
*vin
= video_drvdata(file
);
488 if (v4l2_subdev_has_op(vin_to_source(vin
), pad
, dv_timings_cap
))
496 static int rvin_subscribe_event(struct v4l2_fh
*fh
,
497 const struct v4l2_event_subscription
*sub
)
500 case V4L2_EVENT_SOURCE_CHANGE
:
501 return v4l2_event_subscribe(fh
, sub
, 4, NULL
);
503 return v4l2_ctrl_subscribe_event(fh
, sub
);
506 static int rvin_enum_dv_timings(struct file
*file
, void *priv_fh
,
507 struct v4l2_enum_dv_timings
*timings
)
509 struct rvin_dev
*vin
= video_drvdata(file
);
510 struct v4l2_subdev
*sd
= vin_to_source(vin
);
516 timings
->pad
= vin
->parallel
->sink_pad
;
518 ret
= v4l2_subdev_call(sd
, pad
, enum_dv_timings
, timings
);
525 static int rvin_s_dv_timings(struct file
*file
, void *priv_fh
,
526 struct v4l2_dv_timings
*timings
)
528 struct rvin_dev
*vin
= video_drvdata(file
);
529 struct v4l2_subdev
*sd
= vin_to_source(vin
);
532 ret
= v4l2_subdev_call(sd
, video
, s_dv_timings
, timings
);
536 /* Changing the timings will change the width/height */
537 return rvin_reset_format(vin
);
540 static int rvin_g_dv_timings(struct file
*file
, void *priv_fh
,
541 struct v4l2_dv_timings
*timings
)
543 struct rvin_dev
*vin
= video_drvdata(file
);
544 struct v4l2_subdev
*sd
= vin_to_source(vin
);
546 return v4l2_subdev_call(sd
, video
, g_dv_timings
, timings
);
549 static int rvin_query_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
, query_dv_timings
, timings
);
558 static int rvin_dv_timings_cap(struct file
*file
, void *priv_fh
,
559 struct v4l2_dv_timings_cap
*cap
)
561 struct rvin_dev
*vin
= video_drvdata(file
);
562 struct v4l2_subdev
*sd
= vin_to_source(vin
);
568 cap
->pad
= vin
->parallel
->sink_pad
;
570 ret
= v4l2_subdev_call(sd
, pad
, dv_timings_cap
, cap
);
577 static int rvin_g_edid(struct file
*file
, void *fh
, struct v4l2_edid
*edid
)
579 struct rvin_dev
*vin
= video_drvdata(file
);
580 struct v4l2_subdev
*sd
= vin_to_source(vin
);
586 edid
->pad
= vin
->parallel
->sink_pad
;
588 ret
= v4l2_subdev_call(sd
, pad
, get_edid
, edid
);
595 static int rvin_s_edid(struct file
*file
, void *fh
, struct v4l2_edid
*edid
)
597 struct rvin_dev
*vin
= video_drvdata(file
);
598 struct v4l2_subdev
*sd
= vin_to_source(vin
);
604 edid
->pad
= vin
->parallel
->sink_pad
;
606 ret
= v4l2_subdev_call(sd
, pad
, set_edid
, edid
);
613 static const struct v4l2_ioctl_ops rvin_ioctl_ops
= {
614 .vidioc_querycap
= rvin_querycap
,
615 .vidioc_try_fmt_vid_cap
= rvin_try_fmt_vid_cap
,
616 .vidioc_g_fmt_vid_cap
= rvin_g_fmt_vid_cap
,
617 .vidioc_s_fmt_vid_cap
= rvin_s_fmt_vid_cap
,
618 .vidioc_enum_fmt_vid_cap
= rvin_enum_fmt_vid_cap
,
620 .vidioc_g_selection
= rvin_g_selection
,
621 .vidioc_s_selection
= rvin_s_selection
,
623 .vidioc_cropcap
= rvin_cropcap
,
625 .vidioc_enum_input
= rvin_enum_input
,
626 .vidioc_g_input
= rvin_g_input
,
627 .vidioc_s_input
= rvin_s_input
,
629 .vidioc_dv_timings_cap
= rvin_dv_timings_cap
,
630 .vidioc_enum_dv_timings
= rvin_enum_dv_timings
,
631 .vidioc_g_dv_timings
= rvin_g_dv_timings
,
632 .vidioc_s_dv_timings
= rvin_s_dv_timings
,
633 .vidioc_query_dv_timings
= rvin_query_dv_timings
,
635 .vidioc_g_edid
= rvin_g_edid
,
636 .vidioc_s_edid
= rvin_s_edid
,
638 .vidioc_querystd
= rvin_querystd
,
639 .vidioc_g_std
= rvin_g_std
,
640 .vidioc_s_std
= rvin_s_std
,
642 .vidioc_reqbufs
= vb2_ioctl_reqbufs
,
643 .vidioc_create_bufs
= vb2_ioctl_create_bufs
,
644 .vidioc_querybuf
= vb2_ioctl_querybuf
,
645 .vidioc_qbuf
= vb2_ioctl_qbuf
,
646 .vidioc_dqbuf
= vb2_ioctl_dqbuf
,
647 .vidioc_expbuf
= vb2_ioctl_expbuf
,
648 .vidioc_prepare_buf
= vb2_ioctl_prepare_buf
,
649 .vidioc_streamon
= vb2_ioctl_streamon
,
650 .vidioc_streamoff
= vb2_ioctl_streamoff
,
652 .vidioc_log_status
= v4l2_ctrl_log_status
,
653 .vidioc_subscribe_event
= rvin_subscribe_event
,
654 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
657 /* -----------------------------------------------------------------------------
658 * V4L2 Media Controller
661 static void rvin_mc_try_format(struct rvin_dev
*vin
,
662 struct v4l2_pix_format
*pix
)
665 * The V4L2 specification clearly documents the colorspace fields
666 * as being set by drivers for capture devices. Using the values
667 * supplied by userspace thus wouldn't comply with the API. Until
668 * the API is updated force fixed vaules.
670 pix
->colorspace
= RVIN_DEFAULT_COLORSPACE
;
671 pix
->xfer_func
= V4L2_MAP_XFER_FUNC_DEFAULT(pix
->colorspace
);
672 pix
->ycbcr_enc
= V4L2_MAP_YCBCR_ENC_DEFAULT(pix
->colorspace
);
673 pix
->quantization
= V4L2_MAP_QUANTIZATION_DEFAULT(true, pix
->colorspace
,
676 rvin_format_align(vin
, pix
);
679 static int rvin_mc_try_fmt_vid_cap(struct file
*file
, void *priv
,
680 struct v4l2_format
*f
)
682 struct rvin_dev
*vin
= video_drvdata(file
);
684 rvin_mc_try_format(vin
, &f
->fmt
.pix
);
689 static int rvin_mc_s_fmt_vid_cap(struct file
*file
, void *priv
,
690 struct v4l2_format
*f
)
692 struct rvin_dev
*vin
= video_drvdata(file
);
694 if (vb2_is_busy(&vin
->queue
))
697 rvin_mc_try_format(vin
, &f
->fmt
.pix
);
699 vin
->format
= f
->fmt
.pix
;
703 vin
->crop
.width
= vin
->format
.width
;
704 vin
->crop
.height
= vin
->format
.height
;
705 vin
->compose
= vin
->crop
;
710 static int rvin_mc_enum_input(struct file
*file
, void *priv
,
711 struct v4l2_input
*i
)
716 i
->type
= V4L2_INPUT_TYPE_CAMERA
;
717 strlcpy(i
->name
, "Camera", sizeof(i
->name
));
722 static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops
= {
723 .vidioc_querycap
= rvin_querycap
,
724 .vidioc_try_fmt_vid_cap
= rvin_mc_try_fmt_vid_cap
,
725 .vidioc_g_fmt_vid_cap
= rvin_g_fmt_vid_cap
,
726 .vidioc_s_fmt_vid_cap
= rvin_mc_s_fmt_vid_cap
,
727 .vidioc_enum_fmt_vid_cap
= rvin_enum_fmt_vid_cap
,
729 .vidioc_enum_input
= rvin_mc_enum_input
,
730 .vidioc_g_input
= rvin_g_input
,
731 .vidioc_s_input
= rvin_s_input
,
733 .vidioc_reqbufs
= vb2_ioctl_reqbufs
,
734 .vidioc_create_bufs
= vb2_ioctl_create_bufs
,
735 .vidioc_querybuf
= vb2_ioctl_querybuf
,
736 .vidioc_qbuf
= vb2_ioctl_qbuf
,
737 .vidioc_dqbuf
= vb2_ioctl_dqbuf
,
738 .vidioc_expbuf
= vb2_ioctl_expbuf
,
739 .vidioc_prepare_buf
= vb2_ioctl_prepare_buf
,
740 .vidioc_streamon
= vb2_ioctl_streamon
,
741 .vidioc_streamoff
= vb2_ioctl_streamoff
,
743 .vidioc_log_status
= v4l2_ctrl_log_status
,
744 .vidioc_subscribe_event
= rvin_subscribe_event
,
745 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
748 /* -----------------------------------------------------------------------------
752 static int rvin_power_on(struct rvin_dev
*vin
)
755 struct v4l2_subdev
*sd
= vin_to_source(vin
);
757 pm_runtime_get_sync(vin
->v4l2_dev
.dev
);
759 ret
= v4l2_subdev_call(sd
, core
, s_power
, 1);
760 if (ret
< 0 && ret
!= -ENOIOCTLCMD
&& ret
!= -ENODEV
)
765 static int rvin_power_off(struct rvin_dev
*vin
)
768 struct v4l2_subdev
*sd
= vin_to_source(vin
);
770 ret
= v4l2_subdev_call(sd
, core
, s_power
, 0);
772 pm_runtime_put(vin
->v4l2_dev
.dev
);
774 if (ret
< 0 && ret
!= -ENOIOCTLCMD
&& ret
!= -ENODEV
)
780 static int rvin_initialize_device(struct file
*file
)
782 struct rvin_dev
*vin
= video_drvdata(file
);
785 struct v4l2_format f
= {
786 .type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
,
788 .width
= vin
->format
.width
,
789 .height
= vin
->format
.height
,
790 .field
= vin
->format
.field
,
791 .colorspace
= vin
->format
.colorspace
,
792 .pixelformat
= vin
->format
.pixelformat
,
796 ret
= rvin_power_on(vin
);
800 pm_runtime_enable(&vin
->vdev
.dev
);
801 ret
= pm_runtime_resume(&vin
->vdev
.dev
);
802 if (ret
< 0 && ret
!= -ENOSYS
)
806 * Try to configure with default parameters. Notice: this is the
807 * very first open, so, we cannot race against other calls,
808 * apart from someone else calling open() simultaneously, but
809 * .host_lock is protecting us against it.
811 ret
= rvin_s_fmt_vid_cap(file
, NULL
, &f
);
815 v4l2_ctrl_handler_setup(&vin
->ctrl_handler
);
819 pm_runtime_disable(&vin
->vdev
.dev
);
826 static int rvin_open(struct file
*file
)
828 struct rvin_dev
*vin
= video_drvdata(file
);
831 mutex_lock(&vin
->lock
);
833 file
->private_data
= vin
;
835 ret
= v4l2_fh_open(file
);
839 if (!v4l2_fh_is_singular_file(file
))
842 if (rvin_initialize_device(file
)) {
843 v4l2_fh_release(file
);
848 mutex_unlock(&vin
->lock
);
852 static int rvin_release(struct file
*file
)
854 struct rvin_dev
*vin
= video_drvdata(file
);
858 mutex_lock(&vin
->lock
);
860 /* Save the singular status before we call the clean-up helper */
861 fh_singular
= v4l2_fh_is_singular_file(file
);
863 /* the release helper will cleanup any on-going streaming */
864 ret
= _vb2_fop_release(file
, NULL
);
867 * If this was the last open file.
868 * Then de-initialize hw module.
871 pm_runtime_suspend(&vin
->vdev
.dev
);
872 pm_runtime_disable(&vin
->vdev
.dev
);
876 mutex_unlock(&vin
->lock
);
881 static const struct v4l2_file_operations rvin_fops
= {
882 .owner
= THIS_MODULE
,
883 .unlocked_ioctl
= video_ioctl2
,
885 .release
= rvin_release
,
886 .poll
= vb2_fop_poll
,
887 .mmap
= vb2_fop_mmap
,
888 .read
= vb2_fop_read
,
891 /* -----------------------------------------------------------------------------
892 * Media controller file operations
895 static int rvin_mc_open(struct file
*file
)
897 struct rvin_dev
*vin
= video_drvdata(file
);
900 ret
= mutex_lock_interruptible(&vin
->lock
);
904 ret
= pm_runtime_get_sync(vin
->dev
);
908 ret
= v4l2_pipeline_pm_use(&vin
->vdev
.entity
, 1);
912 file
->private_data
= vin
;
914 ret
= v4l2_fh_open(file
);
918 mutex_unlock(&vin
->lock
);
922 v4l2_pipeline_pm_use(&vin
->vdev
.entity
, 0);
924 pm_runtime_put(vin
->dev
);
926 mutex_unlock(&vin
->lock
);
931 static int rvin_mc_release(struct file
*file
)
933 struct rvin_dev
*vin
= video_drvdata(file
);
936 mutex_lock(&vin
->lock
);
938 /* the release helper will cleanup any on-going streaming. */
939 ret
= _vb2_fop_release(file
, NULL
);
941 v4l2_pipeline_pm_use(&vin
->vdev
.entity
, 0);
942 pm_runtime_put(vin
->dev
);
944 mutex_unlock(&vin
->lock
);
949 static const struct v4l2_file_operations rvin_mc_fops
= {
950 .owner
= THIS_MODULE
,
951 .unlocked_ioctl
= video_ioctl2
,
952 .open
= rvin_mc_open
,
953 .release
= rvin_mc_release
,
954 .poll
= vb2_fop_poll
,
955 .mmap
= vb2_fop_mmap
,
956 .read
= vb2_fop_read
,
959 void rvin_v4l2_unregister(struct rvin_dev
*vin
)
961 if (!video_is_registered(&vin
->vdev
))
964 v4l2_info(&vin
->v4l2_dev
, "Removing %s\n",
965 video_device_node_name(&vin
->vdev
));
967 /* Checks internaly if vdev have been init or not */
968 video_unregister_device(&vin
->vdev
);
971 static void rvin_notify(struct v4l2_subdev
*sd
,
972 unsigned int notification
, void *arg
)
974 struct rvin_dev
*vin
=
975 container_of(sd
->v4l2_dev
, struct rvin_dev
, v4l2_dev
);
977 switch (notification
) {
978 case V4L2_DEVICE_NOTIFY_EVENT
:
979 v4l2_event_queue(&vin
->vdev
, arg
);
986 int rvin_v4l2_register(struct rvin_dev
*vin
)
988 struct video_device
*vdev
= &vin
->vdev
;
991 vin
->v4l2_dev
.notify
= rvin_notify
;
994 vdev
->v4l2_dev
= &vin
->v4l2_dev
;
995 vdev
->queue
= &vin
->queue
;
996 snprintf(vdev
->name
, sizeof(vdev
->name
), "VIN%u output", vin
->id
);
997 vdev
->release
= video_device_release_empty
;
998 vdev
->lock
= &vin
->lock
;
999 vdev
->device_caps
= V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
|
1002 /* Set a default format */
1003 vin
->format
.pixelformat
= RVIN_DEFAULT_FORMAT
;
1004 vin
->format
.width
= RVIN_DEFAULT_WIDTH
;
1005 vin
->format
.height
= RVIN_DEFAULT_HEIGHT
;
1006 vin
->format
.field
= RVIN_DEFAULT_FIELD
;
1007 vin
->format
.colorspace
= RVIN_DEFAULT_COLORSPACE
;
1009 if (vin
->info
->use_mc
) {
1010 vdev
->fops
= &rvin_mc_fops
;
1011 vdev
->ioctl_ops
= &rvin_mc_ioctl_ops
;
1013 vdev
->fops
= &rvin_fops
;
1014 vdev
->ioctl_ops
= &rvin_ioctl_ops
;
1015 rvin_reset_format(vin
);
1018 rvin_format_align(vin
, &vin
->format
);
1020 ret
= video_register_device(&vin
->vdev
, VFL_TYPE_GRABBER
, -1);
1022 vin_err(vin
, "Failed to register video device\n");
1026 video_set_drvdata(&vin
->vdev
, vin
);
1028 v4l2_info(&vin
->v4l2_dev
, "Device registered as %s\n",
1029 video_device_node_name(&vin
->vdev
));