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