Lines Matching +full:csi +full:- +full:2
1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
8 * Author: Jai Luthra <j-luthra@ti.com>
17 #include <media/mipi-csi2.h>
18 #include <media/v4l2-device.h>
19 #include <media/v4l2-ioctl.h>
20 #include <media/v4l2-mc.h>
21 #include <media/videobuf2-dma-contig.h>
23 #define TI_CSI2RX_MODULE_NAME "j721e-csi2rx"
36 #define SHIM_DMACNTX_SIZE_32 2
58 u32 csi_dt; /* CSI Data type. */
67 struct ti_csi2rx_dev *csi; member
87 /* Buffer to drain stale data from PSI-L endpoint */
191 static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi,
221 struct v4l2_pix_format *pix = &v4l2_fmt->fmt.pix; in ti_csi2rx_fill_fmt()
224 pixels_in_word = PSIL_WORD_SIZE_BYTES * 8 / csi_fmt->bpp; in ti_csi2rx_fill_fmt()
227 pix->width = clamp_t(unsigned int, pix->width, in ti_csi2rx_fill_fmt()
229 MAX_WIDTH_BYTES * 8 / csi_fmt->bpp); in ti_csi2rx_fill_fmt()
230 pix->height = clamp_t(unsigned int, pix->height, 1, MAX_HEIGHT_LINES); in ti_csi2rx_fill_fmt()
232 /* Width should be a multiple of transfer word-size */ in ti_csi2rx_fill_fmt()
233 pix->width = rounddown(pix->width, pixels_in_word); in ti_csi2rx_fill_fmt()
235 v4l2_fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; in ti_csi2rx_fill_fmt()
236 pix->pixelformat = csi_fmt->fourcc; in ti_csi2rx_fill_fmt()
237 pix->bytesperline = pix->width * (csi_fmt->bpp / 8); in ti_csi2rx_fill_fmt()
238 pix->sizeimage = pix->bytesperline * pix->height; in ti_csi2rx_fill_fmt()
244 strscpy(cap->driver, TI_CSI2RX_MODULE_NAME, sizeof(cap->driver)); in ti_csi2rx_querycap()
245 strscpy(cap->card, TI_CSI2RX_MODULE_NAME, sizeof(cap->card)); in ti_csi2rx_querycap()
255 if (f->mbus_code) { in ti_csi2rx_enum_fmt_vid_cap()
256 /* 1-to-1 mapping between bus formats and pixel formats */ in ti_csi2rx_enum_fmt_vid_cap()
257 if (f->index > 0) in ti_csi2rx_enum_fmt_vid_cap()
258 return -EINVAL; in ti_csi2rx_enum_fmt_vid_cap()
260 fmt = find_format_by_code(f->mbus_code); in ti_csi2rx_enum_fmt_vid_cap()
262 if (f->index >= ARRAY_SIZE(ti_csi2rx_formats)) in ti_csi2rx_enum_fmt_vid_cap()
263 return -EINVAL; in ti_csi2rx_enum_fmt_vid_cap()
265 fmt = &ti_csi2rx_formats[f->index]; in ti_csi2rx_enum_fmt_vid_cap()
269 return -EINVAL; in ti_csi2rx_enum_fmt_vid_cap()
271 f->pixelformat = fmt->fourcc; in ti_csi2rx_enum_fmt_vid_cap()
272 memset(f->reserved, 0, sizeof(f->reserved)); in ti_csi2rx_enum_fmt_vid_cap()
273 f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; in ti_csi2rx_enum_fmt_vid_cap()
281 struct ti_csi2rx_dev *csi = video_drvdata(file); in ti_csi2rx_g_fmt_vid_cap() local
283 *f = csi->v_fmt; in ti_csi2rx_g_fmt_vid_cap()
297 fmt = find_format_by_fourcc(f->fmt.pix.pixelformat); in ti_csi2rx_try_fmt_vid_cap()
302 f->fmt.pix.field = V4L2_FIELD_NONE; in ti_csi2rx_try_fmt_vid_cap()
312 struct ti_csi2rx_dev *csi = video_drvdata(file); in ti_csi2rx_s_fmt_vid_cap() local
313 struct vb2_queue *q = &csi->vidq; in ti_csi2rx_s_fmt_vid_cap()
317 return -EBUSY; in ti_csi2rx_s_fmt_vid_cap()
323 csi->v_fmt = *f; in ti_csi2rx_s_fmt_vid_cap()
334 fmt = find_format_by_fourcc(fsize->pixel_format); in ti_csi2rx_enum_framesizes()
335 if (!fmt || fsize->index != 0) in ti_csi2rx_enum_framesizes()
336 return -EINVAL; in ti_csi2rx_enum_framesizes()
339 * Number of pixels in one PSI-L word. The transfer happens in multiples in ti_csi2rx_enum_framesizes()
340 * of PSI-L word sizes. in ti_csi2rx_enum_framesizes()
342 pixels_in_word = PSIL_WORD_SIZE_BYTES * 8 / fmt->bpp; in ti_csi2rx_enum_framesizes()
344 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; in ti_csi2rx_enum_framesizes()
345 fsize->stepwise.min_width = pixels_in_word; in ti_csi2rx_enum_framesizes()
346 fsize->stepwise.max_width = rounddown(MAX_WIDTH_BYTES * 8 / fmt->bpp, in ti_csi2rx_enum_framesizes()
348 fsize->stepwise.step_width = pixels_in_word; in ti_csi2rx_enum_framesizes()
349 fsize->stepwise.min_height = 1; in ti_csi2rx_enum_framesizes()
350 fsize->stepwise.max_height = MAX_HEIGHT_LINES; in ti_csi2rx_enum_framesizes()
351 fsize->stepwise.step_height = 1; in ti_csi2rx_enum_framesizes()
388 struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); in csi_async_notifier_bound() local
390 csi->source = subdev; in csi_async_notifier_bound()
397 struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); in csi_async_notifier_complete() local
398 struct video_device *vdev = &csi->vdev; in csi_async_notifier_complete()
401 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); in csi_async_notifier_complete()
405 ret = v4l2_create_fwnode_links_to_pad(csi->source, &csi->pad, in csi_async_notifier_complete()
413 ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); in csi_async_notifier_complete()
425 static int ti_csi2rx_notifier_register(struct ti_csi2rx_dev *csi) in ti_csi2rx_notifier_register() argument
432 node = of_get_child_by_name(csi->dev->of_node, "csi-bridge"); in ti_csi2rx_notifier_register()
434 return -EINVAL; in ti_csi2rx_notifier_register()
439 return -EINVAL; in ti_csi2rx_notifier_register()
442 v4l2_async_nf_init(&csi->notifier, &csi->v4l2_dev); in ti_csi2rx_notifier_register()
443 csi->notifier.ops = &csi_async_notifier_ops; in ti_csi2rx_notifier_register()
445 asc = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode, in ti_csi2rx_notifier_register()
449 v4l2_async_nf_cleanup(&csi->notifier); in ti_csi2rx_notifier_register()
453 ret = v4l2_async_nf_register(&csi->notifier); in ti_csi2rx_notifier_register()
455 v4l2_async_nf_cleanup(&csi->notifier); in ti_csi2rx_notifier_register()
462 static void ti_csi2rx_setup_shim(struct ti_csi2rx_dev *csi) in ti_csi2rx_setup_shim() argument
467 fmt = find_format_by_fourcc(csi->v_fmt.fmt.pix.pixelformat); in ti_csi2rx_setup_shim()
469 /* De-assert the pixel interface reset. */ in ti_csi2rx_setup_shim()
471 writel(reg, csi->shim + SHIM_CNTL); in ti_csi2rx_setup_shim()
474 reg |= FIELD_PREP(SHIM_DMACNTX_FMT, fmt->csi_dt); in ti_csi2rx_setup_shim()
477 * The hardware assumes incoming YUV422 8-bit data on MIPI CSI2 bus in ti_csi2rx_setup_shim()
478 * follows the spec and is packed in the order U0 -> Y0 -> V0 -> Y1 -> in ti_csi2rx_setup_shim()
484 * Byte3 <----------- Byte0 in ti_csi2rx_setup_shim()
494 switch (fmt->fourcc) { in ti_csi2rx_setup_shim()
503 /* Ignore if not YUV 4:2:2 */ in ti_csi2rx_setup_shim()
507 reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, fmt->size); in ti_csi2rx_setup_shim()
509 writel(reg, csi->shim + SHIM_DMACNTX); in ti_csi2rx_setup_shim()
513 writel(reg, csi->shim + SHIM_PSI_CFG0); in ti_csi2rx_setup_shim()
524 * Drain the stale data left at the PSI-L endpoint.
527 * streaming. In multi-stream scenarios this can happen when one stream is
528 * stopped but other is still streaming, and thus module-level pixel reset is
534 static int ti_csi2rx_drain_dma(struct ti_csi2rx_dev *csi) in ti_csi2rx_drain_dma() argument
543 desc = dmaengine_prep_slave_single(csi->dma.chan, csi->dma.drain.paddr, in ti_csi2rx_drain_dma()
544 csi->dma.drain.len, DMA_DEV_TO_MEM, in ti_csi2rx_drain_dma()
547 ret = -EIO; in ti_csi2rx_drain_dma()
551 desc->callback = ti_csi2rx_drain_callback; in ti_csi2rx_drain_dma()
552 desc->callback_param = &drain_complete; in ti_csi2rx_drain_dma()
559 dma_async_issue_pending(csi->dma.chan); in ti_csi2rx_drain_dma()
563 dmaengine_terminate_sync(csi->dma.chan); in ti_csi2rx_drain_dma()
564 dev_dbg(csi->dev, "DMA transfer timed out for drain buffer\n"); in ti_csi2rx_drain_dma()
565 ret = -ETIMEDOUT; in ti_csi2rx_drain_dma()
575 struct ti_csi2rx_dev *csi = buf->csi; in ti_csi2rx_dma_callback() local
576 struct ti_csi2rx_dma *dma = &csi->dma; in ti_csi2rx_dma_callback()
583 buf->vb.vb2_buf.timestamp = ktime_get_ns(); in ti_csi2rx_dma_callback()
584 buf->vb.sequence = csi->sequence++; in ti_csi2rx_dma_callback()
586 spin_lock_irqsave(&dma->lock, flags); in ti_csi2rx_dma_callback()
588 WARN_ON(!list_is_first(&buf->list, &dma->submitted)); in ti_csi2rx_dma_callback()
589 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); in ti_csi2rx_dma_callback()
590 list_del(&buf->list); in ti_csi2rx_dma_callback()
593 while (!list_empty(&dma->queue)) { in ti_csi2rx_dma_callback()
594 buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); in ti_csi2rx_dma_callback()
596 if (ti_csi2rx_start_dma(csi, buf)) { in ti_csi2rx_dma_callback()
597 dev_err(csi->dev, "Failed to queue the next buffer for DMA\n"); in ti_csi2rx_dma_callback()
598 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); in ti_csi2rx_dma_callback()
600 list_move_tail(&buf->list, &dma->submitted); in ti_csi2rx_dma_callback()
604 if (list_empty(&dma->submitted)) in ti_csi2rx_dma_callback()
605 dma->state = TI_CSI2RX_DMA_IDLE; in ti_csi2rx_dma_callback()
607 spin_unlock_irqrestore(&dma->lock, flags); in ti_csi2rx_dma_callback()
610 static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi, in ti_csi2rx_start_dma() argument
615 size_t len = csi->v_fmt.fmt.pix.sizeimage; in ti_csi2rx_start_dma()
619 addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); in ti_csi2rx_start_dma()
620 desc = dmaengine_prep_slave_single(csi->dma.chan, addr, len, in ti_csi2rx_start_dma()
624 return -EIO; in ti_csi2rx_start_dma()
626 desc->callback = ti_csi2rx_dma_callback; in ti_csi2rx_start_dma()
627 desc->callback_param = buf; in ti_csi2rx_start_dma()
634 dma_async_issue_pending(csi->dma.chan); in ti_csi2rx_start_dma()
639 static void ti_csi2rx_stop_dma(struct ti_csi2rx_dev *csi) in ti_csi2rx_stop_dma() argument
641 struct ti_csi2rx_dma *dma = &csi->dma; in ti_csi2rx_stop_dma()
646 spin_lock_irqsave(&dma->lock, flags); in ti_csi2rx_stop_dma()
647 state = csi->dma.state; in ti_csi2rx_stop_dma()
648 dma->state = TI_CSI2RX_DMA_STOPPED; in ti_csi2rx_stop_dma()
649 spin_unlock_irqrestore(&dma->lock, flags); in ti_csi2rx_stop_dma()
655 * is stopped, as the module-level pixel reset cannot be in ti_csi2rx_stop_dma()
658 ret = ti_csi2rx_drain_dma(csi); in ti_csi2rx_stop_dma()
659 if (ret && ret != -ETIMEDOUT) in ti_csi2rx_stop_dma()
660 dev_warn(csi->dev, in ti_csi2rx_stop_dma()
664 ret = dmaengine_terminate_sync(csi->dma.chan); in ti_csi2rx_stop_dma()
666 dev_err(csi->dev, "Failed to stop DMA: %d\n", ret); in ti_csi2rx_stop_dma()
669 static void ti_csi2rx_cleanup_buffers(struct ti_csi2rx_dev *csi, in ti_csi2rx_cleanup_buffers() argument
672 struct ti_csi2rx_dma *dma = &csi->dma; in ti_csi2rx_cleanup_buffers()
676 spin_lock_irqsave(&dma->lock, flags); in ti_csi2rx_cleanup_buffers()
677 list_for_each_entry_safe(buf, tmp, &csi->dma.queue, list) { in ti_csi2rx_cleanup_buffers()
678 list_del(&buf->list); in ti_csi2rx_cleanup_buffers()
679 vb2_buffer_done(&buf->vb.vb2_buf, state); in ti_csi2rx_cleanup_buffers()
681 list_for_each_entry_safe(buf, tmp, &csi->dma.submitted, list) { in ti_csi2rx_cleanup_buffers()
682 list_del(&buf->list); in ti_csi2rx_cleanup_buffers()
683 vb2_buffer_done(&buf->vb.vb2_buf, state); in ti_csi2rx_cleanup_buffers()
685 spin_unlock_irqrestore(&dma->lock, flags); in ti_csi2rx_cleanup_buffers()
692 struct ti_csi2rx_dev *csi = vb2_get_drv_priv(q); in ti_csi2rx_queue_setup() local
693 unsigned int size = csi->v_fmt.fmt.pix.sizeimage; in ti_csi2rx_queue_setup()
697 return -EINVAL; in ti_csi2rx_queue_setup()
709 struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vb->vb2_queue); in ti_csi2rx_buffer_prepare() local
710 unsigned long size = csi->v_fmt.fmt.pix.sizeimage; in ti_csi2rx_buffer_prepare()
713 dev_err(csi->dev, "Data will not fit into plane\n"); in ti_csi2rx_buffer_prepare()
714 return -EINVAL; in ti_csi2rx_buffer_prepare()
723 struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vb->vb2_queue); in ti_csi2rx_buffer_queue() local
725 struct ti_csi2rx_dma *dma = &csi->dma; in ti_csi2rx_buffer_queue()
731 buf->csi = csi; in ti_csi2rx_buffer_queue()
733 spin_lock_irqsave(&dma->lock, flags); in ti_csi2rx_buffer_queue()
738 if (dma->state == TI_CSI2RX_DMA_IDLE) { in ti_csi2rx_buffer_queue()
746 dma->state = TI_CSI2RX_DMA_ACTIVE; in ti_csi2rx_buffer_queue()
748 list_add_tail(&buf->list, &dma->queue); in ti_csi2rx_buffer_queue()
750 spin_unlock_irqrestore(&dma->lock, flags); in ti_csi2rx_buffer_queue()
760 ret = ti_csi2rx_drain_dma(csi); in ti_csi2rx_buffer_queue()
761 if (ret && ret != -ETIMEDOUT) in ti_csi2rx_buffer_queue()
762 dev_warn(csi->dev, in ti_csi2rx_buffer_queue()
765 ret = ti_csi2rx_start_dma(csi, buf); in ti_csi2rx_buffer_queue()
767 dev_err(csi->dev, "Failed to start DMA: %d\n", ret); in ti_csi2rx_buffer_queue()
768 spin_lock_irqsave(&dma->lock, flags); in ti_csi2rx_buffer_queue()
769 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); in ti_csi2rx_buffer_queue()
770 dma->state = TI_CSI2RX_DMA_IDLE; in ti_csi2rx_buffer_queue()
771 spin_unlock_irqrestore(&dma->lock, flags); in ti_csi2rx_buffer_queue()
773 spin_lock_irqsave(&dma->lock, flags); in ti_csi2rx_buffer_queue()
774 list_add_tail(&buf->list, &dma->submitted); in ti_csi2rx_buffer_queue()
775 spin_unlock_irqrestore(&dma->lock, flags); in ti_csi2rx_buffer_queue()
782 struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vq); in ti_csi2rx_start_streaming() local
783 struct ti_csi2rx_dma *dma = &csi->dma; in ti_csi2rx_start_streaming()
788 spin_lock_irqsave(&dma->lock, flags); in ti_csi2rx_start_streaming()
789 if (list_empty(&dma->queue)) in ti_csi2rx_start_streaming()
790 ret = -EIO; in ti_csi2rx_start_streaming()
791 spin_unlock_irqrestore(&dma->lock, flags); in ti_csi2rx_start_streaming()
795 ret = video_device_pipeline_start(&csi->vdev, &csi->pipe); in ti_csi2rx_start_streaming()
799 ti_csi2rx_setup_shim(csi); in ti_csi2rx_start_streaming()
801 csi->sequence = 0; in ti_csi2rx_start_streaming()
803 spin_lock_irqsave(&dma->lock, flags); in ti_csi2rx_start_streaming()
804 buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); in ti_csi2rx_start_streaming()
806 ret = ti_csi2rx_start_dma(csi, buf); in ti_csi2rx_start_streaming()
808 dev_err(csi->dev, "Failed to start DMA: %d\n", ret); in ti_csi2rx_start_streaming()
809 spin_unlock_irqrestore(&dma->lock, flags); in ti_csi2rx_start_streaming()
813 list_move_tail(&buf->list, &dma->submitted); in ti_csi2rx_start_streaming()
814 dma->state = TI_CSI2RX_DMA_ACTIVE; in ti_csi2rx_start_streaming()
815 spin_unlock_irqrestore(&dma->lock, flags); in ti_csi2rx_start_streaming()
817 ret = v4l2_subdev_call(csi->source, video, s_stream, 1); in ti_csi2rx_start_streaming()
824 ti_csi2rx_stop_dma(csi); in ti_csi2rx_start_streaming()
826 video_device_pipeline_stop(&csi->vdev); in ti_csi2rx_start_streaming()
827 writel(0, csi->shim + SHIM_CNTL); in ti_csi2rx_start_streaming()
828 writel(0, csi->shim + SHIM_DMACNTX); in ti_csi2rx_start_streaming()
830 ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_QUEUED); in ti_csi2rx_start_streaming()
836 struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vq); in ti_csi2rx_stop_streaming() local
839 video_device_pipeline_stop(&csi->vdev); in ti_csi2rx_stop_streaming()
841 writel(0, csi->shim + SHIM_CNTL); in ti_csi2rx_stop_streaming()
842 writel(0, csi->shim + SHIM_DMACNTX); in ti_csi2rx_stop_streaming()
844 ret = v4l2_subdev_call(csi->source, video, s_stream, 0); in ti_csi2rx_stop_streaming()
846 dev_err(csi->dev, "Failed to stop subdev stream\n"); in ti_csi2rx_stop_streaming()
848 ti_csi2rx_stop_dma(csi); in ti_csi2rx_stop_streaming()
849 ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_ERROR); in ti_csi2rx_stop_streaming()
862 static int ti_csi2rx_init_vb2q(struct ti_csi2rx_dev *csi) in ti_csi2rx_init_vb2q() argument
864 struct vb2_queue *q = &csi->vidq; in ti_csi2rx_init_vb2q()
867 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; in ti_csi2rx_init_vb2q()
868 q->io_modes = VB2_MMAP | VB2_DMABUF; in ti_csi2rx_init_vb2q()
869 q->drv_priv = csi; in ti_csi2rx_init_vb2q()
870 q->buf_struct_size = sizeof(struct ti_csi2rx_buffer); in ti_csi2rx_init_vb2q()
871 q->ops = &csi_vb2_qops; in ti_csi2rx_init_vb2q()
872 q->mem_ops = &vb2_dma_contig_memops; in ti_csi2rx_init_vb2q()
873 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; in ti_csi2rx_init_vb2q()
874 q->dev = dmaengine_get_dma_device(csi->dma.chan); in ti_csi2rx_init_vb2q()
875 q->lock = &csi->mutex; in ti_csi2rx_init_vb2q()
876 q->min_queued_buffers = 1; in ti_csi2rx_init_vb2q()
882 csi->vdev.queue = q; in ti_csi2rx_init_vb2q()
889 struct media_entity *entity = link->sink->entity; in ti_csi2rx_link_validate()
891 struct ti_csi2rx_dev *csi = container_of(vdev, struct ti_csi2rx_dev, vdev); in ti_csi2rx_link_validate() local
892 struct v4l2_pix_format *csi_fmt = &csi->v_fmt.fmt.pix; in ti_csi2rx_link_validate()
895 .pad = link->source->index, in ti_csi2rx_link_validate()
900 ret = v4l2_subdev_call_state_active(csi->source, pad, in ti_csi2rx_link_validate()
905 if (source_fmt.format.width != csi_fmt->width) { in ti_csi2rx_link_validate()
906 dev_dbg(csi->dev, "Width does not match (source %u, sink %u)\n", in ti_csi2rx_link_validate()
907 source_fmt.format.width, csi_fmt->width); in ti_csi2rx_link_validate()
908 return -EPIPE; in ti_csi2rx_link_validate()
911 if (source_fmt.format.height != csi_fmt->height) { in ti_csi2rx_link_validate()
912 dev_dbg(csi->dev, "Height does not match (source %u, sink %u)\n", in ti_csi2rx_link_validate()
913 source_fmt.format.height, csi_fmt->height); in ti_csi2rx_link_validate()
914 return -EPIPE; in ti_csi2rx_link_validate()
917 if (source_fmt.format.field != csi_fmt->field && in ti_csi2rx_link_validate()
918 csi_fmt->field != V4L2_FIELD_NONE) { in ti_csi2rx_link_validate()
919 dev_dbg(csi->dev, "Field does not match (source %u, sink %u)\n", in ti_csi2rx_link_validate()
920 source_fmt.format.field, csi_fmt->field); in ti_csi2rx_link_validate()
921 return -EPIPE; in ti_csi2rx_link_validate()
926 dev_dbg(csi->dev, "Media bus format 0x%x not supported\n", in ti_csi2rx_link_validate()
928 return -EPIPE; in ti_csi2rx_link_validate()
931 if (ti_fmt->fourcc != csi_fmt->pixelformat) { in ti_csi2rx_link_validate()
932 dev_dbg(csi->dev, in ti_csi2rx_link_validate()
934 ti_fmt->fourcc, csi_fmt->pixelformat); in ti_csi2rx_link_validate()
935 return -EPIPE; in ti_csi2rx_link_validate()
945 static int ti_csi2rx_init_dma(struct ti_csi2rx_dev *csi) in ti_csi2rx_init_dma() argument
952 INIT_LIST_HEAD(&csi->dma.queue); in ti_csi2rx_init_dma()
953 INIT_LIST_HEAD(&csi->dma.submitted); in ti_csi2rx_init_dma()
954 spin_lock_init(&csi->dma.lock); in ti_csi2rx_init_dma()
956 csi->dma.state = TI_CSI2RX_DMA_STOPPED; in ti_csi2rx_init_dma()
958 csi->dma.chan = dma_request_chan(csi->dev, "rx0"); in ti_csi2rx_init_dma()
959 if (IS_ERR(csi->dma.chan)) in ti_csi2rx_init_dma()
960 return PTR_ERR(csi->dma.chan); in ti_csi2rx_init_dma()
962 ret = dmaengine_slave_config(csi->dma.chan, &cfg); in ti_csi2rx_init_dma()
964 dma_release_channel(csi->dma.chan); in ti_csi2rx_init_dma()
968 csi->dma.drain.len = DRAIN_BUFFER_SIZE; in ti_csi2rx_init_dma()
969 csi->dma.drain.vaddr = dma_alloc_coherent(csi->dev, csi->dma.drain.len, in ti_csi2rx_init_dma()
970 &csi->dma.drain.paddr, in ti_csi2rx_init_dma()
972 if (!csi->dma.drain.vaddr) in ti_csi2rx_init_dma()
973 return -ENOMEM; in ti_csi2rx_init_dma()
978 static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) in ti_csi2rx_v4l2_init() argument
980 struct media_device *mdev = &csi->mdev; in ti_csi2rx_v4l2_init()
981 struct video_device *vdev = &csi->vdev; in ti_csi2rx_v4l2_init()
983 struct v4l2_pix_format *pix_fmt = &csi->v_fmt.fmt.pix; in ti_csi2rx_v4l2_init()
988 return -EINVAL; in ti_csi2rx_v4l2_init()
990 pix_fmt->width = 640; in ti_csi2rx_v4l2_init()
991 pix_fmt->height = 480; in ti_csi2rx_v4l2_init()
992 pix_fmt->field = V4L2_FIELD_NONE; in ti_csi2rx_v4l2_init()
993 pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; in ti_csi2rx_v4l2_init()
994 pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601, in ti_csi2rx_v4l2_init()
995 pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE, in ti_csi2rx_v4l2_init()
996 pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB, in ti_csi2rx_v4l2_init()
998 ti_csi2rx_fill_fmt(fmt, &csi->v_fmt); in ti_csi2rx_v4l2_init()
1000 mdev->dev = csi->dev; in ti_csi2rx_v4l2_init()
1001 mdev->hw_revision = 1; in ti_csi2rx_v4l2_init()
1002 strscpy(mdev->model, "TI-CSI2RX", sizeof(mdev->model)); in ti_csi2rx_v4l2_init()
1006 strscpy(vdev->name, TI_CSI2RX_MODULE_NAME, sizeof(vdev->name)); in ti_csi2rx_v4l2_init()
1007 vdev->v4l2_dev = &csi->v4l2_dev; in ti_csi2rx_v4l2_init()
1008 vdev->vfl_dir = VFL_DIR_RX; in ti_csi2rx_v4l2_init()
1009 vdev->fops = &csi_fops; in ti_csi2rx_v4l2_init()
1010 vdev->ioctl_ops = &csi_ioctl_ops; in ti_csi2rx_v4l2_init()
1011 vdev->release = video_device_release_empty; in ti_csi2rx_v4l2_init()
1012 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | in ti_csi2rx_v4l2_init()
1014 vdev->lock = &csi->mutex; in ti_csi2rx_v4l2_init()
1015 video_set_drvdata(vdev, csi); in ti_csi2rx_v4l2_init()
1017 csi->pad.flags = MEDIA_PAD_FL_SINK; in ti_csi2rx_v4l2_init()
1018 vdev->entity.ops = &ti_csi2rx_video_entity_ops; in ti_csi2rx_v4l2_init()
1019 ret = media_entity_pads_init(&csi->vdev.entity, 1, &csi->pad); in ti_csi2rx_v4l2_init()
1023 csi->v4l2_dev.mdev = mdev; in ti_csi2rx_v4l2_init()
1025 ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); in ti_csi2rx_v4l2_init()
1031 v4l2_device_unregister(&csi->v4l2_dev); in ti_csi2rx_v4l2_init()
1039 static void ti_csi2rx_cleanup_dma(struct ti_csi2rx_dev *csi) in ti_csi2rx_cleanup_dma() argument
1041 dma_free_coherent(csi->dev, csi->dma.drain.len, in ti_csi2rx_cleanup_dma()
1042 csi->dma.drain.vaddr, csi->dma.drain.paddr); in ti_csi2rx_cleanup_dma()
1043 csi->dma.drain.vaddr = NULL; in ti_csi2rx_cleanup_dma()
1044 dma_release_channel(csi->dma.chan); in ti_csi2rx_cleanup_dma()
1047 static void ti_csi2rx_cleanup_v4l2(struct ti_csi2rx_dev *csi) in ti_csi2rx_cleanup_v4l2() argument
1049 media_device_unregister(&csi->mdev); in ti_csi2rx_cleanup_v4l2()
1050 v4l2_device_unregister(&csi->v4l2_dev); in ti_csi2rx_cleanup_v4l2()
1051 media_device_cleanup(&csi->mdev); in ti_csi2rx_cleanup_v4l2()
1054 static void ti_csi2rx_cleanup_subdev(struct ti_csi2rx_dev *csi) in ti_csi2rx_cleanup_subdev() argument
1056 v4l2_async_nf_unregister(&csi->notifier); in ti_csi2rx_cleanup_subdev()
1057 v4l2_async_nf_cleanup(&csi->notifier); in ti_csi2rx_cleanup_subdev()
1060 static void ti_csi2rx_cleanup_vb2q(struct ti_csi2rx_dev *csi) in ti_csi2rx_cleanup_vb2q() argument
1062 vb2_queue_release(&csi->vidq); in ti_csi2rx_cleanup_vb2q()
1067 struct ti_csi2rx_dev *csi; in ti_csi2rx_probe() local
1071 csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); in ti_csi2rx_probe()
1072 if (!csi) in ti_csi2rx_probe()
1073 return -ENOMEM; in ti_csi2rx_probe()
1075 csi->dev = &pdev->dev; in ti_csi2rx_probe()
1076 platform_set_drvdata(pdev, csi); in ti_csi2rx_probe()
1078 mutex_init(&csi->mutex); in ti_csi2rx_probe()
1081 csi->shim = devm_ioremap_resource(&pdev->dev, res); in ti_csi2rx_probe()
1082 if (IS_ERR(csi->shim)) { in ti_csi2rx_probe()
1083 ret = PTR_ERR(csi->shim); in ti_csi2rx_probe()
1087 ret = ti_csi2rx_init_dma(csi); in ti_csi2rx_probe()
1091 ret = ti_csi2rx_v4l2_init(csi); in ti_csi2rx_probe()
1095 ret = ti_csi2rx_init_vb2q(csi); in ti_csi2rx_probe()
1099 ret = ti_csi2rx_notifier_register(csi); in ti_csi2rx_probe()
1103 ret = of_platform_populate(csi->dev->of_node, NULL, NULL, csi->dev); in ti_csi2rx_probe()
1105 dev_err(csi->dev, "Failed to create children: %d\n", ret); in ti_csi2rx_probe()
1112 ti_csi2rx_cleanup_subdev(csi); in ti_csi2rx_probe()
1114 ti_csi2rx_cleanup_vb2q(csi); in ti_csi2rx_probe()
1116 ti_csi2rx_cleanup_v4l2(csi); in ti_csi2rx_probe()
1118 ti_csi2rx_cleanup_dma(csi); in ti_csi2rx_probe()
1120 mutex_destroy(&csi->mutex); in ti_csi2rx_probe()
1126 struct ti_csi2rx_dev *csi = platform_get_drvdata(pdev); in ti_csi2rx_remove() local
1128 video_unregister_device(&csi->vdev); in ti_csi2rx_remove()
1130 ti_csi2rx_cleanup_vb2q(csi); in ti_csi2rx_remove()
1131 ti_csi2rx_cleanup_subdev(csi); in ti_csi2rx_remove()
1132 ti_csi2rx_cleanup_v4l2(csi); in ti_csi2rx_remove()
1133 ti_csi2rx_cleanup_dma(csi); in ti_csi2rx_remove()
1135 mutex_destroy(&csi->mutex); in ti_csi2rx_remove()
1141 { .compatible = "ti,j721e-csi2rx-shim", },
1158 MODULE_AUTHOR("Jai Luthra <j-luthra@ti.com>");