1 // SPDX-License-Identifier: GPL-2.0-only
3 * TI Camera Access Layer (CAL) - Video Device
5 * Copyright (c) 2015-2020 Texas Instruments Inc.
8 * Benoit Parrot <bparrot@ti.com>
9 * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
12 #include <linux/delay.h>
13 #include <linux/ioctl.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/videodev2.h>
17 #include <media/media-device.h>
18 #include <media/v4l2-common.h>
19 #include <media/v4l2-ctrls.h>
20 #include <media/v4l2-device.h>
21 #include <media/v4l2-event.h>
22 #include <media/v4l2-fh.h>
23 #include <media/v4l2-ioctl.h>
24 #include <media/videobuf2-core.h>
25 #include <media/videobuf2-dma-contig.h>
29 /* ------------------------------------------------------------------
31 * ------------------------------------------------------------------
34 static const struct cal_fmt cal_formats
[] = {
36 .fourcc
= V4L2_PIX_FMT_YUYV
,
37 .code
= MEDIA_BUS_FMT_YUYV8_2X8
,
40 .fourcc
= V4L2_PIX_FMT_UYVY
,
41 .code
= MEDIA_BUS_FMT_UYVY8_2X8
,
44 .fourcc
= V4L2_PIX_FMT_YVYU
,
45 .code
= MEDIA_BUS_FMT_YVYU8_2X8
,
48 .fourcc
= V4L2_PIX_FMT_VYUY
,
49 .code
= MEDIA_BUS_FMT_VYUY8_2X8
,
52 .fourcc
= V4L2_PIX_FMT_RGB565
, /* gggbbbbb rrrrrggg */
53 .code
= MEDIA_BUS_FMT_RGB565_2X8_LE
,
56 .fourcc
= V4L2_PIX_FMT_RGB565X
, /* rrrrrggg gggbbbbb */
57 .code
= MEDIA_BUS_FMT_RGB565_2X8_BE
,
60 .fourcc
= V4L2_PIX_FMT_RGB555
, /* gggbbbbb arrrrrgg */
61 .code
= MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE
,
64 .fourcc
= V4L2_PIX_FMT_RGB555X
, /* arrrrrgg gggbbbbb */
65 .code
= MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE
,
68 .fourcc
= V4L2_PIX_FMT_RGB24
, /* rgb */
69 .code
= MEDIA_BUS_FMT_RGB888_2X12_LE
,
72 .fourcc
= V4L2_PIX_FMT_BGR24
, /* bgr */
73 .code
= MEDIA_BUS_FMT_RGB888_2X12_BE
,
76 .fourcc
= V4L2_PIX_FMT_RGB32
, /* argb */
77 .code
= MEDIA_BUS_FMT_ARGB8888_1X32
,
80 .fourcc
= V4L2_PIX_FMT_SBGGR8
,
81 .code
= MEDIA_BUS_FMT_SBGGR8_1X8
,
84 .fourcc
= V4L2_PIX_FMT_SGBRG8
,
85 .code
= MEDIA_BUS_FMT_SGBRG8_1X8
,
88 .fourcc
= V4L2_PIX_FMT_SGRBG8
,
89 .code
= MEDIA_BUS_FMT_SGRBG8_1X8
,
92 .fourcc
= V4L2_PIX_FMT_SRGGB8
,
93 .code
= MEDIA_BUS_FMT_SRGGB8_1X8
,
96 .fourcc
= V4L2_PIX_FMT_SBGGR10
,
97 .code
= MEDIA_BUS_FMT_SBGGR10_1X10
,
100 .fourcc
= V4L2_PIX_FMT_SGBRG10
,
101 .code
= MEDIA_BUS_FMT_SGBRG10_1X10
,
104 .fourcc
= V4L2_PIX_FMT_SGRBG10
,
105 .code
= MEDIA_BUS_FMT_SGRBG10_1X10
,
108 .fourcc
= V4L2_PIX_FMT_SRGGB10
,
109 .code
= MEDIA_BUS_FMT_SRGGB10_1X10
,
112 .fourcc
= V4L2_PIX_FMT_SBGGR12
,
113 .code
= MEDIA_BUS_FMT_SBGGR12_1X12
,
116 .fourcc
= V4L2_PIX_FMT_SGBRG12
,
117 .code
= MEDIA_BUS_FMT_SGBRG12_1X12
,
120 .fourcc
= V4L2_PIX_FMT_SGRBG12
,
121 .code
= MEDIA_BUS_FMT_SGRBG12_1X12
,
124 .fourcc
= V4L2_PIX_FMT_SRGGB12
,
125 .code
= MEDIA_BUS_FMT_SRGGB12_1X12
,
130 /* Print Four-character-code (FOURCC) */
131 static char *fourcc_to_str(u32 fmt
)
135 code
[0] = (unsigned char)(fmt
& 0xff);
136 code
[1] = (unsigned char)((fmt
>> 8) & 0xff);
137 code
[2] = (unsigned char)((fmt
>> 16) & 0xff);
138 code
[3] = (unsigned char)((fmt
>> 24) & 0xff);
144 /* ------------------------------------------------------------------
146 * ------------------------------------------------------------------
149 static const struct cal_fmt
*find_format_by_pix(struct cal_ctx
*ctx
,
152 const struct cal_fmt
*fmt
;
155 for (k
= 0; k
< ctx
->num_active_fmt
; k
++) {
156 fmt
= ctx
->active_fmt
[k
];
157 if (fmt
->fourcc
== pixelformat
)
164 static const struct cal_fmt
*find_format_by_code(struct cal_ctx
*ctx
,
167 const struct cal_fmt
*fmt
;
170 for (k
= 0; k
< ctx
->num_active_fmt
; k
++) {
171 fmt
= ctx
->active_fmt
[k
];
172 if (fmt
->code
== code
)
179 static int cal_querycap(struct file
*file
, void *priv
,
180 struct v4l2_capability
*cap
)
182 struct cal_ctx
*ctx
= video_drvdata(file
);
184 strscpy(cap
->driver
, CAL_MODULE_NAME
, sizeof(cap
->driver
));
185 strscpy(cap
->card
, CAL_MODULE_NAME
, sizeof(cap
->card
));
187 snprintf(cap
->bus_info
, sizeof(cap
->bus_info
),
188 "platform:%s", dev_name(ctx
->cal
->dev
));
192 static int cal_enum_fmt_vid_cap(struct file
*file
, void *priv
,
193 struct v4l2_fmtdesc
*f
)
195 struct cal_ctx
*ctx
= video_drvdata(file
);
196 const struct cal_fmt
*fmt
;
198 if (f
->index
>= ctx
->num_active_fmt
)
201 fmt
= ctx
->active_fmt
[f
->index
];
203 f
->pixelformat
= fmt
->fourcc
;
204 f
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
208 static int __subdev_get_format(struct cal_ctx
*ctx
,
209 struct v4l2_mbus_framefmt
*fmt
)
211 struct v4l2_subdev_format sd_fmt
;
212 struct v4l2_mbus_framefmt
*mbus_fmt
= &sd_fmt
.format
;
215 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
218 ret
= v4l2_subdev_call(ctx
->phy
->sensor
, pad
, get_fmt
, NULL
, &sd_fmt
);
224 ctx_dbg(1, ctx
, "%s %dx%d code:%04X\n", __func__
,
225 fmt
->width
, fmt
->height
, fmt
->code
);
230 static int __subdev_set_format(struct cal_ctx
*ctx
,
231 struct v4l2_mbus_framefmt
*fmt
)
233 struct v4l2_subdev_format sd_fmt
;
234 struct v4l2_mbus_framefmt
*mbus_fmt
= &sd_fmt
.format
;
237 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
241 ret
= v4l2_subdev_call(ctx
->phy
->sensor
, pad
, set_fmt
, NULL
, &sd_fmt
);
245 ctx_dbg(1, ctx
, "%s %dx%d code:%04X\n", __func__
,
246 fmt
->width
, fmt
->height
, fmt
->code
);
251 static int cal_calc_format_size(struct cal_ctx
*ctx
,
252 const struct cal_fmt
*fmt
,
253 struct v4l2_format
*f
)
258 ctx_dbg(3, ctx
, "No cal_fmt provided!\n");
263 * Maximum width is bound by the DMA max width in bytes.
264 * We need to recalculate the actual maxi width depending on the
265 * number of bytes per pixels required.
267 max_width
= MAX_WIDTH_BYTES
/ (ALIGN(fmt
->bpp
, 8) >> 3);
268 v4l_bound_align_image(&f
->fmt
.pix
.width
, 48, max_width
, 2,
269 &f
->fmt
.pix
.height
, 32, MAX_HEIGHT_LINES
, 0, 0);
271 bpl
= (f
->fmt
.pix
.width
* ALIGN(fmt
->bpp
, 8)) >> 3;
272 f
->fmt
.pix
.bytesperline
= ALIGN(bpl
, 16);
274 f
->fmt
.pix
.sizeimage
= f
->fmt
.pix
.height
*
275 f
->fmt
.pix
.bytesperline
;
277 ctx_dbg(3, ctx
, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n",
278 __func__
, fourcc_to_str(f
->fmt
.pix
.pixelformat
),
279 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
,
280 f
->fmt
.pix
.bytesperline
, f
->fmt
.pix
.sizeimage
);
285 static int cal_g_fmt_vid_cap(struct file
*file
, void *priv
,
286 struct v4l2_format
*f
)
288 struct cal_ctx
*ctx
= video_drvdata(file
);
295 static int cal_try_fmt_vid_cap(struct file
*file
, void *priv
,
296 struct v4l2_format
*f
)
298 struct cal_ctx
*ctx
= video_drvdata(file
);
299 const struct cal_fmt
*fmt
;
300 struct v4l2_subdev_frame_size_enum fse
;
303 fmt
= find_format_by_pix(ctx
, f
->fmt
.pix
.pixelformat
);
305 ctx_dbg(3, ctx
, "Fourcc format (0x%08x) not found.\n",
306 f
->fmt
.pix
.pixelformat
);
308 /* Just get the first one enumerated */
309 fmt
= ctx
->active_fmt
[0];
310 f
->fmt
.pix
.pixelformat
= fmt
->fourcc
;
313 f
->fmt
.pix
.field
= ctx
->v_fmt
.fmt
.pix
.field
;
315 /* check for/find a valid width/height */
319 fse
.code
= fmt
->code
;
320 fse
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
321 for (fse
.index
= 0; ; fse
.index
++) {
322 ret
= v4l2_subdev_call(ctx
->phy
->sensor
, pad
, enum_frame_size
,
327 if ((f
->fmt
.pix
.width
== fse
.max_width
) &&
328 (f
->fmt
.pix
.height
== fse
.max_height
)) {
331 } else if ((f
->fmt
.pix
.width
>= fse
.min_width
) &&
332 (f
->fmt
.pix
.width
<= fse
.max_width
) &&
333 (f
->fmt
.pix
.height
>= fse
.min_height
) &&
334 (f
->fmt
.pix
.height
<= fse
.max_height
)) {
341 /* use existing values as default */
342 f
->fmt
.pix
.width
= ctx
->v_fmt
.fmt
.pix
.width
;
343 f
->fmt
.pix
.height
= ctx
->v_fmt
.fmt
.pix
.height
;
347 * Use current colorspace for now, it will get
348 * updated properly during s_fmt
350 f
->fmt
.pix
.colorspace
= ctx
->v_fmt
.fmt
.pix
.colorspace
;
351 return cal_calc_format_size(ctx
, fmt
, f
);
354 static int cal_s_fmt_vid_cap(struct file
*file
, void *priv
,
355 struct v4l2_format
*f
)
357 struct cal_ctx
*ctx
= video_drvdata(file
);
358 struct vb2_queue
*q
= &ctx
->vb_vidq
;
359 const struct cal_fmt
*fmt
;
360 struct v4l2_mbus_framefmt mbus_fmt
;
363 if (vb2_is_busy(q
)) {
364 ctx_dbg(3, ctx
, "%s device busy\n", __func__
);
368 ret
= cal_try_fmt_vid_cap(file
, priv
, f
);
372 fmt
= find_format_by_pix(ctx
, f
->fmt
.pix
.pixelformat
);
374 v4l2_fill_mbus_format(&mbus_fmt
, &f
->fmt
.pix
, fmt
->code
);
376 ret
= __subdev_set_format(ctx
, &mbus_fmt
);
380 /* Just double check nothing has gone wrong */
381 if (mbus_fmt
.code
!= fmt
->code
) {
383 "%s subdev changed format on us, this should not happen\n",
388 v4l2_fill_pix_format(&ctx
->v_fmt
.fmt
.pix
, &mbus_fmt
);
389 ctx
->v_fmt
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
390 ctx
->v_fmt
.fmt
.pix
.pixelformat
= fmt
->fourcc
;
391 cal_calc_format_size(ctx
, fmt
, &ctx
->v_fmt
);
393 ctx
->m_fmt
= mbus_fmt
;
399 static int cal_enum_framesizes(struct file
*file
, void *fh
,
400 struct v4l2_frmsizeenum
*fsize
)
402 struct cal_ctx
*ctx
= video_drvdata(file
);
403 const struct cal_fmt
*fmt
;
404 struct v4l2_subdev_frame_size_enum fse
;
407 /* check for valid format */
408 fmt
= find_format_by_pix(ctx
, fsize
->pixel_format
);
410 ctx_dbg(3, ctx
, "Invalid pixel code: %x\n",
411 fsize
->pixel_format
);
415 fse
.index
= fsize
->index
;
417 fse
.code
= fmt
->code
;
418 fse
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
420 ret
= v4l2_subdev_call(ctx
->phy
->sensor
, pad
, enum_frame_size
, NULL
,
425 ctx_dbg(1, ctx
, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
426 __func__
, fse
.index
, fse
.code
, fse
.min_width
, fse
.max_width
,
427 fse
.min_height
, fse
.max_height
);
429 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
430 fsize
->discrete
.width
= fse
.max_width
;
431 fsize
->discrete
.height
= fse
.max_height
;
436 static int cal_enum_input(struct file
*file
, void *priv
,
437 struct v4l2_input
*inp
)
442 inp
->type
= V4L2_INPUT_TYPE_CAMERA
;
443 sprintf(inp
->name
, "Camera %u", inp
->index
);
447 static int cal_g_input(struct file
*file
, void *priv
, unsigned int *i
)
453 static int cal_s_input(struct file
*file
, void *priv
, unsigned int i
)
455 return i
> 0 ? -EINVAL
: 0;
458 /* timeperframe is arbitrary and continuous */
459 static int cal_enum_frameintervals(struct file
*file
, void *priv
,
460 struct v4l2_frmivalenum
*fival
)
462 struct cal_ctx
*ctx
= video_drvdata(file
);
463 const struct cal_fmt
*fmt
;
464 struct v4l2_subdev_frame_interval_enum fie
= {
465 .index
= fival
->index
,
466 .width
= fival
->width
,
467 .height
= fival
->height
,
468 .which
= V4L2_SUBDEV_FORMAT_ACTIVE
,
472 fmt
= find_format_by_pix(ctx
, fival
->pixel_format
);
476 fie
.code
= fmt
->code
;
477 ret
= v4l2_subdev_call(ctx
->phy
->sensor
, pad
, enum_frame_interval
,
481 fival
->type
= V4L2_FRMIVAL_TYPE_DISCRETE
;
482 fival
->discrete
= fie
.interval
;
487 static const struct v4l2_file_operations cal_fops
= {
488 .owner
= THIS_MODULE
,
489 .open
= v4l2_fh_open
,
490 .release
= vb2_fop_release
,
491 .read
= vb2_fop_read
,
492 .poll
= vb2_fop_poll
,
493 .unlocked_ioctl
= video_ioctl2
, /* V4L2 ioctl handler */
494 .mmap
= vb2_fop_mmap
,
497 static const struct v4l2_ioctl_ops cal_ioctl_ops
= {
498 .vidioc_querycap
= cal_querycap
,
499 .vidioc_enum_fmt_vid_cap
= cal_enum_fmt_vid_cap
,
500 .vidioc_g_fmt_vid_cap
= cal_g_fmt_vid_cap
,
501 .vidioc_try_fmt_vid_cap
= cal_try_fmt_vid_cap
,
502 .vidioc_s_fmt_vid_cap
= cal_s_fmt_vid_cap
,
503 .vidioc_enum_framesizes
= cal_enum_framesizes
,
504 .vidioc_reqbufs
= vb2_ioctl_reqbufs
,
505 .vidioc_create_bufs
= vb2_ioctl_create_bufs
,
506 .vidioc_prepare_buf
= vb2_ioctl_prepare_buf
,
507 .vidioc_querybuf
= vb2_ioctl_querybuf
,
508 .vidioc_qbuf
= vb2_ioctl_qbuf
,
509 .vidioc_dqbuf
= vb2_ioctl_dqbuf
,
510 .vidioc_expbuf
= vb2_ioctl_expbuf
,
511 .vidioc_enum_input
= cal_enum_input
,
512 .vidioc_g_input
= cal_g_input
,
513 .vidioc_s_input
= cal_s_input
,
514 .vidioc_enum_frameintervals
= cal_enum_frameintervals
,
515 .vidioc_streamon
= vb2_ioctl_streamon
,
516 .vidioc_streamoff
= vb2_ioctl_streamoff
,
517 .vidioc_log_status
= v4l2_ctrl_log_status
,
518 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
519 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
522 /* ------------------------------------------------------------------
523 * videobuf2 Operations
524 * ------------------------------------------------------------------
527 static int cal_queue_setup(struct vb2_queue
*vq
,
528 unsigned int *nbuffers
, unsigned int *nplanes
,
529 unsigned int sizes
[], struct device
*alloc_devs
[])
531 struct cal_ctx
*ctx
= vb2_get_drv_priv(vq
);
532 unsigned int size
= ctx
->v_fmt
.fmt
.pix
.sizeimage
;
534 if (vq
->num_buffers
+ *nbuffers
< 3)
535 *nbuffers
= 3 - vq
->num_buffers
;
546 ctx_dbg(3, ctx
, "nbuffers=%d, size=%d\n", *nbuffers
, sizes
[0]);
551 static int cal_buffer_prepare(struct vb2_buffer
*vb
)
553 struct cal_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
554 struct cal_buffer
*buf
= container_of(vb
, struct cal_buffer
,
558 if (WARN_ON(!ctx
->fmt
))
561 size
= ctx
->v_fmt
.fmt
.pix
.sizeimage
;
562 if (vb2_plane_size(vb
, 0) < size
) {
564 "data will not fit into plane (%lu < %lu)\n",
565 vb2_plane_size(vb
, 0), size
);
569 vb2_set_plane_payload(&buf
->vb
.vb2_buf
, 0, size
);
573 static void cal_buffer_queue(struct vb2_buffer
*vb
)
575 struct cal_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
576 struct cal_buffer
*buf
= container_of(vb
, struct cal_buffer
,
578 struct cal_dmaqueue
*vidq
= &ctx
->vidq
;
581 /* recheck locking */
582 spin_lock_irqsave(&ctx
->slock
, flags
);
583 list_add_tail(&buf
->list
, &vidq
->active
);
584 spin_unlock_irqrestore(&ctx
->slock
, flags
);
587 static int cal_start_streaming(struct vb2_queue
*vq
, unsigned int count
)
589 struct cal_ctx
*ctx
= vb2_get_drv_priv(vq
);
590 struct cal_dmaqueue
*dma_q
= &ctx
->vidq
;
591 struct cal_buffer
*buf
, *tmp
;
596 spin_lock_irqsave(&ctx
->slock
, flags
);
597 if (list_empty(&dma_q
->active
)) {
598 spin_unlock_irqrestore(&ctx
->slock
, flags
);
599 ctx_dbg(3, ctx
, "buffer queue is empty\n");
603 buf
= list_entry(dma_q
->active
.next
, struct cal_buffer
, list
);
606 list_del(&buf
->list
);
607 spin_unlock_irqrestore(&ctx
->slock
, flags
);
609 addr
= vb2_dma_contig_plane_dma_addr(&ctx
->cur_frm
->vb
.vb2_buf
, 0);
612 pm_runtime_get_sync(ctx
->cal
->dev
);
614 cal_ctx_csi2_config(ctx
);
615 cal_ctx_pix_proc_config(ctx
);
616 cal_ctx_wr_dma_config(ctx
, ctx
->v_fmt
.fmt
.pix
.bytesperline
,
617 ctx
->v_fmt
.fmt
.pix
.height
);
619 cal_camerarx_enable_irqs(ctx
->phy
);
621 ret
= cal_camerarx_start(ctx
->phy
, ctx
->fmt
);
625 cal_ctx_wr_dma_addr(ctx
, addr
);
626 cal_camerarx_ppi_enable(ctx
->phy
);
629 cal_quickdump_regs(ctx
->cal
);
634 spin_lock_irqsave(&ctx
->slock
, flags
);
635 vb2_buffer_done(&ctx
->cur_frm
->vb
.vb2_buf
, VB2_BUF_STATE_QUEUED
);
637 ctx
->next_frm
= NULL
;
638 list_for_each_entry_safe(buf
, tmp
, &dma_q
->active
, list
) {
639 list_del(&buf
->list
);
640 vb2_buffer_done(&buf
->vb
.vb2_buf
, VB2_BUF_STATE_QUEUED
);
642 spin_unlock_irqrestore(&ctx
->slock
, flags
);
646 static void cal_stop_streaming(struct vb2_queue
*vq
)
648 struct cal_ctx
*ctx
= vb2_get_drv_priv(vq
);
649 struct cal_dmaqueue
*dma_q
= &ctx
->vidq
;
650 struct cal_buffer
*buf
, *tmp
;
651 unsigned long timeout
;
655 cal_camerarx_ppi_disable(ctx
->phy
);
657 /* wait for stream and dma to finish */
659 timeout
= jiffies
+ msecs_to_jiffies(500);
660 while (dma_act
&& time_before(jiffies
, timeout
)) {
663 spin_lock_irqsave(&ctx
->slock
, flags
);
664 dma_act
= ctx
->dma_act
;
665 spin_unlock_irqrestore(&ctx
->slock
, flags
);
669 ctx_err(ctx
, "failed to disable dma cleanly\n");
671 cal_camerarx_disable_irqs(ctx
->phy
);
672 cal_camerarx_stop(ctx
->phy
);
674 /* Release all active buffers */
675 spin_lock_irqsave(&ctx
->slock
, flags
);
676 list_for_each_entry_safe(buf
, tmp
, &dma_q
->active
, list
) {
677 list_del(&buf
->list
);
678 vb2_buffer_done(&buf
->vb
.vb2_buf
, VB2_BUF_STATE_ERROR
);
681 if (ctx
->cur_frm
== ctx
->next_frm
) {
682 vb2_buffer_done(&ctx
->cur_frm
->vb
.vb2_buf
, VB2_BUF_STATE_ERROR
);
684 vb2_buffer_done(&ctx
->cur_frm
->vb
.vb2_buf
, VB2_BUF_STATE_ERROR
);
685 vb2_buffer_done(&ctx
->next_frm
->vb
.vb2_buf
,
686 VB2_BUF_STATE_ERROR
);
689 ctx
->next_frm
= NULL
;
690 spin_unlock_irqrestore(&ctx
->slock
, flags
);
692 pm_runtime_put_sync(ctx
->cal
->dev
);
695 static const struct vb2_ops cal_video_qops
= {
696 .queue_setup
= cal_queue_setup
,
697 .buf_prepare
= cal_buffer_prepare
,
698 .buf_queue
= cal_buffer_queue
,
699 .start_streaming
= cal_start_streaming
,
700 .stop_streaming
= cal_stop_streaming
,
701 .wait_prepare
= vb2_ops_wait_prepare
,
702 .wait_finish
= vb2_ops_wait_finish
,
705 /* ------------------------------------------------------------------
706 * V4L2 Initialization and Registration
707 * ------------------------------------------------------------------
710 static const struct video_device cal_videodev
= {
711 .name
= CAL_MODULE_NAME
,
713 .ioctl_ops
= &cal_ioctl_ops
,
715 .release
= video_device_release_empty
,
716 .device_caps
= V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
|
720 static int cal_ctx_v4l2_init_formats(struct cal_ctx
*ctx
)
722 struct v4l2_subdev_mbus_code_enum mbus_code
;
723 struct v4l2_mbus_framefmt mbus_fmt
;
724 const struct cal_fmt
*fmt
;
725 unsigned int i
, j
, k
;
728 /* Enumerate sub device formats and enable all matching local formats */
729 ctx
->active_fmt
= devm_kcalloc(ctx
->cal
->dev
, ARRAY_SIZE(cal_formats
),
730 sizeof(*ctx
->active_fmt
), GFP_KERNEL
);
731 ctx
->num_active_fmt
= 0;
733 for (j
= 0, i
= 0; ret
!= -EINVAL
; ++j
) {
735 memset(&mbus_code
, 0, sizeof(mbus_code
));
737 mbus_code
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
738 ret
= v4l2_subdev_call(ctx
->phy
->sensor
, pad
, enum_mbus_code
,
744 "subdev %s: code: %04x idx: %u\n",
745 ctx
->phy
->sensor
->name
, mbus_code
.code
, j
);
747 for (k
= 0; k
< ARRAY_SIZE(cal_formats
); k
++) {
748 const struct cal_fmt
*fmt
= &cal_formats
[k
];
750 if (mbus_code
.code
== fmt
->code
) {
751 ctx
->active_fmt
[i
] = fmt
;
753 "matched fourcc: %s: code: %04x idx: %u\n",
754 fourcc_to_str(fmt
->fourcc
),
756 ctx
->num_active_fmt
= ++i
;
762 ctx_err(ctx
, "No suitable format reported by subdev %s\n",
763 ctx
->phy
->sensor
->name
);
767 ret
= __subdev_get_format(ctx
, &mbus_fmt
);
771 fmt
= find_format_by_code(ctx
, mbus_fmt
.code
);
773 ctx_dbg(3, ctx
, "mbus code format (0x%08x) not found.\n",
778 /* Save current subdev format */
779 v4l2_fill_pix_format(&ctx
->v_fmt
.fmt
.pix
, &mbus_fmt
);
780 ctx
->v_fmt
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
781 ctx
->v_fmt
.fmt
.pix
.pixelformat
= fmt
->fourcc
;
782 cal_calc_format_size(ctx
, fmt
, &ctx
->v_fmt
);
784 ctx
->m_fmt
= mbus_fmt
;
789 int cal_ctx_v4l2_register(struct cal_ctx
*ctx
)
791 struct v4l2_ctrl_handler
*hdl
= &ctx
->ctrl_handler
;
792 struct video_device
*vfd
= &ctx
->vdev
;
795 ret
= cal_ctx_v4l2_init_formats(ctx
);
799 ret
= v4l2_ctrl_add_handler(hdl
, ctx
->phy
->sensor
->ctrl_handler
, NULL
,
802 ctx_err(ctx
, "Failed to add sensor ctrl handler\n");
806 ret
= video_register_device(vfd
, VFL_TYPE_VIDEO
, cal_video_nr
);
808 ctx_err(ctx
, "Failed to register video device\n");
812 ctx_info(ctx
, "V4L2 device registered as %s\n",
813 video_device_node_name(vfd
));
818 void cal_ctx_v4l2_unregister(struct cal_ctx
*ctx
)
820 ctx_dbg(1, ctx
, "unregistering %s\n",
821 video_device_node_name(&ctx
->vdev
));
823 video_unregister_device(&ctx
->vdev
);
826 int cal_ctx_v4l2_init(struct cal_ctx
*ctx
)
828 struct v4l2_ctrl_handler
*hdl
= &ctx
->ctrl_handler
;
829 struct video_device
*vfd
= &ctx
->vdev
;
830 struct vb2_queue
*q
= &ctx
->vb_vidq
;
833 INIT_LIST_HEAD(&ctx
->vidq
.active
);
834 spin_lock_init(&ctx
->slock
);
835 mutex_init(&ctx
->mutex
);
837 /* Initialize the vb2 queue. */
838 q
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
839 q
->io_modes
= VB2_MMAP
| VB2_DMABUF
| VB2_READ
;
841 q
->buf_struct_size
= sizeof(struct cal_buffer
);
842 q
->ops
= &cal_video_qops
;
843 q
->mem_ops
= &vb2_dma_contig_memops
;
844 q
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
;
845 q
->lock
= &ctx
->mutex
;
846 q
->min_buffers_needed
= 3;
847 q
->dev
= ctx
->cal
->dev
;
849 ret
= vb2_queue_init(q
);
853 /* Initialize the video device and media entity. */
855 vfd
->v4l2_dev
= &ctx
->cal
->v4l2_dev
;
857 snprintf(vfd
->name
, sizeof(vfd
->name
), "CAL output %u", ctx
->index
);
858 vfd
->lock
= &ctx
->mutex
;
859 video_set_drvdata(vfd
, ctx
);
861 ctx
->pad
.flags
= MEDIA_PAD_FL_SINK
;
862 ret
= media_entity_pads_init(&vfd
->entity
, 1, &ctx
->pad
);
866 /* Initialize the control handler. */
867 ret
= v4l2_ctrl_handler_init(hdl
, 11);
869 ctx_err(ctx
, "Failed to init ctrl handler\n");
873 vfd
->ctrl_handler
= hdl
;
878 media_entity_cleanup(&vfd
->entity
);
882 void cal_ctx_v4l2_cleanup(struct cal_ctx
*ctx
)
884 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
885 media_entity_cleanup(&ctx
->vdev
.entity
);