Lines Matching +full:imx7 +full:- +full:csi

1 // SPDX-License-Identifier: GPL-2.0
3 * V4L2 Capture CSI Subdev for Freescale i.MX6UL/L / i.MX7 SOC
13 #include <linux/dma-mapping.h>
33 #include <media/media-device.h>
34 #include <media/media-entity.h>
35 #include <media/v4l2-async.h>
36 #include <media/v4l2-common.h>
37 #include <media/v4l2-dev.h>
38 #include <media/v4l2-device.h>
39 #include <media/v4l2-fh.h>
40 #include <media/v4l2-ioctl.h>
41 #include <media/v4l2-mc.h>
42 #include <media/v4l2-subdev.h>
43 #include <media/videobuf2-core.h>
44 #include <media/videobuf2-dma-contig.h>
45 #include <media/videobuf2-v4l2.h>
51 /* csi control reg 1 */
106 /* csi status reg */
126 /* csi image parameter reg */
130 /* csi control reg 18 */
177 #define IMX7_CSI_VIDEO_NAME "imx-capture"
193 /* the in-memory FourCC pixel format */
197 * NOTE! codes pointer is NULL for in-memory-only formats.
280 /* -----------------------------------------------------------------------------
284 static u32 imx7_csi_reg_read(struct imx7_csi *csi, unsigned int offset) in imx7_csi_reg_read() argument
286 return readl(csi->regbase + offset); in imx7_csi_reg_read()
289 static void imx7_csi_reg_write(struct imx7_csi *csi, unsigned int value, in imx7_csi_reg_write() argument
292 writel(value, csi->regbase + offset); in imx7_csi_reg_write()
295 static u32 imx7_csi_irq_clear(struct imx7_csi *csi) in imx7_csi_irq_clear() argument
299 isr = imx7_csi_reg_read(csi, CSI_CSISR); in imx7_csi_irq_clear()
300 imx7_csi_reg_write(csi, isr, CSI_CSISR); in imx7_csi_irq_clear()
305 static void imx7_csi_init_default(struct imx7_csi *csi) in imx7_csi_init_default() argument
307 imx7_csi_reg_write(csi, BIT_SOF_POL | BIT_REDGE | BIT_GCLK_MODE | in imx7_csi_init_default()
310 imx7_csi_reg_write(csi, 0, CSI_CSICR2); in imx7_csi_init_default()
311 imx7_csi_reg_write(csi, BIT_FRMCNT_RST, CSI_CSICR3); in imx7_csi_init_default()
313 imx7_csi_reg_write(csi, BIT_IMAGE_WIDTH(IMX7_CSI_DEF_PIX_WIDTH) | in imx7_csi_init_default()
317 imx7_csi_reg_write(csi, BIT_DMA_REFLASH_RFF, CSI_CSICR3); in imx7_csi_init_default()
320 static void imx7_csi_hw_enable_irq(struct imx7_csi *csi) in imx7_csi_hw_enable_irq() argument
322 u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); in imx7_csi_hw_enable_irq()
328 imx7_csi_reg_write(csi, cr1, CSI_CSICR1); in imx7_csi_hw_enable_irq()
331 static void imx7_csi_hw_disable_irq(struct imx7_csi *csi) in imx7_csi_hw_disable_irq() argument
333 u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); in imx7_csi_hw_disable_irq()
339 imx7_csi_reg_write(csi, cr1, CSI_CSICR1); in imx7_csi_hw_disable_irq()
342 static void imx7_csi_hw_enable(struct imx7_csi *csi) in imx7_csi_hw_enable() argument
344 u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18); in imx7_csi_hw_enable()
348 imx7_csi_reg_write(csi, cr, CSI_CSICR18); in imx7_csi_hw_enable()
351 static void imx7_csi_hw_disable(struct imx7_csi *csi) in imx7_csi_hw_disable() argument
353 u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18); in imx7_csi_hw_disable()
357 imx7_csi_reg_write(csi, cr, CSI_CSICR18); in imx7_csi_hw_disable()
360 static void imx7_csi_dma_reflash(struct imx7_csi *csi) in imx7_csi_dma_reflash() argument
364 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); in imx7_csi_dma_reflash()
366 imx7_csi_reg_write(csi, cr3, CSI_CSICR3); in imx7_csi_dma_reflash()
369 static void imx7_csi_rx_fifo_clear(struct imx7_csi *csi) in imx7_csi_rx_fifo_clear() argument
371 u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1) & ~BIT_FCC; in imx7_csi_rx_fifo_clear()
373 imx7_csi_reg_write(csi, cr1, CSI_CSICR1); in imx7_csi_rx_fifo_clear()
374 imx7_csi_reg_write(csi, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1); in imx7_csi_rx_fifo_clear()
375 imx7_csi_reg_write(csi, cr1 | BIT_FCC, CSI_CSICR1); in imx7_csi_rx_fifo_clear()
378 static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi) in imx7_csi_dmareq_rff_enable() argument
380 u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); in imx7_csi_dmareq_rff_enable()
387 imx7_csi_reg_write(csi, cr3, CSI_CSICR3); in imx7_csi_dmareq_rff_enable()
390 static void imx7_csi_dmareq_rff_disable(struct imx7_csi *csi) in imx7_csi_dmareq_rff_disable() argument
392 u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); in imx7_csi_dmareq_rff_disable()
396 imx7_csi_reg_write(csi, cr3, CSI_CSICR3); in imx7_csi_dmareq_rff_disable()
399 static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t dma_addr, in imx7_csi_update_buf() argument
403 imx7_csi_reg_write(csi, dma_addr, CSI_CSIDMASA_FB2); in imx7_csi_update_buf()
405 imx7_csi_reg_write(csi, dma_addr, CSI_CSIDMASA_FB1); in imx7_csi_update_buf()
408 static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi);
410 static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi) in imx7_csi_setup_vb2_buf() argument
419 buf = imx7_csi_video_next_buf(csi); in imx7_csi_setup_vb2_buf()
421 csi->active_vb2_buf[i] = buf; in imx7_csi_setup_vb2_buf()
422 vb2_buf = &buf->vbuf.vb2_buf; in imx7_csi_setup_vb2_buf()
425 csi->active_vb2_buf[i] = NULL; in imx7_csi_setup_vb2_buf()
426 dma_addr = csi->underrun_buf.dma_addr; in imx7_csi_setup_vb2_buf()
429 imx7_csi_update_buf(csi, dma_addr, i); in imx7_csi_setup_vb2_buf()
433 static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi, in imx7_csi_dma_unsetup_vb2_buf() argument
441 buf = csi->active_vb2_buf[i]; in imx7_csi_dma_unsetup_vb2_buf()
443 struct vb2_buffer *vb = &buf->vbuf.vb2_buf; in imx7_csi_dma_unsetup_vb2_buf()
445 vb->timestamp = ktime_get_ns(); in imx7_csi_dma_unsetup_vb2_buf()
447 csi->active_vb2_buf[i] = NULL; in imx7_csi_dma_unsetup_vb2_buf()
452 static void imx7_csi_free_dma_buf(struct imx7_csi *csi, in imx7_csi_free_dma_buf() argument
455 if (buf->virt) in imx7_csi_free_dma_buf()
456 dma_free_coherent(csi->dev, buf->len, buf->virt, buf->dma_addr); in imx7_csi_free_dma_buf()
458 buf->virt = NULL; in imx7_csi_free_dma_buf()
459 buf->dma_addr = 0; in imx7_csi_free_dma_buf()
462 static int imx7_csi_alloc_dma_buf(struct imx7_csi *csi, in imx7_csi_alloc_dma_buf() argument
465 imx7_csi_free_dma_buf(csi, buf); in imx7_csi_alloc_dma_buf()
467 buf->len = PAGE_ALIGN(size); in imx7_csi_alloc_dma_buf()
468 buf->virt = dma_alloc_coherent(csi->dev, buf->len, &buf->dma_addr, in imx7_csi_alloc_dma_buf()
470 if (!buf->virt) in imx7_csi_alloc_dma_buf()
471 return -ENOMEM; in imx7_csi_alloc_dma_buf()
476 static int imx7_csi_dma_setup(struct imx7_csi *csi) in imx7_csi_dma_setup() argument
480 ret = imx7_csi_alloc_dma_buf(csi, &csi->underrun_buf, in imx7_csi_dma_setup()
481 csi->vdev_fmt.sizeimage); in imx7_csi_dma_setup()
483 v4l2_warn(&csi->sd, "consider increasing the CMA area\n"); in imx7_csi_dma_setup()
487 csi->frame_sequence = 0; in imx7_csi_dma_setup()
488 csi->last_eof = false; in imx7_csi_dma_setup()
489 init_completion(&csi->last_eof_completion); in imx7_csi_dma_setup()
491 imx7_csi_setup_vb2_buf(csi); in imx7_csi_dma_setup()
496 static void imx7_csi_dma_cleanup(struct imx7_csi *csi, in imx7_csi_dma_cleanup() argument
499 imx7_csi_dma_unsetup_vb2_buf(csi, return_status); in imx7_csi_dma_cleanup()
500 imx7_csi_free_dma_buf(csi, &csi->underrun_buf); in imx7_csi_dma_cleanup()
503 static void imx7_csi_dma_stop(struct imx7_csi *csi) in imx7_csi_dma_stop() argument
510 spin_lock_irqsave(&csi->irqlock, flags); in imx7_csi_dma_stop()
511 csi->last_eof = true; in imx7_csi_dma_stop()
512 spin_unlock_irqrestore(&csi->irqlock, flags); in imx7_csi_dma_stop()
518 ret = wait_for_completion_timeout(&csi->last_eof_completion, in imx7_csi_dma_stop()
521 v4l2_warn(&csi->sd, "wait last EOF timeout\n"); in imx7_csi_dma_stop()
523 imx7_csi_hw_disable_irq(csi); in imx7_csi_dma_stop()
526 static void imx7_csi_configure(struct imx7_csi *csi, in imx7_csi_configure() argument
529 struct v4l2_pix_format *out_pix = &csi->vdev_fmt; in imx7_csi_configure()
530 int width = out_pix->width; in imx7_csi_configure()
535 cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); in imx7_csi_configure()
542 if (out_pix->field == V4L2_FIELD_INTERLACED) { in imx7_csi_configure()
544 stride = out_pix->width; in imx7_csi_configure()
547 if (!csi->is_csi2) { in imx7_csi_configure()
554 if (out_pix->pixelformat == V4L2_PIX_FMT_UYVY || in imx7_csi_configure()
555 out_pix->pixelformat == V4L2_PIX_FMT_YUYV) in imx7_csi_configure()
568 switch (sink_fmt->code) { in imx7_csi_configure()
602 * The CSI bridge has a 16-bit input bus. Depending on the in imx7_csi_configure()
606 * then packed into a 32-bit FIFO (as shown in figure 13-11 of in imx7_csi_configure()
609 * The data packing in a 32-bit FIFO input word is controlled by in imx7_csi_configure()
612 * groups four 8-bit input samples (bits [9:2]). When set to 1, in imx7_csi_configure()
613 * data packing groups two 16-bit input samples (bits [15:0]). in imx7_csi_configure()
617 * The field controls the gasket between the CSI-2 receiver and in imx7_csi_configure()
618 * the CSI bridge. On i.MX7 and i.MX8MM, the field must be set in imx7_csi_configure()
619 * to 1 when the CSIS outputs 16-bit samples. On i.MX8MQ, the in imx7_csi_configure()
621 * uses 16-bit samples. Setting MIPI_DOUBLE_CMPNT in that case in imx7_csi_configure()
637 imx7_csi_reg_write(csi, cr1, CSI_CSICR1); in imx7_csi_configure()
638 imx7_csi_reg_write(csi, BIT_DMA_BURST_TYPE_RFF_INCR16, CSI_CSICR2); in imx7_csi_configure()
639 imx7_csi_reg_write(csi, cr3, CSI_CSICR3); in imx7_csi_configure()
640 imx7_csi_reg_write(csi, cr18, CSI_CSICR18); in imx7_csi_configure()
642 imx7_csi_reg_write(csi, (width * out_pix->height) >> 2, CSI_CSIRXCNT); in imx7_csi_configure()
643 imx7_csi_reg_write(csi, BIT_IMAGE_WIDTH(width) | in imx7_csi_configure()
644 BIT_IMAGE_HEIGHT(out_pix->height), in imx7_csi_configure()
646 imx7_csi_reg_write(csi, stride, CSI_CSIFBUF_PARA); in imx7_csi_configure()
649 static int imx7_csi_init(struct imx7_csi *csi, in imx7_csi_init() argument
654 ret = clk_prepare_enable(csi->mclk); in imx7_csi_init()
658 imx7_csi_configure(csi, sd_state); in imx7_csi_init()
660 ret = imx7_csi_dma_setup(csi); in imx7_csi_init()
662 clk_disable_unprepare(csi->mclk); in imx7_csi_init()
669 static void imx7_csi_deinit(struct imx7_csi *csi, in imx7_csi_deinit() argument
672 imx7_csi_dma_cleanup(csi, return_status); in imx7_csi_deinit()
673 imx7_csi_init_default(csi); in imx7_csi_deinit()
674 imx7_csi_dmareq_rff_disable(csi); in imx7_csi_deinit()
675 clk_disable_unprepare(csi->mclk); in imx7_csi_deinit()
678 static void imx7_csi_baseaddr_switch_on_second_frame(struct imx7_csi *csi) in imx7_csi_baseaddr_switch_on_second_frame() argument
680 u32 cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); in imx7_csi_baseaddr_switch_on_second_frame()
685 imx7_csi_reg_write(csi, cr18, CSI_CSICR18); in imx7_csi_baseaddr_switch_on_second_frame()
688 static void imx7_csi_enable(struct imx7_csi *csi) in imx7_csi_enable() argument
691 imx7_csi_rx_fifo_clear(csi); in imx7_csi_enable()
692 imx7_csi_dma_reflash(csi); in imx7_csi_enable()
697 imx7_csi_irq_clear(csi); in imx7_csi_enable()
698 imx7_csi_hw_enable_irq(csi); in imx7_csi_enable()
700 /* Enable the RxFIFO DMA and the CSI. */ in imx7_csi_enable()
701 imx7_csi_dmareq_rff_enable(csi); in imx7_csi_enable()
702 imx7_csi_hw_enable(csi); in imx7_csi_enable()
704 if (csi->model == IMX7_CSI_IMX8MQ) in imx7_csi_enable()
705 imx7_csi_baseaddr_switch_on_second_frame(csi); in imx7_csi_enable()
708 static void imx7_csi_disable(struct imx7_csi *csi) in imx7_csi_disable() argument
710 imx7_csi_dma_stop(csi); in imx7_csi_disable()
712 imx7_csi_dmareq_rff_disable(csi); in imx7_csi_disable()
714 imx7_csi_hw_disable_irq(csi); in imx7_csi_disable()
716 imx7_csi_hw_disable(csi); in imx7_csi_disable()
719 /* -----------------------------------------------------------------------------
723 static void imx7_csi_error_recovery(struct imx7_csi *csi) in imx7_csi_error_recovery() argument
725 imx7_csi_hw_disable(csi); in imx7_csi_error_recovery()
727 imx7_csi_rx_fifo_clear(csi); in imx7_csi_error_recovery()
729 imx7_csi_dma_reflash(csi); in imx7_csi_error_recovery()
731 imx7_csi_hw_enable(csi); in imx7_csi_error_recovery()
734 static void imx7_csi_vb2_buf_done(struct imx7_csi *csi) in imx7_csi_vb2_buf_done() argument
740 done = csi->active_vb2_buf[csi->buf_num]; in imx7_csi_vb2_buf_done()
742 done->vbuf.field = csi->vdev_fmt.field; in imx7_csi_vb2_buf_done()
743 done->vbuf.sequence = csi->frame_sequence; in imx7_csi_vb2_buf_done()
744 vb = &done->vbuf.vb2_buf; in imx7_csi_vb2_buf_done()
745 vb->timestamp = ktime_get_ns(); in imx7_csi_vb2_buf_done()
748 csi->frame_sequence++; in imx7_csi_vb2_buf_done()
751 next = imx7_csi_video_next_buf(csi); in imx7_csi_vb2_buf_done()
753 dma_addr = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0); in imx7_csi_vb2_buf_done()
754 csi->active_vb2_buf[csi->buf_num] = next; in imx7_csi_vb2_buf_done()
756 dma_addr = csi->underrun_buf.dma_addr; in imx7_csi_vb2_buf_done()
757 csi->active_vb2_buf[csi->buf_num] = NULL; in imx7_csi_vb2_buf_done()
760 imx7_csi_update_buf(csi, dma_addr, csi->buf_num); in imx7_csi_vb2_buf_done()
765 struct imx7_csi *csi = data; in imx7_csi_irq_handler() local
768 spin_lock(&csi->irqlock); in imx7_csi_irq_handler()
770 status = imx7_csi_irq_clear(csi); in imx7_csi_irq_handler()
773 dev_warn(csi->dev, "Rx fifo overflow\n"); in imx7_csi_irq_handler()
774 imx7_csi_error_recovery(csi); in imx7_csi_irq_handler()
778 dev_warn(csi->dev, "Hresponse error detected\n"); in imx7_csi_irq_handler()
779 imx7_csi_error_recovery(csi); in imx7_csi_irq_handler()
783 imx7_csi_hw_disable(csi); in imx7_csi_irq_handler()
785 imx7_csi_dma_reflash(csi); in imx7_csi_irq_handler()
787 imx7_csi_hw_enable(csi); in imx7_csi_irq_handler()
794 * CSI DMA is work in one of FB1 and FB2 buffer, in imx7_csi_irq_handler()
797 * when csi work in field0 and field1 will write to in imx7_csi_irq_handler()
801 csi->buf_num = 0; in imx7_csi_irq_handler()
803 csi->buf_num = 1; in imx7_csi_irq_handler()
808 imx7_csi_vb2_buf_done(csi); in imx7_csi_irq_handler()
810 if (csi->last_eof) { in imx7_csi_irq_handler()
811 complete(&csi->last_eof_completion); in imx7_csi_irq_handler()
812 csi->last_eof = false; in imx7_csi_irq_handler()
816 spin_unlock(&csi->irqlock); in imx7_csi_irq_handler()
821 /* -----------------------------------------------------------------------------
834 * The CSI bridge can be configured to sample pixel components from the Rx queue
840 * As the CSI bridge can be interfaced with different IP blocks depending on the
846 * Example: i.MX8MM SoC integrates the CSI bridge with the Samsung CSIS CSI-2
847 * receiver which operates in dual pixel sampling mode. The CSI bridge should
849 * pixel sampling mode. When the CSI bridge is instead integrated on an i.MX7,
970 if (fmt->fourcc == fourcc) in imx7_csi_find_pixel_format()
989 if (!fmt->codes) in imx7_csi_find_mbus_format()
992 for (j = 0; fmt->codes[j]; j++) { in imx7_csi_find_mbus_format()
993 if (code == fmt->codes[j]) in imx7_csi_find_mbus_format()
1003 * requested search criteria. Return the media-bus code that matches
1006 * @code: The returned media-bus code that matches the search criteria at
1018 if (!fmt->codes) in imx7_csi_enum_mbus_formats()
1021 for (j = 0; fmt->codes[j]; j++) { in imx7_csi_enum_mbus_formats()
1023 *code = fmt->codes[j]; in imx7_csi_enum_mbus_formats()
1027 index--; in imx7_csi_enum_mbus_formats()
1031 return -EINVAL; in imx7_csi_enum_mbus_formats()
1034 /* -----------------------------------------------------------------------------
1035 * Video Capture Device - IOCTLs
1041 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_querycap() local
1043 strscpy(cap->driver, IMX7_CSI_VIDEO_NAME, sizeof(cap->driver)); in imx7_csi_video_querycap()
1044 strscpy(cap->card, IMX7_CSI_VIDEO_NAME, sizeof(cap->card)); in imx7_csi_video_querycap()
1045 snprintf(cap->bus_info, sizeof(cap->bus_info), in imx7_csi_video_querycap()
1046 "platform:%s", dev_name(csi->dev)); in imx7_csi_video_querycap()
1054 unsigned int index = f->index; in imx7_csi_video_enum_fmt_vid_cap()
1064 if (f->mbus_code) { in imx7_csi_video_enum_fmt_vid_cap()
1067 if (!fmt->codes) in imx7_csi_video_enum_fmt_vid_cap()
1070 for (j = 0; fmt->codes[j]; j++) { in imx7_csi_video_enum_fmt_vid_cap()
1071 if (f->mbus_code == fmt->codes[j]) in imx7_csi_video_enum_fmt_vid_cap()
1075 if (!fmt->codes[j]) in imx7_csi_video_enum_fmt_vid_cap()
1080 f->pixelformat = fmt->fourcc; in imx7_csi_video_enum_fmt_vid_cap()
1084 index--; in imx7_csi_video_enum_fmt_vid_cap()
1087 return -EINVAL; in imx7_csi_video_enum_fmt_vid_cap()
1096 if (fsize->index > 0) in imx7_csi_video_enum_framesizes()
1097 return -EINVAL; in imx7_csi_video_enum_framesizes()
1099 cc = imx7_csi_find_pixel_format(fsize->pixel_format); in imx7_csi_video_enum_framesizes()
1101 return -EINVAL; in imx7_csi_video_enum_framesizes()
1107 walign = 8 * 8 / cc->bpp; in imx7_csi_video_enum_framesizes()
1109 fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; in imx7_csi_video_enum_framesizes()
1110 fsize->stepwise.min_width = walign; in imx7_csi_video_enum_framesizes()
1111 fsize->stepwise.max_width = round_down(65535U, walign); in imx7_csi_video_enum_framesizes()
1112 fsize->stepwise.min_height = 1; in imx7_csi_video_enum_framesizes()
1113 fsize->stepwise.max_height = 65535; in imx7_csi_video_enum_framesizes()
1114 fsize->stepwise.step_width = walign; in imx7_csi_video_enum_framesizes()
1115 fsize->stepwise.step_height = 1; in imx7_csi_video_enum_framesizes()
1123 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_g_fmt_vid_cap() local
1125 f->fmt.pix = csi->vdev_fmt; in imx7_csi_video_g_fmt_vid_cap()
1138 compose->width = pixfmt->width; in __imx7_csi_video_try_fmt()
1139 compose->height = pixfmt->height; in __imx7_csi_video_try_fmt()
1146 cc = imx7_csi_find_pixel_format(pixfmt->pixelformat); in __imx7_csi_video_try_fmt()
1148 pixfmt->pixelformat = IMX7_CSI_DEF_PIX_FORMAT; in __imx7_csi_video_try_fmt()
1149 cc = imx7_csi_find_pixel_format(pixfmt->pixelformat); in __imx7_csi_video_try_fmt()
1158 walign = 8 * 8 / cc->bpp; in __imx7_csi_video_try_fmt()
1159 pixfmt->width = clamp(round_up(pixfmt->width, walign), walign, in __imx7_csi_video_try_fmt()
1161 pixfmt->height = clamp(pixfmt->height, 1U, 65535U); in __imx7_csi_video_try_fmt()
1163 pixfmt->bytesperline = pixfmt->width * cc->bpp / 8; in __imx7_csi_video_try_fmt()
1164 pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; in __imx7_csi_video_try_fmt()
1165 pixfmt->field = V4L2_FIELD_NONE; in __imx7_csi_video_try_fmt()
1173 __imx7_csi_video_try_fmt(&f->fmt.pix, NULL); in imx7_csi_video_try_fmt_vid_cap()
1180 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_s_fmt_vid_cap() local
1183 if (vb2_is_busy(&csi->q)) { in imx7_csi_video_s_fmt_vid_cap()
1184 dev_err(csi->dev, "%s queue busy\n", __func__); in imx7_csi_video_s_fmt_vid_cap()
1185 return -EBUSY; in imx7_csi_video_s_fmt_vid_cap()
1188 cc = __imx7_csi_video_try_fmt(&f->fmt.pix, &csi->vdev_compose); in imx7_csi_video_s_fmt_vid_cap()
1190 csi->vdev_cc = cc; in imx7_csi_video_s_fmt_vid_cap()
1191 csi->vdev_fmt = f->fmt.pix; in imx7_csi_video_s_fmt_vid_cap()
1199 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_g_selection() local
1201 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) in imx7_csi_video_g_selection()
1202 return -EINVAL; in imx7_csi_video_g_selection()
1204 switch (s->target) { in imx7_csi_video_g_selection()
1209 s->r = csi->vdev_compose; in imx7_csi_video_g_selection()
1217 s->r.left = 0; in imx7_csi_video_g_selection()
1218 s->r.top = 0; in imx7_csi_video_g_selection()
1219 s->r.width = csi->vdev_fmt.width; in imx7_csi_video_g_selection()
1220 s->r.height = csi->vdev_fmt.height; in imx7_csi_video_g_selection()
1223 return -EINVAL; in imx7_csi_video_g_selection()
1252 /* -----------------------------------------------------------------------------
1253 * Video Capture Device - Queue Operations
1262 struct imx7_csi *csi = vb2_get_drv_priv(vq); in imx7_csi_video_queue_setup() local
1264 struct v4l2_pix_format *pix = &csi->vdev_fmt; in imx7_csi_video_queue_setup()
1267 if (vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) in imx7_csi_video_queue_setup()
1268 return -EINVAL; in imx7_csi_video_queue_setup()
1271 if (*nplanes != 1 || sizes[0] < pix->sizeimage) in imx7_csi_video_queue_setup()
1272 return -EINVAL; in imx7_csi_video_queue_setup()
1276 count = min_t(__u32, IMX7_CSI_VIDEO_MEM_LIMIT / pix->sizeimage, count); in imx7_csi_video_queue_setup()
1280 count - q_num_bufs; in imx7_csi_video_queue_setup()
1285 sizes[0] = pix->sizeimage; in imx7_csi_video_queue_setup()
1294 INIT_LIST_HEAD(&buf->list); in imx7_csi_video_buf_init()
1301 struct imx7_csi *csi = vb2_get_drv_priv(vb->vb2_queue); in imx7_csi_video_buf_prepare() local
1302 struct v4l2_pix_format *pix = &csi->vdev_fmt; in imx7_csi_video_buf_prepare()
1304 if (vb2_plane_size(vb, 0) < pix->sizeimage) { in imx7_csi_video_buf_prepare()
1305 dev_err(csi->dev, in imx7_csi_video_buf_prepare()
1307 vb2_plane_size(vb, 0), (long)pix->sizeimage); in imx7_csi_video_buf_prepare()
1308 return -EINVAL; in imx7_csi_video_buf_prepare()
1311 vb2_set_plane_payload(vb, 0, pix->sizeimage); in imx7_csi_video_buf_prepare()
1316 static bool imx7_csi_fast_track_buffer(struct imx7_csi *csi, in imx7_csi_fast_track_buffer() argument
1324 if (!csi->is_streaming) in imx7_csi_fast_track_buffer()
1327 dma_addr = vb2_dma_contig_plane_dma_addr(&buf->vbuf.vb2_buf, 0); in imx7_csi_fast_track_buffer()
1334 * being NULL), then we can fast-track the new buffer by programming in imx7_csi_fast_track_buffer()
1343 * by the interrupt handler for FB2. The fast-tracked buffer would in imx7_csi_fast_track_buffer()
1350 * raised. If that is not the case, fast-tracking succeeded, and we can in imx7_csi_fast_track_buffer()
1358 spin_lock_irqsave(&csi->irqlock, flags); in imx7_csi_fast_track_buffer()
1360 buf_num = csi->buf_num; in imx7_csi_fast_track_buffer()
1361 if (csi->active_vb2_buf[buf_num]) { in imx7_csi_fast_track_buffer()
1362 spin_unlock_irqrestore(&csi->irqlock, flags); in imx7_csi_fast_track_buffer()
1366 imx7_csi_update_buf(csi, dma_addr, buf_num); in imx7_csi_fast_track_buffer()
1368 isr = imx7_csi_reg_read(csi, CSI_CSISR); in imx7_csi_fast_track_buffer()
1379 spin_unlock_irqrestore(&csi->irqlock, flags); in imx7_csi_fast_track_buffer()
1383 csi->active_vb2_buf[buf_num] = buf; in imx7_csi_fast_track_buffer()
1385 spin_unlock_irqrestore(&csi->irqlock, flags); in imx7_csi_fast_track_buffer()
1391 struct imx7_csi *csi = vb2_get_drv_priv(vb->vb2_queue); in imx7_csi_video_buf_queue() local
1395 if (imx7_csi_fast_track_buffer(csi, buf)) in imx7_csi_video_buf_queue()
1398 spin_lock_irqsave(&csi->q_lock, flags); in imx7_csi_video_buf_queue()
1400 list_add_tail(&buf->list, &csi->ready_q); in imx7_csi_video_buf_queue()
1402 spin_unlock_irqrestore(&csi->q_lock, flags); in imx7_csi_video_buf_queue()
1405 static int imx7_csi_video_validate_fmt(struct imx7_csi *csi) in imx7_csi_video_validate_fmt() argument
1415 ret = v4l2_subdev_call_state_active(&csi->sd, pad, get_fmt, &fmt_src); in imx7_csi_video_validate_fmt()
1426 if (csi->vdev_compose.width != fmt_src.format.width || in imx7_csi_video_validate_fmt()
1427 csi->vdev_compose.height != fmt_src.format.height) in imx7_csi_video_validate_fmt()
1428 return -EPIPE; in imx7_csi_video_validate_fmt()
1435 if (!cc || csi->vdev_cc->yuv != cc->yuv) in imx7_csi_video_validate_fmt()
1436 return -EPIPE; in imx7_csi_video_validate_fmt()
1444 struct imx7_csi *csi = vb2_get_drv_priv(vq); in imx7_csi_video_start_streaming() local
1449 ret = imx7_csi_video_validate_fmt(csi); in imx7_csi_video_start_streaming()
1451 dev_err(csi->dev, "capture format not valid\n"); in imx7_csi_video_start_streaming()
1455 mutex_lock(&csi->mdev.graph_mutex); in imx7_csi_video_start_streaming()
1457 ret = __video_device_pipeline_start(csi->vdev, &csi->pipe); in imx7_csi_video_start_streaming()
1461 ret = v4l2_subdev_call(&csi->sd, video, s_stream, 1); in imx7_csi_video_start_streaming()
1465 mutex_unlock(&csi->mdev.graph_mutex); in imx7_csi_video_start_streaming()
1470 __video_device_pipeline_stop(csi->vdev); in imx7_csi_video_start_streaming()
1472 mutex_unlock(&csi->mdev.graph_mutex); in imx7_csi_video_start_streaming()
1473 dev_err(csi->dev, "pipeline start failed with %d\n", ret); in imx7_csi_video_start_streaming()
1475 spin_lock_irqsave(&csi->q_lock, flags); in imx7_csi_video_start_streaming()
1476 list_for_each_entry_safe(buf, tmp, &csi->ready_q, list) { in imx7_csi_video_start_streaming()
1477 list_del(&buf->list); in imx7_csi_video_start_streaming()
1478 vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); in imx7_csi_video_start_streaming()
1480 spin_unlock_irqrestore(&csi->q_lock, flags); in imx7_csi_video_start_streaming()
1486 struct imx7_csi *csi = vb2_get_drv_priv(vq); in imx7_csi_video_stop_streaming() local
1491 mutex_lock(&csi->mdev.graph_mutex); in imx7_csi_video_stop_streaming()
1492 v4l2_subdev_call(&csi->sd, video, s_stream, 0); in imx7_csi_video_stop_streaming()
1493 __video_device_pipeline_stop(csi->vdev); in imx7_csi_video_stop_streaming()
1494 mutex_unlock(&csi->mdev.graph_mutex); in imx7_csi_video_stop_streaming()
1497 spin_lock_irqsave(&csi->q_lock, flags); in imx7_csi_video_stop_streaming()
1498 list_for_each_entry_safe(frame, tmp, &csi->ready_q, list) { in imx7_csi_video_stop_streaming()
1499 list_del(&frame->list); in imx7_csi_video_stop_streaming()
1500 vb2_buffer_done(&frame->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); in imx7_csi_video_stop_streaming()
1502 spin_unlock_irqrestore(&csi->q_lock, flags); in imx7_csi_video_stop_streaming()
1516 /* -----------------------------------------------------------------------------
1517 * Video Capture Device - File Operations
1522 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_open() local
1525 if (mutex_lock_interruptible(&csi->vdev_mutex)) in imx7_csi_video_open()
1526 return -ERESTARTSYS; in imx7_csi_video_open()
1530 dev_err(csi->dev, "v4l2_fh_open failed\n"); in imx7_csi_video_open()
1534 ret = v4l2_pipeline_pm_get(&csi->vdev->entity); in imx7_csi_video_open()
1539 mutex_unlock(&csi->vdev_mutex); in imx7_csi_video_open()
1545 struct imx7_csi *csi = video_drvdata(file); in imx7_csi_video_release() local
1546 struct vb2_queue *vq = &csi->q; in imx7_csi_video_release()
1548 mutex_lock(&csi->vdev_mutex); in imx7_csi_video_release()
1550 if (file->private_data == vq->owner) { in imx7_csi_video_release()
1552 vq->owner = NULL; in imx7_csi_video_release()
1555 v4l2_pipeline_pm_put(&csi->vdev->entity); in imx7_csi_video_release()
1558 mutex_unlock(&csi->vdev_mutex); in imx7_csi_video_release()
1571 /* -----------------------------------------------------------------------------
1572 * Video Capture Device - Init & Cleanup
1575 static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi) in imx7_csi_video_next_buf() argument
1580 spin_lock_irqsave(&csi->q_lock, flags); in imx7_csi_video_next_buf()
1583 if (!list_empty(&csi->ready_q)) { in imx7_csi_video_next_buf()
1584 buf = list_entry(csi->ready_q.next, struct imx7_csi_vb2_buffer, in imx7_csi_video_next_buf()
1586 list_del(&buf->list); in imx7_csi_video_next_buf()
1589 spin_unlock_irqrestore(&csi->q_lock, flags); in imx7_csi_video_next_buf()
1594 static void imx7_csi_video_init_format(struct imx7_csi *csi) in imx7_csi_video_init_format() argument
1596 struct v4l2_pix_format *pixfmt = &csi->vdev_fmt; in imx7_csi_video_init_format()
1598 pixfmt->width = IMX7_CSI_DEF_PIX_WIDTH; in imx7_csi_video_init_format()
1599 pixfmt->height = IMX7_CSI_DEF_PIX_HEIGHT; in imx7_csi_video_init_format()
1601 csi->vdev_cc = __imx7_csi_video_try_fmt(pixfmt, &csi->vdev_compose); in imx7_csi_video_init_format()
1604 static int imx7_csi_video_register(struct imx7_csi *csi) in imx7_csi_video_register() argument
1606 struct v4l2_subdev *sd = &csi->sd; in imx7_csi_video_register()
1607 struct v4l2_device *v4l2_dev = sd->v4l2_dev; in imx7_csi_video_register()
1608 struct video_device *vdev = csi->vdev; in imx7_csi_video_register()
1611 vdev->v4l2_dev = v4l2_dev; in imx7_csi_video_register()
1614 imx7_csi_video_init_format(csi); in imx7_csi_video_register()
1617 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); in imx7_csi_video_register()
1619 dev_err(csi->dev, "Failed to register video device\n"); in imx7_csi_video_register()
1623 dev_info(csi->dev, "Registered %s as /dev/%s\n", vdev->name, in imx7_csi_video_register()
1626 /* Create the link from the CSI subdev to the video device. */ in imx7_csi_video_register()
1627 ret = media_create_pad_link(&sd->entity, IMX7_CSI_PAD_SRC, in imx7_csi_video_register()
1628 &vdev->entity, 0, MEDIA_LNK_FL_IMMUTABLE | in imx7_csi_video_register()
1631 dev_err(csi->dev, "failed to create link to device node\n"); in imx7_csi_video_register()
1639 static void imx7_csi_video_unregister(struct imx7_csi *csi) in imx7_csi_video_unregister() argument
1641 media_entity_cleanup(&csi->vdev->entity); in imx7_csi_video_unregister()
1642 video_unregister_device(csi->vdev); in imx7_csi_video_unregister()
1645 static int imx7_csi_video_init(struct imx7_csi *csi) in imx7_csi_video_init() argument
1651 mutex_init(&csi->vdev_mutex); in imx7_csi_video_init()
1652 INIT_LIST_HEAD(&csi->ready_q); in imx7_csi_video_init()
1653 spin_lock_init(&csi->q_lock); in imx7_csi_video_init()
1658 return -ENOMEM; in imx7_csi_video_init()
1660 vdev->fops = &imx7_csi_video_fops; in imx7_csi_video_init()
1661 vdev->ioctl_ops = &imx7_csi_video_ioctl_ops; in imx7_csi_video_init()
1662 vdev->minor = -1; in imx7_csi_video_init()
1663 vdev->release = video_device_release; in imx7_csi_video_init()
1664 vdev->vfl_dir = VFL_DIR_RX; in imx7_csi_video_init()
1665 vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; in imx7_csi_video_init()
1666 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING in imx7_csi_video_init()
1668 vdev->lock = &csi->vdev_mutex; in imx7_csi_video_init()
1669 vdev->queue = &csi->q; in imx7_csi_video_init()
1671 snprintf(vdev->name, sizeof(vdev->name), "%s capture", csi->sd.name); in imx7_csi_video_init()
1673 video_set_drvdata(vdev, csi); in imx7_csi_video_init()
1674 csi->vdev = vdev; in imx7_csi_video_init()
1677 csi->vdev_pad.flags = MEDIA_PAD_FL_SINK; in imx7_csi_video_init()
1678 ret = media_entity_pads_init(&vdev->entity, 1, &csi->vdev_pad); in imx7_csi_video_init()
1685 vq = &csi->q; in imx7_csi_video_init()
1686 vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; in imx7_csi_video_init()
1687 vq->io_modes = VB2_MMAP | VB2_DMABUF; in imx7_csi_video_init()
1688 vq->drv_priv = csi; in imx7_csi_video_init()
1689 vq->buf_struct_size = sizeof(struct imx7_csi_vb2_buffer); in imx7_csi_video_init()
1690 vq->ops = &imx7_csi_video_qops; in imx7_csi_video_init()
1691 vq->mem_ops = &vb2_dma_contig_memops; in imx7_csi_video_init()
1692 vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; in imx7_csi_video_init()
1693 vq->lock = &csi->vdev_mutex; in imx7_csi_video_init()
1694 vq->min_queued_buffers = 2; in imx7_csi_video_init()
1695 vq->dev = csi->dev; in imx7_csi_video_init()
1699 dev_err(csi->dev, "vb2_queue_init failed\n"); in imx7_csi_video_init()
1707 /* -----------------------------------------------------------------------------
1713 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_s_stream() local
1720 ret = imx7_csi_init(csi, sd_state); in imx7_csi_s_stream()
1724 ret = v4l2_subdev_call(csi->src_sd, video, s_stream, 1); in imx7_csi_s_stream()
1726 imx7_csi_deinit(csi, VB2_BUF_STATE_QUEUED); in imx7_csi_s_stream()
1730 imx7_csi_enable(csi); in imx7_csi_s_stream()
1732 imx7_csi_disable(csi); in imx7_csi_s_stream()
1734 v4l2_subdev_call(csi->src_sd, video, s_stream, 0); in imx7_csi_s_stream()
1736 imx7_csi_deinit(csi, VB2_BUF_STATE_ERROR); in imx7_csi_s_stream()
1739 csi->is_streaming = !!enable; in imx7_csi_s_stream()
1759 mf->code = IMX7_CSI_DEF_MBUS_CODE; in imx7_csi_init_state()
1760 mf->width = IMX7_CSI_DEF_PIX_WIDTH; in imx7_csi_init_state()
1761 mf->height = IMX7_CSI_DEF_PIX_HEIGHT; in imx7_csi_init_state()
1762 mf->field = V4L2_FIELD_NONE; in imx7_csi_init_state()
1764 mf->colorspace = V4L2_COLORSPACE_SRGB; in imx7_csi_init_state()
1765 mf->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mf->colorspace); in imx7_csi_init_state()
1766 mf->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mf->colorspace); in imx7_csi_init_state()
1767 mf->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!cc->yuv, in imx7_csi_init_state()
1768 mf->colorspace, mf->ycbcr_enc); in imx7_csi_init_state()
1783 switch (code->pad) { in imx7_csi_enum_mbus_code()
1785 ret = imx7_csi_enum_mbus_formats(&code->code, code->index); in imx7_csi_enum_mbus_code()
1789 if (code->index != 0) { in imx7_csi_enum_mbus_code()
1790 ret = -EINVAL; in imx7_csi_enum_mbus_code()
1794 code->code = in_fmt->code; in imx7_csi_enum_mbus_code()
1798 ret = -EINVAL; in imx7_csi_enum_mbus_code()
1810 * tryfmt->code must be set on entry.
1817 cc = imx7_csi_find_mbus_format(tryfmt->code); in imx7_csi_try_colorimetry()
1818 if (cc && !cc->yuv) in imx7_csi_try_colorimetry()
1821 switch (tryfmt->colorspace) { in imx7_csi_try_colorimetry()
1832 tryfmt->colorspace = V4L2_COLORSPACE_SRGB; in imx7_csi_try_colorimetry()
1836 if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT) in imx7_csi_try_colorimetry()
1837 tryfmt->xfer_func = in imx7_csi_try_colorimetry()
1838 V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace); in imx7_csi_try_colorimetry()
1840 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) in imx7_csi_try_colorimetry()
1841 tryfmt->ycbcr_enc = in imx7_csi_try_colorimetry()
1842 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace); in imx7_csi_try_colorimetry()
1844 if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT) in imx7_csi_try_colorimetry()
1845 tryfmt->quantization = in imx7_csi_try_colorimetry()
1847 tryfmt->colorspace, in imx7_csi_try_colorimetry()
1848 tryfmt->ycbcr_enc); in imx7_csi_try_colorimetry()
1862 switch (sdformat->pad) { in imx7_csi_try_fmt()
1864 in_cc = imx7_csi_find_mbus_format(in_fmt->code); in imx7_csi_try_fmt()
1866 sdformat->format.width = in_fmt->width; in imx7_csi_try_fmt()
1867 sdformat->format.height = in_fmt->height; in imx7_csi_try_fmt()
1868 sdformat->format.code = in_fmt->code; in imx7_csi_try_fmt()
1869 sdformat->format.field = in_fmt->field; in imx7_csi_try_fmt()
1872 sdformat->format.colorspace = in_fmt->colorspace; in imx7_csi_try_fmt()
1873 sdformat->format.xfer_func = in_fmt->xfer_func; in imx7_csi_try_fmt()
1874 sdformat->format.quantization = in_fmt->quantization; in imx7_csi_try_fmt()
1875 sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc; in imx7_csi_try_fmt()
1879 *cc = imx7_csi_find_mbus_format(sdformat->format.code); in imx7_csi_try_fmt()
1883 sdformat->format.code = code; in imx7_csi_try_fmt()
1886 if (sdformat->format.field != V4L2_FIELD_INTERLACED) in imx7_csi_try_fmt()
1887 sdformat->format.field = V4L2_FIELD_NONE; in imx7_csi_try_fmt()
1891 imx7_csi_try_colorimetry(&sdformat->format); in imx7_csi_try_fmt()
1898 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_set_fmt() local
1905 if (csi->is_streaming) in imx7_csi_set_fmt()
1906 return -EBUSY; in imx7_csi_set_fmt()
1910 fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad); in imx7_csi_set_fmt()
1912 *fmt = sdformat->format; in imx7_csi_set_fmt()
1914 if (sdformat->pad == IMX7_CSI_PAD_SINK) { in imx7_csi_set_fmt()
1917 format.which = sdformat->which; in imx7_csi_set_fmt()
1918 format.format = sdformat->format; in imx7_csi_set_fmt()
1934 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_pad_link_validate() local
1941 * parallel input or the CSI-2 receiver. in imx7_csi_pad_link_validate()
1947 switch (csi->src_sd->entity.function) { in imx7_csi_pad_link_validate()
1949 /* The input is the CSI-2 receiver. */ in imx7_csi_pad_link_validate()
1950 csi->is_csi2 = true; in imx7_csi_pad_link_validate()
1955 for (i = 0; i < csi->src_sd->entity.num_pads; i++) { in imx7_csi_pad_link_validate()
1956 struct media_pad *spad = &csi->src_sd->entity.pads[i]; in imx7_csi_pad_link_validate()
1958 if (!(spad->flags & MEDIA_PAD_FL_SINK)) in imx7_csi_pad_link_validate()
1967 return -ENODEV; in imx7_csi_pad_link_validate()
1969 csi->is_csi2 = pad->entity->function == MEDIA_ENT_F_VID_IF_BRIDGE; in imx7_csi_pad_link_validate()
1977 csi->is_csi2 = false; in imx7_csi_pad_link_validate()
1986 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_registered() local
1989 ret = imx7_csi_video_init(csi); in imx7_csi_registered()
1993 ret = imx7_csi_video_register(csi); in imx7_csi_registered()
1997 ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); in imx7_csi_registered()
2001 ret = media_device_register(&csi->mdev); in imx7_csi_registered()
2008 imx7_csi_video_unregister(csi); in imx7_csi_registered()
2014 struct imx7_csi *csi = v4l2_get_subdevdata(sd); in imx7_csi_unregistered() local
2016 imx7_csi_video_unregister(csi); in imx7_csi_unregistered()
2041 /* -----------------------------------------------------------------------------
2050 /* -----------------------------------------------------------------------------
2058 struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier); in imx7_csi_notify_bound() local
2059 struct media_pad *sink = &csi->sd.entity.pads[IMX7_CSI_PAD_SINK]; in imx7_csi_notify_bound()
2061 csi->src_sd = sd; in imx7_csi_notify_bound()
2069 struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier); in imx7_csi_notify_complete() local
2071 return v4l2_device_register_subdev_nodes(&csi->v4l2_dev); in imx7_csi_notify_complete()
2079 static int imx7_csi_async_register(struct imx7_csi *csi) in imx7_csi_async_register() argument
2085 v4l2_async_nf_init(&csi->notifier, &csi->v4l2_dev); in imx7_csi_async_register()
2087 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0, in imx7_csi_async_register()
2090 ret = dev_err_probe(csi->dev, -ENOTCONN, in imx7_csi_async_register()
2095 asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep, in imx7_csi_async_register()
2101 ret = dev_err_probe(csi->dev, PTR_ERR(asd), in imx7_csi_async_register()
2106 csi->notifier.ops = &imx7_csi_notify_ops; in imx7_csi_async_register()
2108 ret = v4l2_async_nf_register(&csi->notifier); in imx7_csi_async_register()
2115 v4l2_async_nf_cleanup(&csi->notifier); in imx7_csi_async_register()
2119 static void imx7_csi_media_cleanup(struct imx7_csi *csi) in imx7_csi_media_cleanup() argument
2121 v4l2_device_unregister(&csi->v4l2_dev); in imx7_csi_media_cleanup()
2122 media_device_unregister(&csi->mdev); in imx7_csi_media_cleanup()
2123 v4l2_subdev_cleanup(&csi->sd); in imx7_csi_media_cleanup()
2124 media_device_cleanup(&csi->mdev); in imx7_csi_media_cleanup()
2131 static int imx7_csi_media_dev_init(struct imx7_csi *csi) in imx7_csi_media_dev_init() argument
2135 strscpy(csi->mdev.model, "imx-media", sizeof(csi->mdev.model)); in imx7_csi_media_dev_init()
2136 csi->mdev.ops = &imx7_csi_media_ops; in imx7_csi_media_dev_init()
2137 csi->mdev.dev = csi->dev; in imx7_csi_media_dev_init()
2139 csi->v4l2_dev.mdev = &csi->mdev; in imx7_csi_media_dev_init()
2140 strscpy(csi->v4l2_dev.name, "imx-media", in imx7_csi_media_dev_init()
2141 sizeof(csi->v4l2_dev.name)); in imx7_csi_media_dev_init()
2142 snprintf(csi->mdev.bus_info, sizeof(csi->mdev.bus_info), in imx7_csi_media_dev_init()
2143 "platform:%s", dev_name(csi->mdev.dev)); in imx7_csi_media_dev_init()
2145 media_device_init(&csi->mdev); in imx7_csi_media_dev_init()
2147 ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); in imx7_csi_media_dev_init()
2149 v4l2_err(&csi->v4l2_dev, in imx7_csi_media_dev_init()
2157 media_device_cleanup(&csi->mdev); in imx7_csi_media_dev_init()
2162 static int imx7_csi_media_init(struct imx7_csi *csi) in imx7_csi_media_init() argument
2168 ret = imx7_csi_media_dev_init(csi); in imx7_csi_media_init()
2172 v4l2_subdev_init(&csi->sd, &imx7_csi_subdev_ops); in imx7_csi_media_init()
2173 v4l2_set_subdevdata(&csi->sd, csi); in imx7_csi_media_init()
2174 csi->sd.internal_ops = &imx7_csi_internal_ops; in imx7_csi_media_init()
2175 csi->sd.entity.ops = &imx7_csi_entity_ops; in imx7_csi_media_init()
2176 csi->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; in imx7_csi_media_init()
2177 csi->sd.dev = csi->dev; in imx7_csi_media_init()
2178 csi->sd.owner = THIS_MODULE; in imx7_csi_media_init()
2179 csi->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; in imx7_csi_media_init()
2180 snprintf(csi->sd.name, sizeof(csi->sd.name), "csi"); in imx7_csi_media_init()
2183 csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ? in imx7_csi_media_init()
2186 ret = media_entity_pads_init(&csi->sd.entity, IMX7_CSI_PADS_NUM, in imx7_csi_media_init()
2187 csi->pad); in imx7_csi_media_init()
2191 ret = v4l2_subdev_init_finalize(&csi->sd); in imx7_csi_media_init()
2195 ret = v4l2_device_register_subdev(&csi->v4l2_dev, &csi->sd); in imx7_csi_media_init()
2202 imx7_csi_media_cleanup(csi); in imx7_csi_media_init()
2208 struct device *dev = &pdev->dev; in imx7_csi_probe()
2209 struct imx7_csi *csi; in imx7_csi_probe() local
2212 csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); in imx7_csi_probe()
2213 if (!csi) in imx7_csi_probe()
2214 return -ENOMEM; in imx7_csi_probe()
2216 csi->dev = dev; in imx7_csi_probe()
2217 platform_set_drvdata(pdev, csi); in imx7_csi_probe()
2219 spin_lock_init(&csi->irqlock); in imx7_csi_probe()
2222 csi->mclk = devm_clk_get(&pdev->dev, "mclk"); in imx7_csi_probe()
2223 if (IS_ERR(csi->mclk)) { in imx7_csi_probe()
2224 ret = PTR_ERR(csi->mclk); in imx7_csi_probe()
2229 csi->irq = platform_get_irq(pdev, 0); in imx7_csi_probe()
2230 if (csi->irq < 0) in imx7_csi_probe()
2231 return csi->irq; in imx7_csi_probe()
2233 csi->regbase = devm_platform_ioremap_resource(pdev, 0); in imx7_csi_probe()
2234 if (IS_ERR(csi->regbase)) in imx7_csi_probe()
2235 return PTR_ERR(csi->regbase); in imx7_csi_probe()
2237 csi->model = (enum imx_csi_model)(uintptr_t)of_device_get_match_data(&pdev->dev); in imx7_csi_probe()
2239 ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi", in imx7_csi_probe()
2240 (void *)csi); in imx7_csi_probe()
2242 dev_err(dev, "Request CSI IRQ failed.\n"); in imx7_csi_probe()
2247 ret = imx7_csi_media_init(csi); in imx7_csi_probe()
2251 ret = imx7_csi_async_register(csi); in imx7_csi_probe()
2258 imx7_csi_media_cleanup(csi); in imx7_csi_probe()
2265 struct imx7_csi *csi = platform_get_drvdata(pdev); in imx7_csi_remove() local
2267 imx7_csi_media_cleanup(csi); in imx7_csi_remove()
2269 v4l2_async_nf_unregister(&csi->notifier); in imx7_csi_remove()
2270 v4l2_async_nf_cleanup(&csi->notifier); in imx7_csi_remove()
2271 v4l2_async_unregister_subdev(&csi->sd); in imx7_csi_remove()
2275 { .compatible = "fsl,imx8mq-csi", .data = (void *)IMX7_CSI_IMX8MQ },
2276 { .compatible = "fsl,imx7-csi", .data = (void *)IMX7_CSI_IMX7 },
2277 { .compatible = "fsl,imx6ul-csi", .data = (void *)IMX7_CSI_IMX7 },
2287 .name = "imx7-csi",
2292 MODULE_DESCRIPTION("i.MX7 CSI subdev driver");
2295 MODULE_ALIAS("platform:imx7-csi");