1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/pm_runtime.h>
14
15#include <media/v4l2-event.h>
16#include <media/v4l2-ioctl.h>
17#include <media/v4l2-mc.h>
18#include <media/v4l2-rect.h>
19
20#include "rcar-vin.h"
21
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
27
28
29
30
31
32static const struct rvin_video_format rvin_formats[] = {
33 {
34 .fourcc = V4L2_PIX_FMT_NV12,
35 .bpp = 1,
36 },
37 {
38 .fourcc = V4L2_PIX_FMT_NV16,
39 .bpp = 1,
40 },
41 {
42 .fourcc = V4L2_PIX_FMT_YUYV,
43 .bpp = 2,
44 },
45 {
46 .fourcc = V4L2_PIX_FMT_UYVY,
47 .bpp = 2,
48 },
49 {
50 .fourcc = V4L2_PIX_FMT_RGB565,
51 .bpp = 2,
52 },
53 {
54 .fourcc = V4L2_PIX_FMT_XRGB555,
55 .bpp = 2,
56 },
57 {
58 .fourcc = V4L2_PIX_FMT_XBGR32,
59 .bpp = 4,
60 },
61 {
62 .fourcc = V4L2_PIX_FMT_ARGB555,
63 .bpp = 2,
64 },
65 {
66 .fourcc = V4L2_PIX_FMT_ABGR32,
67 .bpp = 4,
68 },
69};
70
71const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
72 u32 pixelformat)
73{
74 int i;
75
76 switch (pixelformat) {
77 case V4L2_PIX_FMT_XBGR32:
78 if (vin->info->model == RCAR_M1)
79 return NULL;
80 break;
81 case V4L2_PIX_FMT_NV12:
82
83
84
85
86 if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333))
87 return NULL;
88 break;
89 default:
90 break;
91 }
92
93 for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
94 if (rvin_formats[i].fourcc == pixelformat)
95 return rvin_formats + i;
96
97 return NULL;
98}
99
100static u32 rvin_format_bytesperline(struct rvin_dev *vin,
101 struct v4l2_pix_format *pix)
102{
103 const struct rvin_video_format *fmt;
104 u32 align;
105
106 fmt = rvin_format_from_pixel(vin, pix->pixelformat);
107
108 if (WARN_ON(!fmt))
109 return -EINVAL;
110
111 switch (pix->pixelformat) {
112 case V4L2_PIX_FMT_NV12:
113 case V4L2_PIX_FMT_NV16:
114 align = 0x20;
115 break;
116 default:
117 align = 0x10;
118 break;
119 }
120
121 if (V4L2_FIELD_IS_SEQUENTIAL(pix->field))
122 align = 0x80;
123
124 return ALIGN(pix->width, align) * fmt->bpp;
125}
126
127static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix)
128{
129 switch (pix->pixelformat) {
130 case V4L2_PIX_FMT_NV12:
131 return pix->bytesperline * pix->height * 3 / 2;
132 case V4L2_PIX_FMT_NV16:
133 return pix->bytesperline * pix->height * 2;
134 default:
135 return pix->bytesperline * pix->height;
136 }
137}
138
139static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
140{
141 u32 walign;
142
143 if (!rvin_format_from_pixel(vin, pix->pixelformat))
144 pix->pixelformat = RVIN_DEFAULT_FORMAT;
145
146 switch (pix->field) {
147 case V4L2_FIELD_TOP:
148 case V4L2_FIELD_BOTTOM:
149 case V4L2_FIELD_NONE:
150 case V4L2_FIELD_INTERLACED_TB:
151 case V4L2_FIELD_INTERLACED_BT:
152 case V4L2_FIELD_INTERLACED:
153 case V4L2_FIELD_ALTERNATE:
154 case V4L2_FIELD_SEQ_TB:
155 case V4L2_FIELD_SEQ_BT:
156 break;
157 default:
158 pix->field = RVIN_DEFAULT_FIELD;
159 break;
160 }
161
162
163 switch (pix->pixelformat) {
164 case V4L2_PIX_FMT_NV12:
165 case V4L2_PIX_FMT_NV16:
166 walign = 5;
167 break;
168 default:
169 walign = 1;
170 break;
171 }
172
173
174 v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign,
175 &pix->height, 4, vin->info->max_height, 2, 0);
176
177 pix->bytesperline = rvin_format_bytesperline(vin, pix);
178 pix->sizeimage = rvin_format_sizeimage(pix);
179
180 vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n",
181 pix->width, pix->height, pix->bytesperline, pix->sizeimage);
182}
183
184
185
186
187
188static int rvin_reset_format(struct rvin_dev *vin)
189{
190 struct v4l2_subdev_format fmt = {
191 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
192 .pad = vin->parallel->source_pad,
193 };
194 int ret;
195
196 ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
197 if (ret)
198 return ret;
199
200 v4l2_fill_pix_format(&vin->format, &fmt.format);
201
202 vin->src_rect.top = 0;
203 vin->src_rect.left = 0;
204 vin->src_rect.width = vin->format.width;
205 vin->src_rect.height = vin->format.height;
206
207
208 if (vin->format.field == V4L2_FIELD_ALTERNATE) {
209 vin->format.field = V4L2_FIELD_INTERLACED;
210 vin->format.height *= 2;
211 }
212
213 rvin_format_align(vin, &vin->format);
214
215 vin->crop = vin->src_rect;
216
217 vin->compose.top = 0;
218 vin->compose.left = 0;
219 vin->compose.width = vin->format.width;
220 vin->compose.height = vin->format.height;
221
222 return 0;
223}
224
225static int rvin_try_format(struct rvin_dev *vin, u32 which,
226 struct v4l2_pix_format *pix,
227 struct v4l2_rect *src_rect)
228{
229 struct v4l2_subdev *sd = vin_to_source(vin);
230 struct v4l2_subdev_pad_config *pad_cfg;
231 struct v4l2_subdev_format format = {
232 .which = which,
233 .pad = vin->parallel->source_pad,
234 };
235 enum v4l2_field field;
236 u32 width, height;
237 int ret;
238
239 pad_cfg = v4l2_subdev_alloc_pad_config(sd);
240 if (pad_cfg == NULL)
241 return -ENOMEM;
242
243 if (!rvin_format_from_pixel(vin, pix->pixelformat))
244 pix->pixelformat = RVIN_DEFAULT_FORMAT;
245
246 v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code);
247
248
249 field = pix->field;
250 width = pix->width;
251 height = pix->height;
252
253 ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
254 if (ret < 0 && ret != -ENOIOCTLCMD)
255 goto done;
256 ret = 0;
257
258 v4l2_fill_pix_format(pix, &format.format);
259
260 if (src_rect) {
261 src_rect->top = 0;
262 src_rect->left = 0;
263 src_rect->width = pix->width;
264 src_rect->height = pix->height;
265 }
266
267 if (field != V4L2_FIELD_ANY)
268 pix->field = field;
269
270 pix->width = width;
271 pix->height = height;
272
273 rvin_format_align(vin, pix);
274done:
275 v4l2_subdev_free_pad_config(pad_cfg);
276
277 return ret;
278}
279
280static int rvin_querycap(struct file *file, void *priv,
281 struct v4l2_capability *cap)
282{
283 struct rvin_dev *vin = video_drvdata(file);
284
285 strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
286 strscpy(cap->card, "R_Car_VIN", sizeof(cap->card));
287 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
288 dev_name(vin->dev));
289 return 0;
290}
291
292static int rvin_try_fmt_vid_cap(struct file *file, void *priv,
293 struct v4l2_format *f)
294{
295 struct rvin_dev *vin = video_drvdata(file);
296
297 return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL);
298}
299
300static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
301 struct v4l2_format *f)
302{
303 struct rvin_dev *vin = video_drvdata(file);
304 struct v4l2_rect fmt_rect, src_rect;
305 int ret;
306
307 if (vb2_is_busy(&vin->queue))
308 return -EBUSY;
309
310 ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
311 &src_rect);
312 if (ret)
313 return ret;
314
315 vin->format = f->fmt.pix;
316
317 fmt_rect.top = 0;
318 fmt_rect.left = 0;
319 fmt_rect.width = vin->format.width;
320 fmt_rect.height = vin->format.height;
321
322 v4l2_rect_map_inside(&vin->crop, &src_rect);
323 v4l2_rect_map_inside(&vin->compose, &fmt_rect);
324 vin->src_rect = src_rect;
325
326 return 0;
327}
328
329static int rvin_g_fmt_vid_cap(struct file *file, void *priv,
330 struct v4l2_format *f)
331{
332 struct rvin_dev *vin = video_drvdata(file);
333
334 f->fmt.pix = vin->format;
335
336 return 0;
337}
338
339static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
340 struct v4l2_fmtdesc *f)
341{
342 struct rvin_dev *vin = video_drvdata(file);
343 unsigned int i;
344 int matched;
345
346
347
348
349
350
351
352
353
354
355
356
357 switch (f->mbus_code) {
358 case 0:
359 case MEDIA_BUS_FMT_YUYV8_1X16:
360 case MEDIA_BUS_FMT_UYVY8_1X16:
361 case MEDIA_BUS_FMT_UYVY8_2X8:
362 case MEDIA_BUS_FMT_UYVY10_2X10:
363 case MEDIA_BUS_FMT_RGB888_1X24:
364 break;
365 default:
366 return -EINVAL;
367 }
368
369 matched = -1;
370 for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) {
371 if (rvin_format_from_pixel(vin, rvin_formats[i].fourcc))
372 matched++;
373
374 if (matched == f->index) {
375 f->pixelformat = rvin_formats[i].fourcc;
376 return 0;
377 }
378 }
379
380 return -EINVAL;
381}
382
383static int rvin_g_selection(struct file *file, void *fh,
384 struct v4l2_selection *s)
385{
386 struct rvin_dev *vin = video_drvdata(file);
387
388 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
389 return -EINVAL;
390
391 switch (s->target) {
392 case V4L2_SEL_TGT_CROP_BOUNDS:
393 case V4L2_SEL_TGT_CROP_DEFAULT:
394 s->r.left = s->r.top = 0;
395 s->r.width = vin->src_rect.width;
396 s->r.height = vin->src_rect.height;
397 break;
398 case V4L2_SEL_TGT_CROP:
399 s->r = vin->crop;
400 break;
401 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
402 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
403 s->r.left = s->r.top = 0;
404 s->r.width = vin->format.width;
405 s->r.height = vin->format.height;
406 break;
407 case V4L2_SEL_TGT_COMPOSE:
408 s->r = vin->compose;
409 break;
410 default:
411 return -EINVAL;
412 }
413
414 return 0;
415}
416
417static int rvin_s_selection(struct file *file, void *fh,
418 struct v4l2_selection *s)
419{
420 struct rvin_dev *vin = video_drvdata(file);
421 const struct rvin_video_format *fmt;
422 struct v4l2_rect r = s->r;
423 struct v4l2_rect max_rect;
424 struct v4l2_rect min_rect = {
425 .width = 6,
426 .height = 2,
427 };
428
429 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
430 return -EINVAL;
431
432 v4l2_rect_set_min_size(&r, &min_rect);
433
434 switch (s->target) {
435 case V4L2_SEL_TGT_CROP:
436
437 max_rect.top = max_rect.left = 0;
438 max_rect.width = vin->src_rect.width;
439 max_rect.height = vin->src_rect.height;
440 v4l2_rect_map_inside(&r, &max_rect);
441
442 v4l_bound_align_image(&r.width, 6, vin->src_rect.width, 0,
443 &r.height, 2, vin->src_rect.height, 0, 0);
444
445 r.top = clamp_t(s32, r.top, 0,
446 vin->src_rect.height - r.height);
447 r.left = clamp_t(s32, r.left, 0, vin->src_rect.width - r.width);
448
449 vin->crop = s->r = r;
450
451 vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
452 r.width, r.height, r.left, r.top,
453 vin->src_rect.width, vin->src_rect.height);
454 break;
455 case V4L2_SEL_TGT_COMPOSE:
456
457 max_rect.top = max_rect.left = 0;
458 max_rect.width = vin->format.width;
459 max_rect.height = vin->format.height;
460 v4l2_rect_map_inside(&r, &max_rect);
461
462
463
464
465
466
467 while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
468 r.top--;
469
470 fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
471 while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
472 r.left--;
473
474 vin->compose = s->r = r;
475
476 vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n",
477 r.width, r.height, r.left, r.top,
478 vin->format.width, vin->format.height);
479 break;
480 default:
481 return -EINVAL;
482 }
483
484
485 rvin_crop_scale_comp(vin);
486
487 return 0;
488}
489
490static int rvin_g_pixelaspect(struct file *file, void *priv,
491 int type, struct v4l2_fract *f)
492{
493 struct rvin_dev *vin = video_drvdata(file);
494 struct v4l2_subdev *sd = vin_to_source(vin);
495
496 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
497 return -EINVAL;
498
499 return v4l2_subdev_call(sd, video, g_pixelaspect, f);
500}
501
502static int rvin_enum_input(struct file *file, void *priv,
503 struct v4l2_input *i)
504{
505 struct rvin_dev *vin = video_drvdata(file);
506 struct v4l2_subdev *sd = vin_to_source(vin);
507 int ret;
508
509 if (i->index != 0)
510 return -EINVAL;
511
512 ret = v4l2_subdev_call(sd, video, g_input_status, &i->status);
513 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
514 return ret;
515
516 i->type = V4L2_INPUT_TYPE_CAMERA;
517
518 if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) {
519 i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
520 i->std = 0;
521 } else {
522 i->capabilities = V4L2_IN_CAP_STD;
523 i->std = vin->vdev.tvnorms;
524 }
525
526 strscpy(i->name, "Camera", sizeof(i->name));
527
528 return 0;
529}
530
531static int rvin_g_input(struct file *file, void *priv, unsigned int *i)
532{
533 *i = 0;
534 return 0;
535}
536
537static int rvin_s_input(struct file *file, void *priv, unsigned int i)
538{
539 if (i > 0)
540 return -EINVAL;
541 return 0;
542}
543
544static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a)
545{
546 struct rvin_dev *vin = video_drvdata(file);
547 struct v4l2_subdev *sd = vin_to_source(vin);
548
549 return v4l2_subdev_call(sd, video, querystd, a);
550}
551
552static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a)
553{
554 struct rvin_dev *vin = video_drvdata(file);
555 int ret;
556
557 ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a);
558 if (ret < 0)
559 return ret;
560
561 vin->std = a;
562
563
564 return rvin_reset_format(vin);
565}
566
567static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a)
568{
569 struct rvin_dev *vin = video_drvdata(file);
570
571 if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap))
572 return -ENOIOCTLCMD;
573
574 *a = vin->std;
575
576 return 0;
577}
578
579static int rvin_subscribe_event(struct v4l2_fh *fh,
580 const struct v4l2_event_subscription *sub)
581{
582 switch (sub->type) {
583 case V4L2_EVENT_SOURCE_CHANGE:
584 return v4l2_event_subscribe(fh, sub, 4, NULL);
585 }
586 return v4l2_ctrl_subscribe_event(fh, sub);
587}
588
589static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
590 struct v4l2_enum_dv_timings *timings)
591{
592 struct rvin_dev *vin = video_drvdata(file);
593 struct v4l2_subdev *sd = vin_to_source(vin);
594 int ret;
595
596 if (timings->pad)
597 return -EINVAL;
598
599 timings->pad = vin->parallel->sink_pad;
600
601 ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
602
603 timings->pad = 0;
604
605 return ret;
606}
607
608static int rvin_s_dv_timings(struct file *file, void *priv_fh,
609 struct v4l2_dv_timings *timings)
610{
611 struct rvin_dev *vin = video_drvdata(file);
612 struct v4l2_subdev *sd = vin_to_source(vin);
613 int ret;
614
615 ret = v4l2_subdev_call(sd, video, s_dv_timings, timings);
616 if (ret)
617 return ret;
618
619
620 return rvin_reset_format(vin);
621}
622
623static int rvin_g_dv_timings(struct file *file, void *priv_fh,
624 struct v4l2_dv_timings *timings)
625{
626 struct rvin_dev *vin = video_drvdata(file);
627 struct v4l2_subdev *sd = vin_to_source(vin);
628
629 return v4l2_subdev_call(sd, video, g_dv_timings, timings);
630}
631
632static int rvin_query_dv_timings(struct file *file, void *priv_fh,
633 struct v4l2_dv_timings *timings)
634{
635 struct rvin_dev *vin = video_drvdata(file);
636 struct v4l2_subdev *sd = vin_to_source(vin);
637
638 return v4l2_subdev_call(sd, video, query_dv_timings, timings);
639}
640
641static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
642 struct v4l2_dv_timings_cap *cap)
643{
644 struct rvin_dev *vin = video_drvdata(file);
645 struct v4l2_subdev *sd = vin_to_source(vin);
646 int ret;
647
648 if (cap->pad)
649 return -EINVAL;
650
651 cap->pad = vin->parallel->sink_pad;
652
653 ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
654
655 cap->pad = 0;
656
657 return ret;
658}
659
660static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
661{
662 struct rvin_dev *vin = video_drvdata(file);
663 struct v4l2_subdev *sd = vin_to_source(vin);
664 int ret;
665
666 if (edid->pad)
667 return -EINVAL;
668
669 edid->pad = vin->parallel->sink_pad;
670
671 ret = v4l2_subdev_call(sd, pad, get_edid, edid);
672
673 edid->pad = 0;
674
675 return ret;
676}
677
678static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
679{
680 struct rvin_dev *vin = video_drvdata(file);
681 struct v4l2_subdev *sd = vin_to_source(vin);
682 int ret;
683
684 if (edid->pad)
685 return -EINVAL;
686
687 edid->pad = vin->parallel->sink_pad;
688
689 ret = v4l2_subdev_call(sd, pad, set_edid, edid);
690
691 edid->pad = 0;
692
693 return ret;
694}
695
696static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
697 .vidioc_querycap = rvin_querycap,
698 .vidioc_try_fmt_vid_cap = rvin_try_fmt_vid_cap,
699 .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap,
700 .vidioc_s_fmt_vid_cap = rvin_s_fmt_vid_cap,
701 .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
702
703 .vidioc_g_selection = rvin_g_selection,
704 .vidioc_s_selection = rvin_s_selection,
705
706 .vidioc_g_pixelaspect = rvin_g_pixelaspect,
707
708 .vidioc_enum_input = rvin_enum_input,
709 .vidioc_g_input = rvin_g_input,
710 .vidioc_s_input = rvin_s_input,
711
712 .vidioc_dv_timings_cap = rvin_dv_timings_cap,
713 .vidioc_enum_dv_timings = rvin_enum_dv_timings,
714 .vidioc_g_dv_timings = rvin_g_dv_timings,
715 .vidioc_s_dv_timings = rvin_s_dv_timings,
716 .vidioc_query_dv_timings = rvin_query_dv_timings,
717
718 .vidioc_g_edid = rvin_g_edid,
719 .vidioc_s_edid = rvin_s_edid,
720
721 .vidioc_querystd = rvin_querystd,
722 .vidioc_g_std = rvin_g_std,
723 .vidioc_s_std = rvin_s_std,
724
725 .vidioc_reqbufs = vb2_ioctl_reqbufs,
726 .vidioc_create_bufs = vb2_ioctl_create_bufs,
727 .vidioc_querybuf = vb2_ioctl_querybuf,
728 .vidioc_qbuf = vb2_ioctl_qbuf,
729 .vidioc_dqbuf = vb2_ioctl_dqbuf,
730 .vidioc_expbuf = vb2_ioctl_expbuf,
731 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
732 .vidioc_streamon = vb2_ioctl_streamon,
733 .vidioc_streamoff = vb2_ioctl_streamoff,
734
735 .vidioc_log_status = v4l2_ctrl_log_status,
736 .vidioc_subscribe_event = rvin_subscribe_event,
737 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
738};
739
740
741
742
743
744static void rvin_mc_try_format(struct rvin_dev *vin,
745 struct v4l2_pix_format *pix)
746{
747
748
749
750
751
752
753 pix->colorspace = RVIN_DEFAULT_COLORSPACE;
754 pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
755 pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
756 pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
757 pix->ycbcr_enc);
758
759 rvin_format_align(vin, pix);
760}
761
762static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
763 struct v4l2_format *f)
764{
765 struct rvin_dev *vin = video_drvdata(file);
766
767 rvin_mc_try_format(vin, &f->fmt.pix);
768
769 return 0;
770}
771
772static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
773 struct v4l2_format *f)
774{
775 struct rvin_dev *vin = video_drvdata(file);
776
777 if (vb2_is_busy(&vin->queue))
778 return -EBUSY;
779
780 rvin_mc_try_format(vin, &f->fmt.pix);
781
782 vin->format = f->fmt.pix;
783
784 vin->crop.top = 0;
785 vin->crop.left = 0;
786 vin->crop.width = vin->format.width;
787 vin->crop.height = vin->format.height;
788 vin->compose = vin->crop;
789
790 return 0;
791}
792
793static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
794 .vidioc_querycap = rvin_querycap,
795 .vidioc_try_fmt_vid_cap = rvin_mc_try_fmt_vid_cap,
796 .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap,
797 .vidioc_s_fmt_vid_cap = rvin_mc_s_fmt_vid_cap,
798 .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
799
800 .vidioc_reqbufs = vb2_ioctl_reqbufs,
801 .vidioc_create_bufs = vb2_ioctl_create_bufs,
802 .vidioc_querybuf = vb2_ioctl_querybuf,
803 .vidioc_qbuf = vb2_ioctl_qbuf,
804 .vidioc_dqbuf = vb2_ioctl_dqbuf,
805 .vidioc_expbuf = vb2_ioctl_expbuf,
806 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
807 .vidioc_streamon = vb2_ioctl_streamon,
808 .vidioc_streamoff = vb2_ioctl_streamoff,
809
810 .vidioc_log_status = v4l2_ctrl_log_status,
811 .vidioc_subscribe_event = rvin_subscribe_event,
812 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
813};
814
815
816
817
818
819static int rvin_power_parallel(struct rvin_dev *vin, bool on)
820{
821 struct v4l2_subdev *sd = vin_to_source(vin);
822 int power = on ? 1 : 0;
823 int ret;
824
825 ret = v4l2_subdev_call(sd, core, s_power, power);
826 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
827 return ret;
828
829 return 0;
830}
831
832static int rvin_open(struct file *file)
833{
834 struct rvin_dev *vin = video_drvdata(file);
835 int ret;
836
837 ret = pm_runtime_get_sync(vin->dev);
838 if (ret < 0)
839 return ret;
840
841 ret = mutex_lock_interruptible(&vin->lock);
842 if (ret)
843 goto err_pm;
844
845 file->private_data = vin;
846
847 ret = v4l2_fh_open(file);
848 if (ret)
849 goto err_unlock;
850
851 if (vin->info->use_mc)
852 ret = v4l2_pipeline_pm_get(&vin->vdev.entity);
853 else if (v4l2_fh_is_singular_file(file))
854 ret = rvin_power_parallel(vin, true);
855
856 if (ret < 0)
857 goto err_open;
858
859 ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler);
860 if (ret)
861 goto err_power;
862
863 mutex_unlock(&vin->lock);
864
865 return 0;
866err_power:
867 if (vin->info->use_mc)
868 v4l2_pipeline_pm_put(&vin->vdev.entity);
869 else if (v4l2_fh_is_singular_file(file))
870 rvin_power_parallel(vin, false);
871err_open:
872 v4l2_fh_release(file);
873err_unlock:
874 mutex_unlock(&vin->lock);
875err_pm:
876 pm_runtime_put(vin->dev);
877
878 return ret;
879}
880
881static int rvin_release(struct file *file)
882{
883 struct rvin_dev *vin = video_drvdata(file);
884 bool fh_singular;
885 int ret;
886
887 mutex_lock(&vin->lock);
888
889
890 fh_singular = v4l2_fh_is_singular_file(file);
891
892
893 ret = _vb2_fop_release(file, NULL);
894
895 if (vin->info->use_mc) {
896 v4l2_pipeline_pm_put(&vin->vdev.entity);
897 } else {
898 if (fh_singular)
899 rvin_power_parallel(vin, false);
900 }
901
902 mutex_unlock(&vin->lock);
903
904 pm_runtime_put(vin->dev);
905
906 return ret;
907}
908
909static const struct v4l2_file_operations rvin_fops = {
910 .owner = THIS_MODULE,
911 .unlocked_ioctl = video_ioctl2,
912 .open = rvin_open,
913 .release = rvin_release,
914 .poll = vb2_fop_poll,
915 .mmap = vb2_fop_mmap,
916 .read = vb2_fop_read,
917};
918
919void rvin_v4l2_unregister(struct rvin_dev *vin)
920{
921 if (!video_is_registered(&vin->vdev))
922 return;
923
924 v4l2_info(&vin->v4l2_dev, "Removing %s\n",
925 video_device_node_name(&vin->vdev));
926
927
928 video_unregister_device(&vin->vdev);
929}
930
931static void rvin_notify(struct v4l2_subdev *sd,
932 unsigned int notification, void *arg)
933{
934 struct rvin_dev *vin =
935 container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev);
936
937 switch (notification) {
938 case V4L2_DEVICE_NOTIFY_EVENT:
939 v4l2_event_queue(&vin->vdev, arg);
940 break;
941 default:
942 break;
943 }
944}
945
946int rvin_v4l2_register(struct rvin_dev *vin)
947{
948 struct video_device *vdev = &vin->vdev;
949 int ret;
950
951 vin->v4l2_dev.notify = rvin_notify;
952
953
954 vdev->v4l2_dev = &vin->v4l2_dev;
955 vdev->queue = &vin->queue;
956 snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id);
957 vdev->release = video_device_release_empty;
958 vdev->lock = &vin->lock;
959 vdev->fops = &rvin_fops;
960 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
961 V4L2_CAP_READWRITE;
962
963
964 vin->format.pixelformat = RVIN_DEFAULT_FORMAT;
965 vin->format.width = RVIN_DEFAULT_WIDTH;
966 vin->format.height = RVIN_DEFAULT_HEIGHT;
967 vin->format.field = RVIN_DEFAULT_FIELD;
968 vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
969
970 if (vin->info->use_mc) {
971 vdev->device_caps |= V4L2_CAP_IO_MC;
972 vdev->ioctl_ops = &rvin_mc_ioctl_ops;
973 } else {
974 vdev->ioctl_ops = &rvin_ioctl_ops;
975 rvin_reset_format(vin);
976 }
977
978 rvin_format_align(vin, &vin->format);
979
980 ret = video_register_device(&vin->vdev, VFL_TYPE_VIDEO, -1);
981 if (ret) {
982 vin_err(vin, "Failed to register video device\n");
983 return ret;
984 }
985
986 video_set_drvdata(&vin->vdev, vin);
987
988 v4l2_info(&vin->v4l2_dev, "Device registered as %s\n",
989 video_device_node_name(&vin->vdev));
990
991 return ret;
992}
993