Lines Matching +full:csi +full:- +full:2
1 // SPDX-License-Identifier: GPL-2.0
3 * V4L2 Capture CSI Subdev for Freescale i.MX6UL/L / i.MX7 SOC
25 #include <media/v4l2-device.h>
26 #include <media/v4l2-fwnode.h>
27 #include <media/v4l2-ioctl.h>
28 #include <media/v4l2-mc.h>
29 #include <media/v4l2-subdev.h>
30 #include <media/videobuf2-dma-contig.h>
34 #define IMX7_CSI_PADS_NUM 2
36 /* csi control reg 1 */
63 #define BIT_INV_PCLK BIT(2)
67 /* control reg 2 */
69 #define BIT_DMA_BURST_TYPE_RFF_INCR8 (2 << 30)
87 #define BIT_ZERO_PACK_EN BIT(2)
91 /* csi status reg */
111 /* csi image parameter reg */
115 /* csi control reg 18 */
128 #define BIT_MASK_OPTION_SECOND_FRAME (2 << 18)
134 #define BIT_DEINTERLACE_EN BIT(2)
139 #define CSI_MCLK_ENC 2
162 #define IMX7_CSI_VIDEO_NAME "imx-capture"
178 /* the in-memory FourCC pixel format */
182 * NOTE! codes pointer is NULL for in-memory-only formats.
246 struct imx7_csi_vb2_buffer *active_vb2_buf[2];
265 /* -----------------------------------------------------------------------------
269 static u32 imx7_csi_reg_read(struct imx7_csi *csi, unsigned int offset) in imx7_csi_reg_read() argument
271 return readl(csi->regbase + offset); in imx7_csi_reg_read()
274 static void imx7_csi_reg_write(struct imx7_csi *csi, unsigned int value, in imx7_csi_reg_write() argument
277 writel(value, csi->regbase + offset); in imx7_csi_reg_write()
280 static u32 imx7_csi_irq_clear(struct imx7_csi *csi) in imx7_csi_irq_clear() argument
284 isr = imx7_csi_reg_read(csi, CSI_CSISR); in imx7_csi_irq_clear()
285 imx7_csi_reg_write(csi, isr, CSI_CSISR); in imx7_csi_irq_clear()
290 static void imx7_csi_init_default(struct imx7_csi *csi) in imx7_csi_init_default() argument
292 imx7_csi_reg_write(csi, BIT_SOF_POL | BIT_REDGE | BIT_GCLK_MODE | in imx7_csi_init_default()
295 imx7_csi_reg_write(csi, 0, CSI_CSICR2); in imx7_csi_init_default()
296 imx7_csi_reg_write(csi, BIT_FRMCNT_RST, CSI_CSICR3); in imx7_csi_init_default()
298 imx7_csi_reg_write(csi, BIT_IMAGE_WIDTH(IMX7_CSI_DEF_PIX_WIDTH) | in imx7_csi_init_default()
302 imx7_csi_reg_write(csi, BIT_DMA_REFLASH_RFF, CSI_CSICR3); in imx7_csi_init_default()
305 static void imx7_csi_hw_enable_irq(struct imx7_csi *csi) in imx7_csi_hw_enable_irq() argument
307 u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); in imx7_csi_hw_enable_irq()
313 imx7_csi_reg_write(csi, cr1, CSI_CSICR1); in imx7_csi_hw_enable_irq()
316 static void imx7_csi_hw_disable_irq(struct imx7_csi *csi) in imx7_csi_hw_disable_irq() argument
318 u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); in imx7_csi_hw_disable_irq()
324 imx7_csi_reg_write(csi, cr1, CSI_CSICR1); in imx7_csi_hw_disable_irq()
327 static void imx7_csi_hw_enable(struct imx7_csi *csi) in imx7_csi_hw_enable() argument
329 u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18); in imx7_csi_hw_enable()
333 imx7_csi_reg_write(csi, cr, CSI_CSICR18); in imx7_csi_hw_enable()
336 static void imx7_csi_hw_disable(struct imx7_csi *csi) in imx7_csi_hw_disable() argument
338 u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18); in imx7_csi_hw_disable()
342 imx7_csi_reg_write(csi, cr, CSI_CSICR18); in imx7_csi_hw_disable()
345 static void imx7_csi_dma_reflash(struct imx7_csi *csi) in imx7_csi_dma_reflash() argument
349 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); in imx7_csi_dma_reflash()
351 imx7_csi_reg_write(csi, cr3, CSI_CSICR3); in imx7_csi_dma_reflash()
354 static void imx7_csi_rx_fifo_clear(struct imx7_csi *csi) in imx7_csi_rx_fifo_clear() argument
356 u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1) & ~BIT_FCC; in imx7_csi_rx_fifo_clear()
358 imx7_csi_reg_write(csi, cr1, CSI_CSICR1); in imx7_csi_rx_fifo_clear()
359 imx7_csi_reg_write(csi, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1); in imx7_csi_rx_fifo_clear()
360 imx7_csi_reg_write(csi, cr1 | BIT_FCC, CSI_CSICR1); in imx7_csi_rx_fifo_clear()
363 static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi) in imx7_csi_dmareq_rff_enable() argument
365 u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); in imx7_csi_dmareq_rff_enable()
370 cr3 |= BIT_RXFF_LEVEL(2); in imx7_csi_dmareq_rff_enable()
372 imx7_csi_reg_write(csi, cr3, CSI_CSICR3); in imx7_csi_dmareq_rff_enable()
375 static void imx7_csi_dmareq_rff_disable(struct imx7_csi *csi) in imx7_csi_dmareq_rff_disable() argument
377 u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); in imx7_csi_dmareq_rff_disable()
381 imx7_csi_reg_write(csi, cr3, CSI_CSICR3); in imx7_csi_dmareq_rff_disable()
384 static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t dma_addr, in imx7_csi_update_buf() argument
388 imx7_csi_reg_write(csi, dma_addr, CSI_CSIDMASA_FB2); in imx7_csi_update_buf()
390 imx7_csi_reg_write(csi, dma_addr, CSI_CSIDMASA_FB1); in imx7_csi_update_buf()
393 static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi);
395 static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi) in imx7_csi_setup_vb2_buf() argument
401 for (i = 0; i < 2; i++) { in imx7_csi_setup_vb2_buf()
404 buf = imx7_csi_video_next_buf(csi); in imx7_csi_setup_vb2_buf()
406 csi->active_vb2_buf[i] = buf; in imx7_csi_setup_vb2_buf()
407 vb2_buf = &buf->vbuf.vb2_buf; in imx7_csi_setup_vb2_buf()
410 csi->active_vb2_buf[i] = NULL; in imx7_csi_setup_vb2_buf()
411 dma_addr = csi->underrun_buf.dma_addr; in imx7_csi_setup_vb2_buf()
414 imx7_csi_update_buf(csi, dma_addr, i); in imx7_csi_setup_vb2_buf()
418 static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi, in imx7_csi_dma_unsetup_vb2_buf() argument
425 for (i = 0; i < 2; i++) { in imx7_csi_dma_unsetup_vb2_buf()
426 buf = csi->active_vb2_buf[i]; in imx7_csi_dma_unsetup_vb2_buf()
428 struct vb2_buffer *vb = &buf->vbuf.vb2_buf; in imx7_csi_dma_unsetup_vb2_buf()
430 vb->timestamp = ktime_get_ns(); in imx7_csi_dma_unsetup_vb2_buf()
432 csi->active_vb2_buf[i] = NULL; in imx7_csi_dma_unsetup_vb2_buf()
437 static void imx7_csi_free_dma_buf(struct imx7_csi *csi, in imx7_csi_free_dma_buf() argument
440 if (buf->virt) in imx7_csi_free_dma_buf()
441 dma_free_coherent(csi->dev, buf->len, buf->virt, buf->dma_addr); in imx7_csi_free_dma_buf()
443 buf->virt = NULL; in imx7_csi_free_dma_buf()
444 buf->dma_addr = 0; in imx7_csi_free_dma_buf()
447 static int imx7_csi_alloc_dma_buf(struct imx7_csi *csi, in imx7_csi_alloc_dma_buf() argument
450 imx7_csi_free_dma_buf(csi, buf); in imx7_csi_alloc_dma_buf()
452 buf->len = PAGE_ALIGN(size); in imx7_csi_alloc_dma_buf()
453 buf->virt = dma_alloc_coherent(csi->dev, buf->len, &buf->dma_addr, in imx7_csi_alloc_dma_buf()
455 if (!buf->virt) in imx7_csi_alloc_dma_buf()
456 return -ENOMEM; in imx7_csi_alloc_dma_buf()
461 static int imx7_csi_dma_setup(struct imx7_csi *csi) in imx7_csi_dma_setup() argument
465 ret = imx7_csi_alloc_dma_buf(csi, &csi->underrun_buf, in imx7_csi_dma_setup()
466 csi->vdev_fmt.sizeimage); in imx7_csi_dma_setup()
468 v4l2_warn(&csi->sd, "consider increasing the CMA area\n"); in imx7_csi_dma_setup()
472 csi->frame_sequence = 0; in imx7_csi_dma_setup()
473 csi->last_eof = false; in imx7_csi_dma_setup()
474 init_completion(&csi->last_eof_completion); in imx7_csi_dma_setup()
476 imx7_csi_setup_vb2_buf(csi); in imx7_csi_dma_setup()
481 static void imx7_csi_dma_cleanup(struct imx7_csi *csi, in imx7_csi_dma_cleanup() argument
484 imx7_csi_dma_unsetup_vb2_buf(csi, return_status); in imx7_csi_dma_cleanup()
485 imx7_csi_free_dma_buf(csi, &csi->underrun_buf); in imx7_csi_dma_cleanup()
488 static void imx7_csi_dma_stop(struct imx7_csi *csi) in imx7_csi_dma_stop() argument
495 spin_lock_irqsave(&csi->irqlock, flags); in imx7_csi_dma_stop()
496 csi->last_eof = true; in imx7_csi_dma_stop()
497 spin_unlock_irqrestore(&csi->irqlock, flags); in imx7_csi_dma_stop()
503 ret = wait_for_completion_timeout(&csi->last_eof_completion, in imx7_csi_dma_stop()
506 v4l2_warn(&csi->sd, "wait last EOF timeout\n"); in imx7_csi_dma_stop()
508 imx7_csi_hw_disable_irq(csi); in imx7_csi_dma_stop()
511 static void imx7_csi_configure(struct imx7_csi *csi, in imx7_csi_configure() argument
514 struct v4l2_pix_format *out_pix = &csi->vdev_fmt; in imx7_csi_configure()
515 int width = out_pix->width; in imx7_csi_configure()
520 cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); in imx7_csi_configure()
527 if (out_pix->field == V4L2_FIELD_INTERLACED) { in imx7_csi_configure()
529 stride = out_pix->width; in imx7_csi_configure()
532 if (!csi->is_csi2) { in imx7_csi_configure()
539 if (out_pix->pixelformat == V4L2_PIX_FMT_UYVY || in imx7_csi_configure()
540 out_pix->pixelformat == V4L2_PIX_FMT_YUYV) in imx7_csi_configure()
541 width *= 2; in imx7_csi_configure()
545 sink_fmt = v4l2_subdev_get_pad_format(&csi->sd, sd_state, in imx7_csi_configure()
553 switch (sink_fmt->code) { in imx7_csi_configure()
587 * The CSI bridge has a 16-bit input bus. Depending on the in imx7_csi_configure()
589 * per clock sample (in bits [9:2] or [9:0] respectively) or in imx7_csi_configure()
591 * then packed into a 32-bit FIFO (as shown in figure 13-11 of in imx7_csi_configure()
594 * The data packing in a 32-bit FIFO input word is controlled by in imx7_csi_configure()
597 * groups four 8-bit input samples (bits [9:2]). When set to 1, in imx7_csi_configure()
598 * data packing groups two 16-bit input samples (bits [15:0]). in imx7_csi_configure()
601 * configured according to the input format for YUV 4:2:2 data. in imx7_csi_configure()
602 * The field controls the gasket between the CSI-2 receiver and in imx7_csi_configure()
603 * the CSI bridge. On i.MX7 and i.MX8MM, the field must be set in imx7_csi_configure()
604 * to 1 when the CSIS outputs 16-bit samples. On i.MX8MQ, the in imx7_csi_configure()
605 * gasket ignores the MIPI_DOUBLE_CMPNT bit and YUV 4:2:2 always in imx7_csi_configure()
606 * uses 16-bit samples. Setting MIPI_DOUBLE_CMPNT in that case in imx7_csi_configure()
622 imx7_csi_reg_write(csi, cr1, CSI_CSICR1); in imx7_csi_configure()
623 imx7_csi_reg_write(csi, BIT_DMA_BURST_TYPE_RFF_INCR16, CSI_CSICR2); in imx7_csi_configure()
624 imx7_csi_reg_write(csi, cr3, CSI_CSICR3); in imx7_csi_configure()
625 imx7_csi_reg_write(csi, cr18, CSI_CSICR18); in imx7_csi_configure()
627 imx7_csi_reg_write(csi, (width * out_pix->height) >> 2, CSI_CSIRXCNT); in imx7_csi_configure()
628 imx7_csi_reg_write(csi, BIT_IMAGE_WIDTH(width) | in imx7_csi_configure()
629 BIT_IMAGE_HEIGHT(out_pix->height), in imx7_csi_configure()
631 imx7_csi_reg_write(csi, stride, CSI_CSIFBUF_PARA); in imx7_csi_configure()
634 static int imx7_csi_init(struct imx7_csi *csi, in imx7_csi_init() argument
639 ret = clk_prepare_enable(csi->mclk); in imx7_csi_init()
643 imx7_csi_configure(csi, sd_state); in imx7_csi_init()
645 ret = imx7_csi_dma_setup(csi); in imx7_csi_init()
647 clk_disable_unprepare(csi->mclk); in imx7_csi_init()
654 static void imx7_csi_deinit(struct imx7_csi *csi, in imx7_csi_deinit() argument
657 imx7_csi_dma_cleanup(csi, return_status); in imx7_csi_deinit()
658 imx7_csi_init_default(csi); in imx7_csi_deinit()
659 imx7_csi_dmareq_rff_disable(csi); in imx7_csi_deinit()
660 clk_disable_unprepare(csi->mclk); in imx7_csi_deinit()
663 static void imx7_csi_baseaddr_switch_on_second_frame(struct imx7_csi *csi) in imx7_csi_baseaddr_switch_on_second_frame() argument
665 u32 cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); in imx7_csi_baseaddr_switch_on_second_frame()
670 imx7_csi_reg_write(csi, cr18, CSI_CSICR18); in imx7_csi_baseaddr_switch_on_second_frame()
673 static void imx7_csi_enable(struct imx7_csi *csi) in imx7_csi_enable() argument
676 imx7_csi_rx_fifo_clear(csi); in imx7_csi_enable()
677 imx7_csi_dma_reflash(csi); in imx7_csi_enable()
682 imx7_csi_irq_clear(csi); in imx7_csi_enable()
683 imx7_csi_hw_enable_irq(csi); in imx7_csi_enable()
685 /* Enable the RxFIFO DMA and the CSI. */ in imx7_csi_enable()
686 imx7_csi_dmareq_rff_enable(csi); in imx7_csi_enable()
687 imx7_csi_hw_enable(csi); in imx7_csi_enable()
689 if (csi->model == IMX7_CSI_IMX8MQ) in imx7_csi_enable()
690 imx7_csi_baseaddr_switch_on_second_frame(csi); in imx7_csi_enable()
693 static void imx7_csi_disable(struct imx7_csi *csi) in imx7_csi_disable() argument
695 imx7_csi_dma_stop(csi); in imx7_csi_disable()
697 imx7_csi_dmareq_rff_disable(csi); in imx7_csi_disable()
699 imx7_csi_hw_disable_irq(csi); in imx7_csi_disable()
701 imx7_csi_hw_disable(csi); in imx7_csi_disable()
704 /* -----------------------------------------------------------------------------
708 static void imx7_csi_error_recovery(struct imx7_csi *csi) in imx7_csi_error_recovery() argument
710 imx7_csi_hw_disable(csi); in imx7_csi_error_recovery()
712 imx7_csi_rx_fifo_clear(csi); in imx7_csi_error_recovery()
714 imx7_csi_dma_reflash(csi); in imx7_csi_error_recovery()
716 imx7_csi_hw_enable(csi); in imx7_csi_error_recovery()
719 static void imx7_csi_vb2_buf_done(struct imx7_csi *csi) in imx7_csi_vb2_buf_done() argument
725 done = csi->active_vb2_buf[csi->buf_num]; in imx7_csi_vb2_buf_done()
727 done->vbuf.field = csi->vdev_fmt.field; in imx7_csi_vb2_buf_done()
728 done->vbuf.sequence = csi->frame_sequence; in imx7_csi_vb2_buf_done()
729 vb = &done->vbuf.vb2_buf; in imx7_csi_vb2_buf_done()
730 vb->timestamp = ktime_get_ns(); in imx7_csi_vb2_buf_done()
733 csi->frame_sequence++; in imx7_csi_vb2_buf_done()
736 next = imx7_csi_video_next_buf(csi); in imx7_csi_vb2_buf_done()
738 dma_addr = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0); in imx7_csi_vb2_buf_done()
739 csi->active_vb2_buf[csi->buf_num] = next; in imx7_csi_vb2_buf_done()
741 dma_addr = csi->underrun_buf.dma_addr; in imx7_csi_vb2_buf_done()
742 csi->active_vb2_buf[csi->buf_num] = NULL; in imx7_csi_vb2_buf_done()
745 imx7_csi_update_buf(csi, dma_addr, csi->buf_num); in imx7_csi_vb2_buf_done()
750 struct imx7_csi *csi = data; in imx7_csi_irq_handler() local
753 spin_lock(&csi->irqlock); in imx7_csi_irq_handler()
755 status = imx7_csi_irq_clear(csi); in imx7_csi_irq_handler()
758 dev_warn(csi->dev, "Rx fifo overflow\n"); in imx7_csi_irq_handler()
759 imx7_csi_error_recovery(csi); in imx7_csi_irq_handler()
763 dev_warn(csi->dev, "Hresponse error detected\n"); in imx7_csi_irq_handler()
764 imx7_csi_error_recovery(csi); in imx7_csi_irq_handler()
768 imx7_csi_hw_disable(csi); in imx7_csi_irq_handler()
770 imx7_csi_dma_reflash(csi); in imx7_csi_irq_handler()
772 imx7_csi_hw_enable(csi); in imx7_csi_irq_handler()
779 * CSI DMA is work in one of FB1 and FB2 buffer, in imx7_csi_irq_handler()
782 * when csi work in field0 and field1 will write to in imx7_csi_irq_handler()
786 csi->buf_num = 0; in imx7_csi_irq_handler()
788 csi->buf_num = 1; in imx7_csi_irq_handler()
793 imx7_csi_vb2_buf_done(csi); in imx7_csi_irq_handler()
795 if (csi->last_eof) { in imx7_csi_irq_handler()
796 complete(&csi->last_eof_completion); in imx7_csi_irq_handler()
797 csi->last_eof = false; in imx7_csi_irq_handler()
801 spin_unlock(&csi->irqlock); in imx7_csi_irq_handler()
806 /* -----------------------------------------------------------------------------
819 * The CSI bridge can be configured to sample pixel components from the Rx queue
825 * As the CSI bridge can be interfaced with different IP blocks depending on the
831 * Example: i.MX8MM SoC integrates the CSI bridge with the Samsung CSIS CSI-2
832 * receiver which operates in dual pixel sampling mode. The CSI bridge should
834 * pixel sampling mode. When the CSI bridge is instead integrated on an i.MX7,
955 if (fmt->fourcc == fourcc) in imx7_csi_find_pixel_format()
974 if (!fmt->codes) in imx7_csi_find_mbus_format()
977 for (j = 0; fmt->codes[j]; j++) { in imx7_csi_find_mbus_format()
978 if (code == fmt->codes[j]) in imx7_csi_find_mbus_format()
988 * requested search criteria. Return the media-bus code that matches
991 * @code: The returned media-bus code that matches the search criteria at
1003 if (!fmt->codes) in imx7_csi_enum_mbus_formats()
1006 for (j = 0; fmt->codes[j]; j++) { in imx7_csi_enum_mbus_formats()
1008 *code = fmt->codes[j]; in imx7_csi_enum_mbus_formats()
1012 index--; in imx7_csi_enum_mbus_formats()
1016 return -EINVAL; in imx7_csi_enum_mbus_formats()
1019 /* -----------------------------------------------------------------------------
1020 * Video Capture Device - IOCTLs
1026 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_querycap() local
1028 strscpy(cap->driver, IMX7_CSI_VIDEO_NAME, sizeof(cap->driver)); in imx7_csi_video_querycap()
1029 strscpy(cap->card, IMX7_CSI_VIDEO_NAME, sizeof(cap->card)); in imx7_csi_video_querycap()
1030 snprintf(cap->bus_info, sizeof(cap->bus_info), in imx7_csi_video_querycap()
1031 "platform:%s", dev_name(csi->dev)); in imx7_csi_video_querycap()
1039 unsigned int index = f->index; in imx7_csi_video_enum_fmt_vid_cap()
1049 if (f->mbus_code) { in imx7_csi_video_enum_fmt_vid_cap()
1052 if (!fmt->codes) in imx7_csi_video_enum_fmt_vid_cap()
1055 for (j = 0; fmt->codes[j]; j++) { in imx7_csi_video_enum_fmt_vid_cap()
1056 if (f->mbus_code == fmt->codes[j]) in imx7_csi_video_enum_fmt_vid_cap()
1060 if (!fmt->codes[j]) in imx7_csi_video_enum_fmt_vid_cap()
1065 f->pixelformat = fmt->fourcc; in imx7_csi_video_enum_fmt_vid_cap()
1069 index--; in imx7_csi_video_enum_fmt_vid_cap()
1072 return -EINVAL; in imx7_csi_video_enum_fmt_vid_cap()
1081 if (fsize->index > 0) in imx7_csi_video_enum_framesizes()
1082 return -EINVAL; in imx7_csi_video_enum_framesizes()
1084 cc = imx7_csi_find_pixel_format(fsize->pixel_format); in imx7_csi_video_enum_framesizes()
1086 return -EINVAL; in imx7_csi_video_enum_framesizes()
1092 walign = 8 * 8 / cc->bpp; in imx7_csi_video_enum_framesizes()
1094 fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; in imx7_csi_video_enum_framesizes()
1095 fsize->stepwise.min_width = walign; in imx7_csi_video_enum_framesizes()
1096 fsize->stepwise.max_width = round_down(65535U, walign); in imx7_csi_video_enum_framesizes()
1097 fsize->stepwise.min_height = 1; in imx7_csi_video_enum_framesizes()
1098 fsize->stepwise.max_height = 65535; in imx7_csi_video_enum_framesizes()
1099 fsize->stepwise.step_width = walign; in imx7_csi_video_enum_framesizes()
1100 fsize->stepwise.step_height = 1; in imx7_csi_video_enum_framesizes()
1108 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_g_fmt_vid_cap() local
1110 f->fmt.pix = csi->vdev_fmt; in imx7_csi_video_g_fmt_vid_cap()
1123 compose->width = pixfmt->width; in __imx7_csi_video_try_fmt()
1124 compose->height = pixfmt->height; in __imx7_csi_video_try_fmt()
1131 cc = imx7_csi_find_pixel_format(pixfmt->pixelformat); in __imx7_csi_video_try_fmt()
1133 pixfmt->pixelformat = IMX7_CSI_DEF_PIX_FORMAT; in __imx7_csi_video_try_fmt()
1134 cc = imx7_csi_find_pixel_format(pixfmt->pixelformat); in __imx7_csi_video_try_fmt()
1143 walign = 8 * 8 / cc->bpp; in __imx7_csi_video_try_fmt()
1144 pixfmt->width = clamp(round_up(pixfmt->width, walign), walign, in __imx7_csi_video_try_fmt()
1146 pixfmt->height = clamp(pixfmt->height, 1U, 65535U); in __imx7_csi_video_try_fmt()
1148 pixfmt->bytesperline = pixfmt->width * cc->bpp / 8; in __imx7_csi_video_try_fmt()
1149 pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; in __imx7_csi_video_try_fmt()
1150 pixfmt->field = V4L2_FIELD_NONE; in __imx7_csi_video_try_fmt()
1158 __imx7_csi_video_try_fmt(&f->fmt.pix, NULL); in imx7_csi_video_try_fmt_vid_cap()
1165 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_s_fmt_vid_cap() local
1168 if (vb2_is_busy(&csi->q)) { in imx7_csi_video_s_fmt_vid_cap()
1169 dev_err(csi->dev, "%s queue busy\n", __func__); in imx7_csi_video_s_fmt_vid_cap()
1170 return -EBUSY; in imx7_csi_video_s_fmt_vid_cap()
1173 cc = __imx7_csi_video_try_fmt(&f->fmt.pix, &csi->vdev_compose); in imx7_csi_video_s_fmt_vid_cap()
1175 csi->vdev_cc = cc; in imx7_csi_video_s_fmt_vid_cap()
1176 csi->vdev_fmt = f->fmt.pix; in imx7_csi_video_s_fmt_vid_cap()
1184 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_g_selection() local
1186 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) in imx7_csi_video_g_selection()
1187 return -EINVAL; in imx7_csi_video_g_selection()
1189 switch (s->target) { in imx7_csi_video_g_selection()
1194 s->r = csi->vdev_compose; in imx7_csi_video_g_selection()
1202 s->r.left = 0; in imx7_csi_video_g_selection()
1203 s->r.top = 0; in imx7_csi_video_g_selection()
1204 s->r.width = csi->vdev_fmt.width; in imx7_csi_video_g_selection()
1205 s->r.height = csi->vdev_fmt.height; in imx7_csi_video_g_selection()
1208 return -EINVAL; in imx7_csi_video_g_selection()
1237 /* -----------------------------------------------------------------------------
1238 * Video Capture Device - Queue Operations
1247 struct imx7_csi *csi = vb2_get_drv_priv(vq); in imx7_csi_video_queue_setup() local
1248 struct v4l2_pix_format *pix = &csi->vdev_fmt; in imx7_csi_video_queue_setup()
1251 if (vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) in imx7_csi_video_queue_setup()
1252 return -EINVAL; in imx7_csi_video_queue_setup()
1255 if (*nplanes != 1 || sizes[0] < pix->sizeimage) in imx7_csi_video_queue_setup()
1256 return -EINVAL; in imx7_csi_video_queue_setup()
1257 count += vq->num_buffers; in imx7_csi_video_queue_setup()
1260 count = min_t(__u32, IMX7_CSI_VIDEO_MEM_LIMIT / pix->sizeimage, count); in imx7_csi_video_queue_setup()
1263 *nbuffers = (count < vq->num_buffers) ? 0 : in imx7_csi_video_queue_setup()
1264 count - vq->num_buffers; in imx7_csi_video_queue_setup()
1269 sizes[0] = pix->sizeimage; in imx7_csi_video_queue_setup()
1278 INIT_LIST_HEAD(&buf->list); in imx7_csi_video_buf_init()
1285 struct imx7_csi *csi = vb2_get_drv_priv(vb->vb2_queue); in imx7_csi_video_buf_prepare() local
1286 struct v4l2_pix_format *pix = &csi->vdev_fmt; in imx7_csi_video_buf_prepare()
1288 if (vb2_plane_size(vb, 0) < pix->sizeimage) { in imx7_csi_video_buf_prepare()
1289 dev_err(csi->dev, in imx7_csi_video_buf_prepare()
1291 vb2_plane_size(vb, 0), (long)pix->sizeimage); in imx7_csi_video_buf_prepare()
1292 return -EINVAL; in imx7_csi_video_buf_prepare()
1295 vb2_set_plane_payload(vb, 0, pix->sizeimage); in imx7_csi_video_buf_prepare()
1300 static bool imx7_csi_fast_track_buffer(struct imx7_csi *csi, in imx7_csi_fast_track_buffer() argument
1308 if (!csi->is_streaming) in imx7_csi_fast_track_buffer()
1311 dma_addr = vb2_dma_contig_plane_dma_addr(&buf->vbuf.vb2_buf, 0); in imx7_csi_fast_track_buffer()
1318 * being NULL), then we can fast-track the new buffer by programming in imx7_csi_fast_track_buffer()
1327 * by the interrupt handler for FB2. The fast-tracked buffer would in imx7_csi_fast_track_buffer()
1334 * raised. If that is not the case, fast-tracking succeeded, and we can in imx7_csi_fast_track_buffer()
1342 spin_lock_irqsave(&csi->irqlock, flags); in imx7_csi_fast_track_buffer()
1344 buf_num = csi->buf_num; in imx7_csi_fast_track_buffer()
1345 if (csi->active_vb2_buf[buf_num]) { in imx7_csi_fast_track_buffer()
1346 spin_unlock_irqrestore(&csi->irqlock, flags); in imx7_csi_fast_track_buffer()
1350 imx7_csi_update_buf(csi, dma_addr, buf_num); in imx7_csi_fast_track_buffer()
1352 isr = imx7_csi_reg_read(csi, CSI_CSISR); in imx7_csi_fast_track_buffer()
1363 spin_unlock_irqrestore(&csi->irqlock, flags); in imx7_csi_fast_track_buffer()
1367 csi->active_vb2_buf[buf_num] = buf; in imx7_csi_fast_track_buffer()
1369 spin_unlock_irqrestore(&csi->irqlock, flags); in imx7_csi_fast_track_buffer()
1375 struct imx7_csi *csi = vb2_get_drv_priv(vb->vb2_queue); in imx7_csi_video_buf_queue() local
1379 if (imx7_csi_fast_track_buffer(csi, buf)) in imx7_csi_video_buf_queue()
1382 spin_lock_irqsave(&csi->q_lock, flags); in imx7_csi_video_buf_queue()
1384 list_add_tail(&buf->list, &csi->ready_q); in imx7_csi_video_buf_queue()
1386 spin_unlock_irqrestore(&csi->q_lock, flags); in imx7_csi_video_buf_queue()
1389 static int imx7_csi_video_validate_fmt(struct imx7_csi *csi) in imx7_csi_video_validate_fmt() argument
1399 ret = v4l2_subdev_call_state_active(&csi->sd, pad, get_fmt, &fmt_src); in imx7_csi_video_validate_fmt()
1410 if (csi->vdev_compose.width != fmt_src.format.width || in imx7_csi_video_validate_fmt()
1411 csi->vdev_compose.height != fmt_src.format.height) in imx7_csi_video_validate_fmt()
1412 return -EPIPE; in imx7_csi_video_validate_fmt()
1419 if (!cc || csi->vdev_cc->yuv != cc->yuv) in imx7_csi_video_validate_fmt()
1420 return -EPIPE; in imx7_csi_video_validate_fmt()
1428 struct imx7_csi *csi = vb2_get_drv_priv(vq); in imx7_csi_video_start_streaming() local
1433 ret = imx7_csi_video_validate_fmt(csi); in imx7_csi_video_start_streaming()
1435 dev_err(csi->dev, "capture format not valid\n"); in imx7_csi_video_start_streaming()
1439 mutex_lock(&csi->mdev.graph_mutex); in imx7_csi_video_start_streaming()
1441 ret = __video_device_pipeline_start(csi->vdev, &csi->pipe); in imx7_csi_video_start_streaming()
1445 ret = v4l2_subdev_call(&csi->sd, video, s_stream, 1); in imx7_csi_video_start_streaming()
1449 mutex_unlock(&csi->mdev.graph_mutex); in imx7_csi_video_start_streaming()
1454 __video_device_pipeline_stop(csi->vdev); in imx7_csi_video_start_streaming()
1456 mutex_unlock(&csi->mdev.graph_mutex); in imx7_csi_video_start_streaming()
1457 dev_err(csi->dev, "pipeline start failed with %d\n", ret); in imx7_csi_video_start_streaming()
1459 spin_lock_irqsave(&csi->q_lock, flags); in imx7_csi_video_start_streaming()
1460 list_for_each_entry_safe(buf, tmp, &csi->ready_q, list) { in imx7_csi_video_start_streaming()
1461 list_del(&buf->list); in imx7_csi_video_start_streaming()
1462 vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); in imx7_csi_video_start_streaming()
1464 spin_unlock_irqrestore(&csi->q_lock, flags); in imx7_csi_video_start_streaming()
1470 struct imx7_csi *csi = vb2_get_drv_priv(vq); in imx7_csi_video_stop_streaming() local
1475 mutex_lock(&csi->mdev.graph_mutex); in imx7_csi_video_stop_streaming()
1476 v4l2_subdev_call(&csi->sd, video, s_stream, 0); in imx7_csi_video_stop_streaming()
1477 __video_device_pipeline_stop(csi->vdev); in imx7_csi_video_stop_streaming()
1478 mutex_unlock(&csi->mdev.graph_mutex); in imx7_csi_video_stop_streaming()
1481 spin_lock_irqsave(&csi->q_lock, flags); in imx7_csi_video_stop_streaming()
1482 list_for_each_entry_safe(frame, tmp, &csi->ready_q, list) { in imx7_csi_video_stop_streaming()
1483 list_del(&frame->list); in imx7_csi_video_stop_streaming()
1484 vb2_buffer_done(&frame->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); in imx7_csi_video_stop_streaming()
1486 spin_unlock_irqrestore(&csi->q_lock, flags); in imx7_csi_video_stop_streaming()
1500 /* -----------------------------------------------------------------------------
1501 * Video Capture Device - File Operations
1506 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_open() local
1509 if (mutex_lock_interruptible(&csi->vdev_mutex)) in imx7_csi_video_open()
1510 return -ERESTARTSYS; in imx7_csi_video_open()
1514 dev_err(csi->dev, "v4l2_fh_open failed\n"); in imx7_csi_video_open()
1518 ret = v4l2_pipeline_pm_get(&csi->vdev->entity); in imx7_csi_video_open()
1523 mutex_unlock(&csi->vdev_mutex); in imx7_csi_video_open()
1529 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_release() local
1530 struct vb2_queue *vq = &csi->q; in imx7_csi_video_release()
1532 mutex_lock(&csi->vdev_mutex); in imx7_csi_video_release()
1534 if (file->private_data == vq->owner) { in imx7_csi_video_release()
1536 vq->owner = NULL; in imx7_csi_video_release()
1539 v4l2_pipeline_pm_put(&csi->vdev->entity); in imx7_csi_video_release()
1542 mutex_unlock(&csi->vdev_mutex); in imx7_csi_video_release()
1555 /* -----------------------------------------------------------------------------
1556 * Video Capture Device - Init & Cleanup
1559 static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi) in imx7_csi_video_next_buf() argument
1564 spin_lock_irqsave(&csi->q_lock, flags); in imx7_csi_video_next_buf()
1567 if (!list_empty(&csi->ready_q)) { in imx7_csi_video_next_buf()
1568 buf = list_entry(csi->ready_q.next, struct imx7_csi_vb2_buffer, in imx7_csi_video_next_buf()
1570 list_del(&buf->list); in imx7_csi_video_next_buf()
1573 spin_unlock_irqrestore(&csi->q_lock, flags); in imx7_csi_video_next_buf()
1578 static void imx7_csi_video_init_format(struct imx7_csi *csi) in imx7_csi_video_init_format() argument
1580 struct v4l2_pix_format *pixfmt = &csi->vdev_fmt; in imx7_csi_video_init_format()
1582 pixfmt->width = IMX7_CSI_DEF_PIX_WIDTH; in imx7_csi_video_init_format()
1583 pixfmt->height = IMX7_CSI_DEF_PIX_HEIGHT; in imx7_csi_video_init_format()
1585 csi->vdev_cc = __imx7_csi_video_try_fmt(pixfmt, &csi->vdev_compose); in imx7_csi_video_init_format()
1588 static int imx7_csi_video_register(struct imx7_csi *csi) in imx7_csi_video_register() argument
1590 struct v4l2_subdev *sd = &csi->sd; in imx7_csi_video_register()
1591 struct v4l2_device *v4l2_dev = sd->v4l2_dev; in imx7_csi_video_register()
1592 struct video_device *vdev = csi->vdev; in imx7_csi_video_register()
1595 vdev->v4l2_dev = v4l2_dev; in imx7_csi_video_register()
1598 imx7_csi_video_init_format(csi); in imx7_csi_video_register()
1601 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); in imx7_csi_video_register()
1603 dev_err(csi->dev, "Failed to register video device\n"); in imx7_csi_video_register()
1607 dev_info(csi->dev, "Registered %s as /dev/%s\n", vdev->name, in imx7_csi_video_register()
1610 /* Create the link from the CSI subdev to the video device. */ in imx7_csi_video_register()
1611 ret = media_create_pad_link(&sd->entity, IMX7_CSI_PAD_SRC, in imx7_csi_video_register()
1612 &vdev->entity, 0, MEDIA_LNK_FL_IMMUTABLE | in imx7_csi_video_register()
1615 dev_err(csi->dev, "failed to create link to device node\n"); in imx7_csi_video_register()
1623 static void imx7_csi_video_unregister(struct imx7_csi *csi) in imx7_csi_video_unregister() argument
1625 media_entity_cleanup(&csi->vdev->entity); in imx7_csi_video_unregister()
1626 video_unregister_device(csi->vdev); in imx7_csi_video_unregister()
1629 static int imx7_csi_video_init(struct imx7_csi *csi) in imx7_csi_video_init() argument
1635 mutex_init(&csi->vdev_mutex); in imx7_csi_video_init()
1636 INIT_LIST_HEAD(&csi->ready_q); in imx7_csi_video_init()
1637 spin_lock_init(&csi->q_lock); in imx7_csi_video_init()
1642 return -ENOMEM; in imx7_csi_video_init()
1644 vdev->fops = &imx7_csi_video_fops; in imx7_csi_video_init()
1645 vdev->ioctl_ops = &imx7_csi_video_ioctl_ops; in imx7_csi_video_init()
1646 vdev->minor = -1; in imx7_csi_video_init()
1647 vdev->release = video_device_release; in imx7_csi_video_init()
1648 vdev->vfl_dir = VFL_DIR_RX; in imx7_csi_video_init()
1649 vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; in imx7_csi_video_init()
1650 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING in imx7_csi_video_init()
1652 vdev->lock = &csi->vdev_mutex; in imx7_csi_video_init()
1653 vdev->queue = &csi->q; in imx7_csi_video_init()
1655 snprintf(vdev->name, sizeof(vdev->name), "%s capture", csi->sd.name); in imx7_csi_video_init()
1657 video_set_drvdata(vdev, csi); in imx7_csi_video_init()
1658 csi->vdev = vdev; in imx7_csi_video_init()
1661 csi->vdev_pad.flags = MEDIA_PAD_FL_SINK; in imx7_csi_video_init()
1662 ret = media_entity_pads_init(&vdev->entity, 1, &csi->vdev_pad); in imx7_csi_video_init()
1669 vq = &csi->q; in imx7_csi_video_init()
1670 vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; in imx7_csi_video_init()
1671 vq->io_modes = VB2_MMAP | VB2_DMABUF; in imx7_csi_video_init()
1672 vq->drv_priv = csi; in imx7_csi_video_init()
1673 vq->buf_struct_size = sizeof(struct imx7_csi_vb2_buffer); in imx7_csi_video_init()
1674 vq->ops = &imx7_csi_video_qops; in imx7_csi_video_init()
1675 vq->mem_ops = &vb2_dma_contig_memops; in imx7_csi_video_init()
1676 vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; in imx7_csi_video_init()
1677 vq->lock = &csi->vdev_mutex; in imx7_csi_video_init()
1678 vq->min_buffers_needed = 2; in imx7_csi_video_init()
1679 vq->dev = csi->dev; in imx7_csi_video_init()
1683 dev_err(csi->dev, "vb2_queue_init failed\n"); in imx7_csi_video_init()
1691 /* -----------------------------------------------------------------------------
1697 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_s_stream() local
1704 ret = imx7_csi_init(csi, sd_state); in imx7_csi_s_stream()
1708 ret = v4l2_subdev_call(csi->src_sd, video, s_stream, 1); in imx7_csi_s_stream()
1710 imx7_csi_deinit(csi, VB2_BUF_STATE_QUEUED); in imx7_csi_s_stream()
1714 imx7_csi_enable(csi); in imx7_csi_s_stream()
1716 imx7_csi_disable(csi); in imx7_csi_s_stream()
1718 v4l2_subdev_call(csi->src_sd, video, s_stream, 0); in imx7_csi_s_stream()
1720 imx7_csi_deinit(csi, VB2_BUF_STATE_ERROR); in imx7_csi_s_stream()
1723 csi->is_streaming = !!enable; in imx7_csi_s_stream()
1743 mf->code = IMX7_CSI_DEF_MBUS_CODE; in imx7_csi_init_cfg()
1744 mf->width = IMX7_CSI_DEF_PIX_WIDTH; in imx7_csi_init_cfg()
1745 mf->height = IMX7_CSI_DEF_PIX_HEIGHT; in imx7_csi_init_cfg()
1746 mf->field = V4L2_FIELD_NONE; in imx7_csi_init_cfg()
1748 mf->colorspace = V4L2_COLORSPACE_SRGB; in imx7_csi_init_cfg()
1749 mf->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mf->colorspace); in imx7_csi_init_cfg()
1750 mf->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mf->colorspace); in imx7_csi_init_cfg()
1751 mf->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!cc->yuv, in imx7_csi_init_cfg()
1752 mf->colorspace, mf->ycbcr_enc); in imx7_csi_init_cfg()
1767 switch (code->pad) { in imx7_csi_enum_mbus_code()
1769 ret = imx7_csi_enum_mbus_formats(&code->code, code->index); in imx7_csi_enum_mbus_code()
1773 if (code->index != 0) { in imx7_csi_enum_mbus_code()
1774 ret = -EINVAL; in imx7_csi_enum_mbus_code()
1778 code->code = in_fmt->code; in imx7_csi_enum_mbus_code()
1782 ret = -EINVAL; in imx7_csi_enum_mbus_code()
1794 * tryfmt->code must be set on entry.
1801 cc = imx7_csi_find_mbus_format(tryfmt->code); in imx7_csi_try_colorimetry()
1802 if (cc && !cc->yuv) in imx7_csi_try_colorimetry()
1805 switch (tryfmt->colorspace) { in imx7_csi_try_colorimetry()
1816 tryfmt->colorspace = V4L2_COLORSPACE_SRGB; in imx7_csi_try_colorimetry()
1820 if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT) in imx7_csi_try_colorimetry()
1821 tryfmt->xfer_func = in imx7_csi_try_colorimetry()
1822 V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace); in imx7_csi_try_colorimetry()
1824 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) in imx7_csi_try_colorimetry()
1825 tryfmt->ycbcr_enc = in imx7_csi_try_colorimetry()
1826 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace); in imx7_csi_try_colorimetry()
1828 if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT) in imx7_csi_try_colorimetry()
1829 tryfmt->quantization = in imx7_csi_try_colorimetry()
1831 tryfmt->colorspace, in imx7_csi_try_colorimetry()
1832 tryfmt->ycbcr_enc); in imx7_csi_try_colorimetry()
1846 switch (sdformat->pad) { in imx7_csi_try_fmt()
1848 in_cc = imx7_csi_find_mbus_format(in_fmt->code); in imx7_csi_try_fmt()
1850 sdformat->format.width = in_fmt->width; in imx7_csi_try_fmt()
1851 sdformat->format.height = in_fmt->height; in imx7_csi_try_fmt()
1852 sdformat->format.code = in_fmt->code; in imx7_csi_try_fmt()
1853 sdformat->format.field = in_fmt->field; in imx7_csi_try_fmt()
1856 sdformat->format.colorspace = in_fmt->colorspace; in imx7_csi_try_fmt()
1857 sdformat->format.xfer_func = in_fmt->xfer_func; in imx7_csi_try_fmt()
1858 sdformat->format.quantization = in_fmt->quantization; in imx7_csi_try_fmt()
1859 sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc; in imx7_csi_try_fmt()
1863 *cc = imx7_csi_find_mbus_format(sdformat->format.code); in imx7_csi_try_fmt()
1867 sdformat->format.code = code; in imx7_csi_try_fmt()
1870 if (sdformat->format.field != V4L2_FIELD_INTERLACED) in imx7_csi_try_fmt()
1871 sdformat->format.field = V4L2_FIELD_NONE; in imx7_csi_try_fmt()
1875 imx7_csi_try_colorimetry(&sdformat->format); in imx7_csi_try_fmt()
1882 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_set_fmt() local
1889 if (csi->is_streaming) in imx7_csi_set_fmt()
1890 return -EBUSY; in imx7_csi_set_fmt()
1894 fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad); in imx7_csi_set_fmt()
1896 *fmt = sdformat->format; in imx7_csi_set_fmt()
1898 if (sdformat->pad == IMX7_CSI_PAD_SINK) { in imx7_csi_set_fmt()
1901 format.which = sdformat->which; in imx7_csi_set_fmt()
1902 format.format = sdformat->format; in imx7_csi_set_fmt()
1918 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_pad_link_validate() local
1925 * parallel input or the CSI-2 receiver. in imx7_csi_pad_link_validate()
1931 switch (csi->src_sd->entity.function) { in imx7_csi_pad_link_validate()
1933 /* The input is the CSI-2 receiver. */ in imx7_csi_pad_link_validate()
1934 csi->is_csi2 = true; in imx7_csi_pad_link_validate()
1939 for (i = 0; i < csi->src_sd->entity.num_pads; i++) { in imx7_csi_pad_link_validate()
1940 struct media_pad *spad = &csi->src_sd->entity.pads[i]; in imx7_csi_pad_link_validate()
1942 if (!(spad->flags & MEDIA_PAD_FL_SINK)) in imx7_csi_pad_link_validate()
1951 return -ENODEV; in imx7_csi_pad_link_validate()
1953 csi->is_csi2 = pad->entity->function == MEDIA_ENT_F_VID_IF_BRIDGE; in imx7_csi_pad_link_validate()
1961 csi->is_csi2 = false; in imx7_csi_pad_link_validate()
1970 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_registered() local
1973 ret = imx7_csi_video_init(csi); in imx7_csi_registered()
1977 ret = imx7_csi_video_register(csi); in imx7_csi_registered()
1981 ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); in imx7_csi_registered()
1985 ret = media_device_register(&csi->mdev); in imx7_csi_registered()
1992 imx7_csi_video_unregister(csi); in imx7_csi_registered()
1998 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_unregistered() local
2000 imx7_csi_video_unregister(csi); in imx7_csi_unregistered()
2025 /* -----------------------------------------------------------------------------
2034 /* -----------------------------------------------------------------------------
2042 struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier); in imx7_csi_notify_bound() local
2043 struct media_pad *sink = &csi->sd.entity.pads[IMX7_CSI_PAD_SINK]; in imx7_csi_notify_bound()
2045 csi->src_sd = sd; in imx7_csi_notify_bound()
2053 struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier); in imx7_csi_notify_complete() local
2055 return v4l2_device_register_subdev_nodes(&csi->v4l2_dev); in imx7_csi_notify_complete()
2063 static int imx7_csi_async_register(struct imx7_csi *csi) in imx7_csi_async_register() argument
2069 v4l2_async_nf_init(&csi->notifier, &csi->v4l2_dev); in imx7_csi_async_register()
2071 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0, in imx7_csi_async_register()
2074 ret = dev_err_probe(csi->dev, -ENOTCONN, in imx7_csi_async_register()
2079 asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep, in imx7_csi_async_register()
2085 ret = dev_err_probe(csi->dev, PTR_ERR(asd), in imx7_csi_async_register()
2090 csi->notifier.ops = &imx7_csi_notify_ops; in imx7_csi_async_register()
2092 ret = v4l2_async_nf_register(&csi->notifier); in imx7_csi_async_register()
2099 v4l2_async_nf_cleanup(&csi->notifier); in imx7_csi_async_register()
2103 static void imx7_csi_media_cleanup(struct imx7_csi *csi) in imx7_csi_media_cleanup() argument
2105 v4l2_device_unregister(&csi->v4l2_dev); in imx7_csi_media_cleanup()
2106 media_device_unregister(&csi->mdev); in imx7_csi_media_cleanup()
2107 v4l2_subdev_cleanup(&csi->sd); in imx7_csi_media_cleanup()
2108 media_device_cleanup(&csi->mdev); in imx7_csi_media_cleanup()
2115 static int imx7_csi_media_dev_init(struct imx7_csi *csi) in imx7_csi_media_dev_init() argument
2119 strscpy(csi->mdev.model, "imx-media", sizeof(csi->mdev.model)); in imx7_csi_media_dev_init()
2120 csi->mdev.ops = &imx7_csi_media_ops; in imx7_csi_media_dev_init()
2121 csi->mdev.dev = csi->dev; in imx7_csi_media_dev_init()
2123 csi->v4l2_dev.mdev = &csi->mdev; in imx7_csi_media_dev_init()
2124 strscpy(csi->v4l2_dev.name, "imx-media", in imx7_csi_media_dev_init()
2125 sizeof(csi->v4l2_dev.name)); in imx7_csi_media_dev_init()
2126 snprintf(csi->mdev.bus_info, sizeof(csi->mdev.bus_info), in imx7_csi_media_dev_init()
2127 "platform:%s", dev_name(csi->mdev.dev)); in imx7_csi_media_dev_init()
2129 media_device_init(&csi->mdev); in imx7_csi_media_dev_init()
2131 ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); in imx7_csi_media_dev_init()
2133 v4l2_err(&csi->v4l2_dev, in imx7_csi_media_dev_init()
2141 media_device_cleanup(&csi->mdev); in imx7_csi_media_dev_init()
2146 static int imx7_csi_media_init(struct imx7_csi *csi) in imx7_csi_media_init() argument
2152 ret = imx7_csi_media_dev_init(csi); in imx7_csi_media_init()
2156 v4l2_subdev_init(&csi->sd, &imx7_csi_subdev_ops); in imx7_csi_media_init()
2157 v4l2_set_subdevdata(&csi->sd, csi); in imx7_csi_media_init()
2158 csi->sd.internal_ops = &imx7_csi_internal_ops; in imx7_csi_media_init()
2159 csi->sd.entity.ops = &imx7_csi_entity_ops; in imx7_csi_media_init()
2160 csi->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; in imx7_csi_media_init()
2161 csi->sd.dev = csi->dev; in imx7_csi_media_init()
2162 csi->sd.owner = THIS_MODULE; in imx7_csi_media_init()
2163 csi->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; in imx7_csi_media_init()
2164 snprintf(csi->sd.name, sizeof(csi->sd.name), "csi"); in imx7_csi_media_init()
2167 csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ? in imx7_csi_media_init()
2170 ret = media_entity_pads_init(&csi->sd.entity, IMX7_CSI_PADS_NUM, in imx7_csi_media_init()
2171 csi->pad); in imx7_csi_media_init()
2175 ret = v4l2_subdev_init_finalize(&csi->sd); in imx7_csi_media_init()
2179 ret = v4l2_device_register_subdev(&csi->v4l2_dev, &csi->sd); in imx7_csi_media_init()
2186 imx7_csi_media_cleanup(csi); in imx7_csi_media_init()
2192 struct device *dev = &pdev->dev; in imx7_csi_probe()
2193 struct imx7_csi *csi; in imx7_csi_probe() local
2196 csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); in imx7_csi_probe()
2197 if (!csi) in imx7_csi_probe()
2198 return -ENOMEM; in imx7_csi_probe()
2200 csi->dev = dev; in imx7_csi_probe()
2201 platform_set_drvdata(pdev, csi); in imx7_csi_probe()
2203 spin_lock_init(&csi->irqlock); in imx7_csi_probe()
2206 csi->mclk = devm_clk_get(&pdev->dev, "mclk"); in imx7_csi_probe()
2207 if (IS_ERR(csi->mclk)) { in imx7_csi_probe()
2208 ret = PTR_ERR(csi->mclk); in imx7_csi_probe()
2213 csi->irq = platform_get_irq(pdev, 0); in imx7_csi_probe()
2214 if (csi->irq < 0) in imx7_csi_probe()
2215 return csi->irq; in imx7_csi_probe()
2217 csi->regbase = devm_platform_ioremap_resource(pdev, 0); in imx7_csi_probe()
2218 if (IS_ERR(csi->regbase)) in imx7_csi_probe()
2219 return PTR_ERR(csi->regbase); in imx7_csi_probe()
2221 csi->model = (enum imx_csi_model)(uintptr_t)of_device_get_match_data(&pdev->dev); in imx7_csi_probe()
2223 ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi", in imx7_csi_probe()
2224 (void *)csi); in imx7_csi_probe()
2226 dev_err(dev, "Request CSI IRQ failed.\n"); in imx7_csi_probe()
2231 ret = imx7_csi_media_init(csi); in imx7_csi_probe()
2235 ret = imx7_csi_async_register(csi); in imx7_csi_probe()
2242 imx7_csi_media_cleanup(csi); in imx7_csi_probe()
2249 struct imx7_csi *csi = platform_get_drvdata(pdev); in imx7_csi_remove() local
2251 imx7_csi_media_cleanup(csi); in imx7_csi_remove()
2253 v4l2_async_nf_unregister(&csi->notifier); in imx7_csi_remove()
2254 v4l2_async_nf_cleanup(&csi->notifier); in imx7_csi_remove()
2255 v4l2_async_unregister_subdev(&csi->sd); in imx7_csi_remove()
2259 { .compatible = "fsl,imx8mq-csi", .data = (void *)IMX7_CSI_IMX8MQ },
2260 { .compatible = "fsl,imx7-csi", .data = (void *)IMX7_CSI_IMX7 },
2261 { .compatible = "fsl,imx6ul-csi", .data = (void *)IMX7_CSI_IMX7 },
2271 .name = "imx7-csi",
2276 MODULE_DESCRIPTION("i.MX7 CSI subdev driver");
2279 MODULE_ALIAS("platform:imx7-csi");