]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ENGR00278663-1 [mxc_v4l2_capture]: Add IPU v4l2 capture driver files
authorOliver Brown <oliver.brown@freescale.com>
Fri, 6 Sep 2013 19:22:07 +0000 (14:22 -0500)
committerLothar Waßmann <LW@KARO-electronics.de>
Wed, 20 Aug 2014 08:06:29 +0000 (10:06 +0200)
Copied files from
commit 0339bfd7164324c5c0208cf6467ef244f714c43a
Author: Liu Ying <Ying.Liu@freescale.com>
Date:   Wed Sep 4 13:21:21 2013 +0800

-Added function and file names to error messages that are similar
-Changed mxc_v4l_open to use clk_prepare_enable()
-Changed mxc_v4l_open to use clk_disable_unprepare()

Signed-off-by: Oliver Brown <oliver.brown@freescale.com>
drivers/media/platform/mxc/capture/Kconfig
drivers/media/platform/mxc/capture/Makefile
drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c [new file with mode: 0644]
drivers/media/platform/mxc/capture/ipu_csi_enc.c [new file with mode: 0644]
drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c [new file with mode: 0644]
drivers/media/platform/mxc/capture/ipu_prp_enc.c [new file with mode: 0644]
drivers/media/platform/mxc/capture/ipu_prp_sw.h [new file with mode: 0644]
drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c [new file with mode: 0644]
drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c [new file with mode: 0644]
drivers/media/platform/mxc/capture/ipu_still.c [new file with mode: 0644]
drivers/media/platform/mxc/capture/mxc_v4l2_capture.c [new file with mode: 0755]

index 762de46f7c6211e7d2f24384f4f6603007baae02..5b410f7cbbcbcc2f37440e12fcfc8cd209494f96 100644 (file)
@@ -1,3 +1,11 @@
+if VIDEO_MXC_CAPTURE
+
+menu "MXC Camera/V4L2 PRP Features support"
+config VIDEO_MXC_IPU_CAMERA
+       bool
+       depends on VIDEO_MXC_CAPTURE && MXC_IPU
+       default y
+
 config VIDEO_MXC_CSI_CAMERA
        tristate "CSI camera support"
        depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
@@ -9,3 +17,52 @@ config MXC_CAMERA_OV5640
         depends on !VIDEO_MXC_EMMA_CAMERA && I2C
         ---help---
           If you plan to use the ov5640 Camera with your MXC system, say Y here.
+
+choice
+       prompt "Select Overlay Rounting"
+       default MXC_IPU_DEVICE_QUEUE_SDC
+       depends on VIDEO_MXC_IPU_CAMERA && FB_MXC_SYNC_PANEL
+
+config MXC_IPU_DEVICE_QUEUE_SDC
+       tristate "Queue ipu device for overlay library"
+       depends on VIDEO_MXC_IPU_CAMERA
+       ---help---
+         Use case CSI->MEM->IPU DEVICE->SDC:
+               Images from sensor will be frist recieved in memory,then
+               queue to ipu device for processing if needed, and displaying
+               it on synchronous display with SDC use case.
+
+config MXC_IPU_PRP_VF_SDC
+       bool "Pre-Processor VF SDC library"
+       depends on VIDEO_MXC_IPU_CAMERA
+       ---help---
+         Use case PRP_VF_SDC:
+               Preprocessing image from smart sensor for viewfinder and
+               displaying it on synchronous display with SDC use case.
+               If SDC BG is selected, Rotation will not be supported.
+               CSI -> IC (PRP VF) -> MEM
+               MEM -> IC (ROT) -> MEM
+               MEM -> SDC (FG/BG)
+
+endchoice
+
+config MXC_IPU_PRP_ENC
+       tristate "Pre-processor Encoder library"
+       depends on VIDEO_MXC_IPU_CAMERA
+       default y
+       ---help---
+         Use case PRP_ENC:
+               Preprocessing image from smart sensor for encoder.
+               CSI -> IC (PRP ENC) -> MEM
+
+config MXC_IPU_CSI_ENC
+       tristate "IPU CSI Encoder library"
+       depends on VIDEO_MXC_IPU_CAMERA
+       default y
+       ---help---
+         Use case IPU_CSI_ENC:
+               Get raw image with CSI from smart sensor for encoder.
+               CSI -> MEM
+endmenu
+
+endif
index 2fc2596038f9e28e3b17f93fd75b44a4f46e8d50..9be45ffc7de7a800c41cd8e50118426eeff4b322 100644 (file)
@@ -1,2 +1,12 @@
 obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA)     += fsl_csi.o csi_v4l2_capture.o
-obj-$(CONFIG_MXC_CAMERA_OV5640)                += ov5640.o
+
+ifeq ($(CONFIG_VIDEO_MXC_IPU_CAMERA),y)
+       obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc_v4l2_capture.o
+       obj-$(CONFIG_MXC_IPU_PRP_VF_SDC) += ipu_prp_vf_sdc.o ipu_prp_vf_sdc_bg.o
+       obj-$(CONFIG_MXC_IPU_DEVICE_QUEUE_SDC) += ipu_fg_overlay_sdc.o ipu_bg_overlay_sdc.o
+       obj-$(CONFIG_MXC_IPU_PRP_ENC) += ipu_prp_enc.o ipu_still.o
+       obj-$(CONFIG_MXC_IPU_CSI_ENC) += ipu_csi_enc.o ipu_still.o
+endif
+
+ov5640_camera-objs := ov5640.o
+obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera.o
diff --git a/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c b/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c
new file mode 100644 (file)
index 0000000..fc77525
--- /dev/null
@@ -0,0 +1,554 @@
+
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_bg_overlay_sdc_bg.c
+ *
+ * @brief IPU Use case for PRP-VF back-ground
+ *
+ * @ingroup IPU
+ */
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/ipu.h>
+#include <linux/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int csi_buffer_num;
+static u32 bpp, csi_mem_bufsize = 3;
+static u32 out_format;
+static struct ipu_soc *disp_ipu;
+static u32 offset;
+
+static void csi_buf_work_func(struct work_struct *work)
+{
+       int err = 0;
+       cam_data *cam =
+               container_of(work, struct _cam_data, csi_work_struct);
+
+       struct ipu_task task;
+       memset(&task, 0, sizeof(task));
+
+       if (csi_buffer_num)
+               task.input.paddr = cam->vf_bufs[0];
+       else
+               task.input.paddr = cam->vf_bufs[1];
+       task.input.width = cam->crop_current.width;
+       task.input.height = cam->crop_current.height;
+       task.input.format = IPU_PIX_FMT_UYVY;
+
+       task.output.paddr = offset;
+       task.output.width = cam->overlay_fb->var.xres;
+       task.output.height = cam->overlay_fb->var.yres;
+       task.output.format = out_format;
+       task.output.rotate = cam->rotation;
+       task.output.crop.pos.x = cam->win.w.left;
+       task.output.crop.pos.y = cam->win.w.top;
+       if (cam->win.w.width > 1024 || cam->win.w.height > 1024) {
+               task.output.crop.w = cam->overlay_fb->var.xres;
+               task.output.crop.h = cam->overlay_fb->var.yres;
+       } else {
+               task.output.crop.w = cam->win.w.width;
+               task.output.crop.h = cam->win.w.height;
+       }
+again:
+       err = ipu_check_task(&task);
+       if (err != IPU_CHECK_OK) {
+               if (err > IPU_CHECK_ERR_MIN) {
+                       if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
+                               task.input.crop.w -= 8;
+                               goto again;
+                       }
+                       if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
+                               task.input.crop.h -= 8;
+                               goto again;
+                       }
+                       if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
+                                       task.output.width -= 8;
+                                       task.output.crop.w = task.output.width;
+                               goto again;
+                       }
+                       if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
+                                       task.output.height -= 8;
+                                       task.output.crop.h = task.output.height;
+                               goto again;
+                       }
+                       printk(KERN_ERR "check ipu taks fail\n");
+                       return;
+               }
+               printk(KERN_ERR "check ipu taks fail\n");
+               return;
+       }
+       err = ipu_queue_task(&task);
+       if (err < 0)
+               printk(KERN_ERR "queue ipu task error\n");
+}
+
+static void get_disp_ipu(cam_data *cam)
+{
+       if (cam->output > 2)
+               disp_ipu = ipu_get_soc(1); /* using DISP4 */
+       else
+               disp_ipu = ipu_get_soc(0);
+}
+
+
+/*!
+ * csi ENC callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t csi_enc_callback(int irq, void *dev_id)
+{
+       cam_data *cam = (cam_data *) dev_id;
+
+       ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, csi_buffer_num);
+       schedule_work(&cam->csi_work_struct);
+       csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
+       return IRQ_HANDLED;
+}
+
+static int csi_enc_setup(cam_data *cam)
+{
+       ipu_channel_params_t params;
+       u32 pixel_fmt;
+       int err = 0, sensor_protocol = 0;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       if (!cam) {
+               printk(KERN_ERR "cam private is NULL\n");
+               return -ENXIO;
+       }
+
+       memset(&params, 0, sizeof(ipu_channel_params_t));
+       params.csi_mem.csi = cam->csi;
+
+       sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
+       switch (sensor_protocol) {
+       case IPU_CSI_CLK_MODE_GATED_CLK:
+       case IPU_CSI_CLK_MODE_NONGATED_CLK:
+       case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+               params.csi_mem.interlaced = false;
+               break;
+       case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+               params.csi_mem.interlaced = true;
+               break;
+       default:
+               printk(KERN_ERR "sensor protocol unsupported\n");
+               return -EINVAL;
+       }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id) {
+                               params.csi_mem.mipi_en = true;
+                               params.csi_mem.mipi_vc =
+                               mipi_csi2_get_virtual_channel(mipi_csi2_info);
+                               params.csi_mem.mipi_id =
+                               mipi_csi2_get_datatype(mipi_csi2_info);
+
+                               mipi_csi2_pixelclk_enable(mipi_csi2_info);
+                       } else {
+                               params.csi_mem.mipi_en = false;
+                               params.csi_mem.mipi_vc = 0;
+                               params.csi_mem.mipi_id = 0;
+                       }
+               } else {
+                       params.csi_mem.mipi_en = false;
+                       params.csi_mem.mipi_vc = 0;
+                       params.csi_mem.mipi_id = 0;
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0],
+                                 (dma_addr_t) cam->vf_bufs[0]);
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1],
+                                 (dma_addr_t) cam->vf_bufs[1]);
+       }
+       csi_mem_bufsize =
+               cam->crop_current.width * cam->crop_current.height * 2;
+       cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
+       cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
+                                                          cam->vf_bufs_size[0],
+                                                          (dma_addr_t *) &
+                                                          cam->vf_bufs[0],
+                                                          GFP_DMA |
+                                                          GFP_KERNEL);
+       if (cam->vf_bufs_vaddr[0] == NULL) {
+               printk(KERN_ERR "Error to allocate vf buffer\n");
+               err = -ENOMEM;
+               goto out_2;
+       }
+       cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
+       cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
+                                                          cam->vf_bufs_size[1],
+                                                          (dma_addr_t *) &
+                                                          cam->vf_bufs[1],
+                                                          GFP_DMA |
+                                                          GFP_KERNEL);
+       if (cam->vf_bufs_vaddr[1] == NULL) {
+               printk(KERN_ERR "Error to allocate vf buffer\n");
+               err = -ENOMEM;
+               goto out_1;
+       }
+       pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
+
+       err = ipu_init_channel(cam->ipu, CSI_MEM, &params);
+       if (err != 0) {
+               printk(KERN_ERR "ipu_init_channel %d\n", err);
+               goto out_1;
+       }
+
+       pixel_fmt = IPU_PIX_FMT_UYVY;
+       err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+                               pixel_fmt, cam->crop_current.width,
+                               cam->crop_current.height,
+                               cam->crop_current.width, IPU_ROTATE_NONE,
+                               cam->vf_bufs[0], cam->vf_bufs[1], 0,
+                               cam->offset.u_offset, cam->offset.u_offset);
+       if (err != 0) {
+               printk(KERN_ERR "CSI_MEM output buffer\n");
+               goto out_1;
+       }
+       err = ipu_enable_channel(cam->ipu, CSI_MEM);
+       if (err < 0) {
+               printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+               goto out_1;
+       }
+
+       csi_buffer_num = 0;
+
+       ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0);
+       ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 1);
+       return err;
+out_1:
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0],
+                                 (dma_addr_t) cam->vf_bufs[0]);
+               cam->vf_bufs_vaddr[0] = NULL;
+               cam->vf_bufs[0] = 0;
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1],
+                                 (dma_addr_t) cam->vf_bufs[1]);
+               cam->vf_bufs_vaddr[1] = NULL;
+               cam->vf_bufs[1] = 0;
+       }
+out_2:
+       return err;
+}
+
+/*!
+ * Enable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_enabling_tasks(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+
+       ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
+       err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
+                             csi_enc_callback, 0, "Mxc Camera", cam);
+       if (err != 0) {
+               printk(KERN_ERR "Error registering CSI0_OUT_EOF irq\n");
+               return err;
+       }
+
+       INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
+
+       err = csi_enc_setup(cam);
+       if (err != 0) {
+               printk(KERN_ERR "csi_enc_setup %d\n", err);
+               goto out1;
+       }
+
+       return err;
+out1:
+       ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
+       return err;
+}
+
+/*!
+ * bg_overlay_start - start the overlay task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int bg_overlay_start(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+
+       if (!cam) {
+               printk(KERN_ERR "private is NULL\n");
+               return -EIO;
+       }
+
+       if (cam->overlay_active == true) {
+               pr_debug("already start.\n");
+               return 0;
+       }
+
+       get_disp_ipu(cam);
+
+       out_format = cam->v4l2_fb.fmt.pixelformat;
+       if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
+               bpp = 3, csi_mem_bufsize = 3;
+               pr_info("BGR24\n");
+       } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
+               bpp = 2, csi_mem_bufsize = 2;
+               pr_info("RGB565\n");
+       } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
+               bpp = 4, csi_mem_bufsize = 4;
+               pr_info("BGR32\n");
+       } else {
+               printk(KERN_ERR
+                      "unsupported fix format from the framebuffer.\n");
+               return -EINVAL;
+       }
+
+       offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
+           csi_mem_bufsize * cam->win.w.left;
+
+       if (cam->v4l2_fb.base == 0)
+               printk(KERN_ERR "invalid frame buffer address.\n");
+       else
+               offset += (u32) cam->v4l2_fb.base;
+
+       csi_mem_bufsize = cam->win.w.width * cam->win.w.height
+                               * csi_mem_bufsize;
+
+       err = csi_enc_enabling_tasks(cam);
+       if (err != 0) {
+               printk(KERN_ERR "Error csi enc enable fail\n");
+               return err;
+       }
+
+       cam->overlay_active = true;
+       return err;
+}
+
+/*!
+ * bg_overlay_stop - stop the overlay task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int bg_overlay_stop(void *private)
+{
+       int err = 0;
+       cam_data *cam = (cam_data *) private;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       if (cam->overlay_active == false)
+               return 0;
+
+       err = ipu_disable_channel(cam->ipu, CSI_MEM, true);
+
+       ipu_uninit_channel(cam->ipu, CSI_MEM);
+
+       csi_buffer_num = 0;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id)
+                               mipi_csi2_pixelclk_disable(mipi_csi2_info);
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       flush_work_sync(&cam->csi_work_struct);
+       cancel_work_sync(&cam->csi_work_struct);
+
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+               cam->vf_bufs_vaddr[0] = NULL;
+               cam->vf_bufs[0] = 0;
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+               cam->vf_bufs_vaddr[1] = NULL;
+               cam->vf_bufs[1] = 0;
+       }
+       if (cam->rot_vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->rot_vf_buf_size[0],
+                                 cam->rot_vf_bufs_vaddr[0],
+                                 cam->rot_vf_bufs[0]);
+               cam->rot_vf_bufs_vaddr[0] = NULL;
+               cam->rot_vf_bufs[0] = 0;
+       }
+       if (cam->rot_vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->rot_vf_buf_size[1],
+                                 cam->rot_vf_bufs_vaddr[1],
+                                 cam->rot_vf_bufs[1]);
+               cam->rot_vf_bufs_vaddr[1] = NULL;
+               cam->rot_vf_bufs[1] = 0;
+       }
+
+       cam->overlay_active = false;
+       return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int bg_overlay_enable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int bg_overlay_disable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       /* free csi eof irq firstly.
+        * when disable csi, wait for idmac eof.
+        * it requests eof irq again */
+       ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
+
+       return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select bg as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int bg_overlay_sdc_select(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       if (cam) {
+               cam->vf_start_sdc = bg_overlay_start;
+               cam->vf_stop_sdc = bg_overlay_stop;
+               cam->vf_enable_csi = bg_overlay_enable_csi;
+               cam->vf_disable_csi = bg_overlay_disable_csi;
+               cam->overlay_active = false;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(bg_overlay_sdc_select);
+
+/*!
+ * function to de-select bg as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int bg_overlay_sdc_deselect(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       if (cam) {
+               cam->vf_start_sdc = NULL;
+               cam->vf_stop_sdc = NULL;
+               cam->vf_enable_csi = NULL;
+               cam->vf_disable_csi = NULL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(bg_overlay_sdc_deselect);
+
+/*!
+ * Init background overlay task.
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int bg_overlay_sdc_init(void)
+{
+       return 0;
+}
+
+/*!
+ * Deinit background overlay task.
+ *
+ * @return  Error code indicating success or failure
+ */
+void __exit bg_overlay_sdc_exit(void)
+{
+}
+
+module_init(bg_overlay_sdc_init);
+module_exit(bg_overlay_sdc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_csi_enc.c b/drivers/media/platform/mxc/capture/ipu_csi_enc.c
new file mode 100644 (file)
index 0000000..4752f77
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_csi_enc.c
+ *
+ * @brief CSI Use case for video capture
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/ipu.h>
+#include <linux/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#ifdef CAMERA_DBG
+       #define CAMERA_TRACE(x) (printk)x
+#else
+       #define CAMERA_TRACE(x)
+#endif
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * csi ENC callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t csi_enc_callback(int irq, void *dev_id)
+{
+       cam_data *cam = (cam_data *) dev_id;
+
+       if (cam->enc_callback == NULL)
+               return IRQ_HANDLED;
+
+       cam->enc_callback(irq, dev_id);
+       return IRQ_HANDLED;
+}
+
+/*!
+ * CSI ENC enable channel setup function
+ *
+ * @param cam       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_setup(cam_data *cam)
+{
+       ipu_channel_params_t params;
+       u32 pixel_fmt;
+       int err = 0, sensor_protocol = 0;
+       dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       CAMERA_TRACE("In csi_enc_setup\n");
+       if (!cam) {
+               printk(KERN_ERR "cam private is NULL\n");
+               return -ENXIO;
+       }
+
+       memset(&params, 0, sizeof(ipu_channel_params_t));
+       params.csi_mem.csi = cam->csi;
+
+       sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
+       switch (sensor_protocol) {
+       case IPU_CSI_CLK_MODE_GATED_CLK:
+       case IPU_CSI_CLK_MODE_NONGATED_CLK:
+       case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+               params.csi_mem.interlaced = false;
+               break;
+       case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+               params.csi_mem.interlaced = true;
+               break;
+       default:
+               printk(KERN_ERR "sensor protocol unsupported\n");
+               return -EINVAL;
+       }
+
+       if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+               pixel_fmt = IPU_PIX_FMT_YUV420P;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420)
+               pixel_fmt = IPU_PIX_FMT_YVU420P;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P)
+               pixel_fmt = IPU_PIX_FMT_YUV422P;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
+               pixel_fmt = IPU_PIX_FMT_UYVY;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+               pixel_fmt = IPU_PIX_FMT_YUYV;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
+               pixel_fmt = IPU_PIX_FMT_NV12;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
+               pixel_fmt = IPU_PIX_FMT_BGR24;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
+               pixel_fmt = IPU_PIX_FMT_RGB24;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
+               pixel_fmt = IPU_PIX_FMT_RGB565;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
+               pixel_fmt = IPU_PIX_FMT_BGR32;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
+               pixel_fmt = IPU_PIX_FMT_RGB32;
+       else {
+               printk(KERN_ERR "format not supported\n");
+               return -EINVAL;
+       }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id) {
+                               params.csi_mem.mipi_en = true;
+                               params.csi_mem.mipi_vc =
+                               mipi_csi2_get_virtual_channel(mipi_csi2_info);
+                               params.csi_mem.mipi_id =
+                               mipi_csi2_get_datatype(mipi_csi2_info);
+
+                               mipi_csi2_pixelclk_enable(mipi_csi2_info);
+                       } else {
+                               params.csi_mem.mipi_en = false;
+                               params.csi_mem.mipi_vc = 0;
+                               params.csi_mem.mipi_id = 0;
+                       }
+               } else {
+                       params.csi_mem.mipi_en = false;
+                       params.csi_mem.mipi_vc = 0;
+                       params.csi_mem.mipi_id = 0;
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       err = ipu_init_channel(cam->ipu, CSI_MEM, &params);
+       if (err != 0) {
+               printk(KERN_ERR "ipu_init_channel %d\n", err);
+               return err;
+       }
+
+       err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+                                     pixel_fmt, cam->v2f.fmt.pix.width,
+                                     cam->v2f.fmt.pix.height,
+                                     cam->v2f.fmt.pix.bytesperline,
+                                     IPU_ROTATE_NONE,
+                                     dummy, dummy, 0,
+                                     cam->offset.u_offset,
+                                     cam->offset.v_offset);
+       if (err != 0) {
+               printk(KERN_ERR "CSI_MEM output buffer\n");
+               return err;
+       }
+       err = ipu_enable_channel(cam->ipu, CSI_MEM);
+       if (err < 0) {
+               printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+               return err;
+       }
+
+       return err;
+}
+
+/*!
+ * function to update physical buffer address for encorder IDMA channel
+ *
+ * @param eba         physical buffer address for encorder IDMA channel
+ * @param buffer_num  int buffer 0 or buffer 1
+ *
+ * @return  status
+ */
+static int csi_enc_eba_update(struct ipu_soc *ipu, dma_addr_t eba,
+                             int *buffer_num)
+{
+       int err = 0;
+
+       pr_debug("eba %x\n", eba);
+       err = ipu_update_channel_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+                                       *buffer_num, eba);
+       if (err != 0) {
+               ipu_clear_buffer_ready(ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+                                      *buffer_num);
+
+               err = ipu_update_channel_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+                                               *buffer_num, eba);
+               if (err != 0) {
+                       pr_err("ERROR: v4l2 capture: fail to update "
+                              "buf%d\n", *buffer_num);
+                       return err;
+               }
+       }
+
+       ipu_select_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num);
+
+       *buffer_num = (*buffer_num == 0) ? 1 : 0;
+
+       return 0;
+}
+
+/*!
+ * Enable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_enabling_tasks(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+       CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
+
+       cam->dummy_frame.vaddress = dma_alloc_coherent(0,
+                              PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+                              &cam->dummy_frame.paddress,
+                              GFP_DMA | GFP_KERNEL);
+       if (cam->dummy_frame.vaddress == 0) {
+               pr_err("ERROR: v4l2 capture: Allocate dummy frame "
+                      "failed.\n");
+               return -ENOBUFS;
+       }
+       cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
+       cam->dummy_frame.buffer.length =
+           PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+       cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
+
+       ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
+       err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
+                             csi_enc_callback, 0, "Mxc Camera", cam);
+       if (err != 0) {
+               printk(KERN_ERR "Error registering rot irq\n");
+               return err;
+       }
+
+       err = csi_enc_setup(cam);
+       if (err != 0) {
+               printk(KERN_ERR "csi_enc_setup %d\n", err);
+               return err;
+       }
+
+       return err;
+}
+
+/*!
+ * Disable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+static int csi_enc_disabling_tasks(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       err = ipu_disable_channel(cam->ipu, CSI_MEM, true);
+
+       ipu_uninit_channel(cam->ipu, CSI_MEM);
+
+       if (cam->dummy_frame.vaddress != 0) {
+               dma_free_coherent(0, cam->dummy_frame.buffer.length,
+                                 cam->dummy_frame.vaddress,
+                                 cam->dummy_frame.paddress);
+               cam->dummy_frame.vaddress = 0;
+       }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id)
+                               mipi_csi2_pixelclk_disable(mipi_csi2_info);
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_enable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_disable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       /* free csi eof irq firstly.
+        * when disable csi, wait for idmac eof.
+        * it requests eof irq again */
+       ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
+
+       return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select CSI ENC as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+int csi_enc_select(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+
+       if (cam) {
+               cam->enc_update_eba = csi_enc_eba_update;
+               cam->enc_enable = csi_enc_enabling_tasks;
+               cam->enc_disable = csi_enc_disabling_tasks;
+               cam->enc_enable_csi = csi_enc_enable_csi;
+               cam->enc_disable_csi = csi_enc_disable_csi;
+       } else {
+               err = -EIO;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(csi_enc_select);
+
+/*!
+ * function to de-select CSI ENC as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+int csi_enc_deselect(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+
+       if (cam) {
+               cam->enc_update_eba = NULL;
+               cam->enc_enable = NULL;
+               cam->enc_disable = NULL;
+               cam->enc_enable_csi = NULL;
+               cam->enc_disable_csi = NULL;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(csi_enc_deselect);
+
+/*!
+ * Init the Encorder channels
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int csi_enc_init(void)
+{
+       return 0;
+}
+
+/*!
+ * Deinit the Encorder channels
+ *
+ */
+void __exit csi_enc_exit(void)
+{
+}
+
+module_init(csi_enc_init);
+module_exit(csi_enc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("CSI ENC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c b/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c
new file mode 100644 (file)
index 0000000..43baba2
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/* * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_foreground_sdc.c
+ *
+ * @brief IPU Use case for PRP-VF
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/ipu.h>
+#include <linux/mxcfb.h>
+#include <linux/mipi_csi2.h>
+
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#ifdef CAMERA_DBG
+       #define CAMERA_TRACE(x) (printk)x
+#else
+       #define CAMERA_TRACE(x)
+#endif
+
+static int csi_buffer_num, buffer_num;
+static u32 csi_mem_bufsize;
+static struct ipu_soc *disp_ipu;
+static struct fb_info *fbi;
+static struct fb_var_screeninfo fbvar;
+static u32 vf_out_format;
+static void csi_buf_work_func(struct work_struct *work)
+{
+       int err = 0;
+       cam_data *cam =
+               container_of(work, struct _cam_data, csi_work_struct);
+
+       struct ipu_task task;
+       memset(&task, 0, sizeof(task));
+
+       if (csi_buffer_num)
+               task.input.paddr = cam->vf_bufs[0];
+       else
+               task.input.paddr = cam->vf_bufs[1];
+       task.input.width = cam->crop_current.width;
+       task.input.height = cam->crop_current.height;
+       task.input.format = IPU_PIX_FMT_NV12;
+
+       if (buffer_num == 0)
+               task.output.paddr = fbi->fix.smem_start +
+                               (fbi->fix.line_length * fbvar.yres);
+       else
+               task.output.paddr = fbi->fix.smem_start;
+       task.output.width = cam->win.w.width;
+       task.output.height = cam->win.w.height;
+       task.output.format = vf_out_format;
+       task.output.rotate = cam->rotation;
+again:
+       err = ipu_check_task(&task);
+       if (err != IPU_CHECK_OK) {
+               if (err > IPU_CHECK_ERR_MIN) {
+                       if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
+                               task.input.crop.w -= 8;
+                               goto again;
+                       }
+                       if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
+                               task.input.crop.h -= 8;
+                               goto again;
+                       }
+                       if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
+                                       task.output.width -= 8;
+                                       task.output.crop.w = task.output.width;
+                               goto again;
+                       }
+                       if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
+                                       task.output.height -= 8;
+                                       task.output.crop.h = task.output.height;
+                               goto again;
+                       }
+                       printk(KERN_ERR "check ipu taks fail\n");
+                       return;
+               }
+               printk(KERN_ERR "check ipu taks fail\n");
+               return;
+       }
+       err = ipu_queue_task(&task);
+       if (err < 0)
+               printk(KERN_ERR "queue ipu task error\n");
+       ipu_select_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, buffer_num);
+       buffer_num = (buffer_num == 0) ? 1 : 0;
+}
+
+static void get_disp_ipu(cam_data *cam)
+{
+       if (cam->output > 2)
+               disp_ipu = ipu_get_soc(1); /* using DISP4 */
+       else
+               disp_ipu = ipu_get_soc(0);
+}
+
+/*!
+ * csi ENC callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t csi_enc_callback(int irq, void *dev_id)
+{
+       cam_data *cam = (cam_data *) dev_id;
+
+       ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, csi_buffer_num);
+       if ((cam->crop_current.width != cam->win.w.width) ||
+               (cam->crop_current.height != cam->win.w.height) ||
+               (vf_out_format != IPU_PIX_FMT_NV12) ||
+               (cam->rotation >= IPU_ROTATE_VERT_FLIP))
+               schedule_work(&cam->csi_work_struct);
+       csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
+       return IRQ_HANDLED;
+}
+
+static int csi_enc_setup(cam_data *cam)
+{
+       ipu_channel_params_t params;
+       int err = 0, sensor_protocol = 0;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       CAMERA_TRACE("In csi_enc_setup\n");
+       if (!cam) {
+               printk(KERN_ERR "cam private is NULL\n");
+               return -ENXIO;
+       }
+
+       memset(&params, 0, sizeof(ipu_channel_params_t));
+       params.csi_mem.csi = cam->csi;
+
+       sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
+       switch (sensor_protocol) {
+       case IPU_CSI_CLK_MODE_GATED_CLK:
+       case IPU_CSI_CLK_MODE_NONGATED_CLK:
+       case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+               params.csi_mem.interlaced = false;
+               break;
+       case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+               params.csi_mem.interlaced = true;
+               break;
+       default:
+               printk(KERN_ERR "sensor protocol unsupported\n");
+               return -EINVAL;
+       }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id) {
+                               params.csi_mem.mipi_en = true;
+                               params.csi_mem.mipi_vc =
+                               mipi_csi2_get_virtual_channel(mipi_csi2_info);
+                               params.csi_mem.mipi_id =
+                               mipi_csi2_get_datatype(mipi_csi2_info);
+
+                               mipi_csi2_pixelclk_enable(mipi_csi2_info);
+                       } else {
+                               params.csi_mem.mipi_en = false;
+                               params.csi_mem.mipi_vc = 0;
+                               params.csi_mem.mipi_id = 0;
+                       }
+               } else {
+                       params.csi_mem.mipi_en = false;
+                       params.csi_mem.mipi_vc = 0;
+                       params.csi_mem.mipi_id = 0;
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0],
+                                 (dma_addr_t) cam->vf_bufs[0]);
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1],
+                                 (dma_addr_t) cam->vf_bufs[1]);
+       }
+       csi_mem_bufsize = cam->crop_current.width *
+                         cam->crop_current.height * 3/2;
+       cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
+       cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
+                                                          cam->vf_bufs_size[0],
+                                                          (dma_addr_t *) &
+                                                          cam->vf_bufs[0],
+                                                          GFP_DMA |
+                                                          GFP_KERNEL);
+       if (cam->vf_bufs_vaddr[0] == NULL) {
+               printk(KERN_ERR "Error to allocate vf buffer\n");
+               err = -ENOMEM;
+               goto out_2;
+       }
+       cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
+       cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
+                                                          cam->vf_bufs_size[1],
+                                                          (dma_addr_t *) &
+                                                          cam->vf_bufs[1],
+                                                          GFP_DMA |
+                                                          GFP_KERNEL);
+       if (cam->vf_bufs_vaddr[1] == NULL) {
+               printk(KERN_ERR "Error to allocate vf buffer\n");
+               err = -ENOMEM;
+               goto out_1;
+       }
+       pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
+
+       err = ipu_init_channel(cam->ipu, CSI_MEM, &params);
+       if (err != 0) {
+               printk(KERN_ERR "ipu_init_channel %d\n", err);
+               goto out_1;
+       }
+
+       if ((cam->crop_current.width == cam->win.w.width) &&
+               (cam->crop_current.height == cam->win.w.height) &&
+               (vf_out_format == IPU_PIX_FMT_NV12) &&
+               (cam->rotation < IPU_ROTATE_VERT_FLIP)) {
+               err = ipu_init_channel_buffer(cam->ipu, CSI_MEM,
+                       IPU_OUTPUT_BUFFER,
+                       IPU_PIX_FMT_NV12,
+                       cam->crop_current.width,
+                       cam->crop_current.height,
+                       cam->crop_current.width, IPU_ROTATE_NONE,
+                       fbi->fix.smem_start +
+                       (fbi->fix.line_length * fbvar.yres),
+                       fbi->fix.smem_start, 0,
+                       cam->offset.u_offset, cam->offset.u_offset);
+       } else {
+               err = ipu_init_channel_buffer(cam->ipu, CSI_MEM,
+                       IPU_OUTPUT_BUFFER,
+                       IPU_PIX_FMT_NV12,
+                       cam->crop_current.width,
+                       cam->crop_current.height,
+                       cam->crop_current.width, IPU_ROTATE_NONE,
+                       cam->vf_bufs[0], cam->vf_bufs[1], 0,
+                       cam->offset.u_offset, cam->offset.u_offset);
+       }
+       if (err != 0) {
+               printk(KERN_ERR "CSI_MEM output buffer\n");
+               goto out_1;
+       }
+       err = ipu_enable_channel(cam->ipu, CSI_MEM);
+       if (err < 0) {
+               printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+               goto out_1;
+       }
+
+       csi_buffer_num = 0;
+
+       ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0);
+       ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 1);
+       return err;
+out_1:
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0],
+                                 (dma_addr_t) cam->vf_bufs[0]);
+               cam->vf_bufs_vaddr[0] = NULL;
+               cam->vf_bufs[0] = 0;
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1],
+                                 (dma_addr_t) cam->vf_bufs[1]);
+               cam->vf_bufs_vaddr[1] = NULL;
+               cam->vf_bufs[1] = 0;
+       }
+out_2:
+       return err;
+}
+
+/*!
+ * Enable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_enabling_tasks(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+       CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
+
+       ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
+       err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
+                             csi_enc_callback, 0, "Mxc Camera", cam);
+       if (err != 0) {
+               printk(KERN_ERR "Error registering CSI0_OUT_EOF irq\n");
+               return err;
+       }
+
+       INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
+
+       err = csi_enc_setup(cam);
+       if (err != 0) {
+               printk(KERN_ERR "csi_enc_setup %d\n", err);
+               goto out1;
+       }
+
+       return err;
+out1:
+       ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
+       return err;
+}
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * foreground_start - start the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int foreground_start(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0, i = 0, screen_size;
+       char *base;
+
+       if (!cam) {
+               printk(KERN_ERR "private is NULL\n");
+               return -EIO;
+       }
+
+       if (cam->overlay_active == true) {
+               pr_debug("already started.\n");
+               return 0;
+       }
+
+       get_disp_ipu(cam);
+
+       for (i = 0; i < num_registered_fb; i++) {
+               char *idstr = registered_fb[i]->fix.id;
+               if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+                   ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+                       fbi = registered_fb[i];
+                       break;
+               }
+       }
+
+       if (fbi == NULL) {
+               printk(KERN_ERR "DISP FG fb not found\n");
+               return -EPERM;
+       }
+
+       fbvar = fbi->var;
+
+       /* Store the overlay frame buffer's original std */
+       cam->fb_origin_std = fbvar.nonstd;
+
+       if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
+               /* Use DP to do CSC so that we can get better performance */
+               vf_out_format = IPU_PIX_FMT_NV12;
+               fbvar.nonstd = vf_out_format;
+       } else {
+               vf_out_format = IPU_PIX_FMT_RGB565;
+               fbvar.nonstd = 0;
+       }
+
+       fbvar.bits_per_pixel = 16;
+       fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
+       fbvar.yres = cam->win.w.height;
+       fbvar.yres_virtual = cam->win.w.height * 2;
+       fbvar.yoffset = 0;
+       fbvar.vmode &= ~FB_VMODE_YWRAP;
+       fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
+       fbvar.activate |= FB_ACTIVATE_FORCE;
+       fb_set_var(fbi, &fbvar);
+
+       ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left,
+                       cam->win.w.top);
+
+       /* Fill black color for framebuffer */
+       base = (char *) fbi->screen_base;
+       screen_size = fbi->var.xres * fbi->var.yres;
+       if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
+               memset(base, 0, screen_size);
+               base += screen_size;
+               for (i = 0; i < screen_size / 2; i++, base++)
+                       *base = 0x80;
+       } else {
+               for (i = 0; i < screen_size * 2; i++, base++)
+                       *base = 0x00;
+       }
+
+       console_lock();
+       fb_blank(fbi, FB_BLANK_UNBLANK);
+       console_unlock();
+
+       /* correct display ch buffer address */
+       ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+                               0, fbi->fix.smem_start +
+                               (fbi->fix.line_length * fbvar.yres));
+       ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+                                       1, fbi->fix.smem_start);
+
+       err = csi_enc_enabling_tasks(cam);
+       if (err != 0) {
+               printk(KERN_ERR "Error csi enc enable fail\n");
+               return err;
+       }
+
+       cam->overlay_active = true;
+       return err;
+
+}
+
+/*!
+ * foreground_stop - stop the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int foreground_stop(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0, i = 0;
+       struct fb_info *fbi = NULL;
+       struct fb_var_screeninfo fbvar;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       if (cam->overlay_active == false)
+               return 0;
+
+       err = ipu_disable_channel(cam->ipu, CSI_MEM, true);
+
+       ipu_uninit_channel(cam->ipu, CSI_MEM);
+
+       csi_buffer_num = 0;
+       buffer_num = 0;
+
+       for (i = 0; i < num_registered_fb; i++) {
+               char *idstr = registered_fb[i]->fix.id;
+               if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+                   ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+                       fbi = registered_fb[i];
+                       break;
+               }
+       }
+
+       if (fbi == NULL) {
+               printk(KERN_ERR "DISP FG fb not found\n");
+               return -EPERM;
+       }
+
+       console_lock();
+       fb_blank(fbi, FB_BLANK_POWERDOWN);
+       console_unlock();
+
+       /* Set the overlay frame buffer std to what it is used to be */
+       fbvar = fbi->var;
+       fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
+       fbvar.nonstd = cam->fb_origin_std;
+       fbvar.activate |= FB_ACTIVATE_FORCE;
+       fb_set_var(fbi, &fbvar);
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id)
+                               mipi_csi2_pixelclk_disable(mipi_csi2_info);
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       flush_work_sync(&cam->csi_work_struct);
+       cancel_work_sync(&cam->csi_work_struct);
+
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0],
+                                 (dma_addr_t) cam->vf_bufs[0]);
+               cam->vf_bufs_vaddr[0] = NULL;
+               cam->vf_bufs[0] = 0;
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1],
+                                 (dma_addr_t) cam->vf_bufs[1]);
+               cam->vf_bufs_vaddr[1] = NULL;
+               cam->vf_bufs[1] = 0;
+       }
+
+       cam->overlay_active = false;
+       return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int foreground_enable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int foreground_disable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       /* free csi eof irq firstly.
+        * when disable csi, wait for idmac eof.
+        * it requests eof irq again */
+       ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
+
+       return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select foreground as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int foreground_sdc_select(void *private)
+{
+       cam_data *cam;
+       int err = 0;
+       if (private) {
+               cam = (cam_data *) private;
+               cam->vf_start_sdc = foreground_start;
+               cam->vf_stop_sdc = foreground_stop;
+               cam->vf_enable_csi = foreground_enable_csi;
+               cam->vf_disable_csi = foreground_disable_csi;
+               cam->overlay_active = false;
+       } else
+               err = -EIO;
+
+       return err;
+}
+EXPORT_SYMBOL(foreground_sdc_select);
+
+/*!
+ * function to de-select foreground as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  int
+ */
+int foreground_sdc_deselect(void *private)
+{
+       cam_data *cam;
+
+       if (private) {
+               cam = (cam_data *) private;
+               cam->vf_start_sdc = NULL;
+               cam->vf_stop_sdc = NULL;
+               cam->vf_enable_csi = NULL;
+               cam->vf_disable_csi = NULL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(foreground_sdc_deselect);
+
+/*!
+ * Init viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int foreground_sdc_init(void)
+{
+       return 0;
+}
+
+/*!
+ * Deinit viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+void __exit foreground_sdc_exit(void)
+{
+}
+
+module_init(foreground_sdc_init);
+module_exit(foreground_sdc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_prp_enc.c b/drivers/media/platform/mxc/capture/ipu_prp_enc.c
new file mode 100644 (file)
index 0000000..c163127
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_prp_enc.c
+ *
+ * @brief IPU Use case for PRP-ENC
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/ipu.h>
+#include <linux/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#ifdef CAMERA_DBG
+       #define CAMERA_TRACE(x) (printk)x
+#else
+       #define CAMERA_TRACE(x)
+#endif
+
+static ipu_rotate_mode_t grotation = IPU_ROTATE_NONE;
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * IPU ENC callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prp_enc_callback(int irq, void *dev_id)
+{
+       cam_data *cam = (cam_data *) dev_id;
+
+       if (cam->enc_callback == NULL)
+               return IRQ_HANDLED;
+
+       cam->enc_callback(irq, dev_id);
+
+       return IRQ_HANDLED;
+}
+
+/*!
+ * PrpENC enable channel setup function
+ *
+ * @param cam       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_enc_setup(cam_data *cam)
+{
+       ipu_channel_params_t enc;
+       int err = 0;
+       dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       CAMERA_TRACE("In prp_enc_setup\n");
+       if (!cam) {
+               printk(KERN_ERR "cam private is NULL\n");
+               return -ENXIO;
+       }
+       memset(&enc, 0, sizeof(ipu_channel_params_t));
+
+       ipu_csi_get_window_size(cam->ipu, &enc.csi_prp_enc_mem.in_width,
+                               &enc.csi_prp_enc_mem.in_height, cam->csi);
+
+       enc.csi_prp_enc_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
+       enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.width;
+       enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.height;
+       enc.csi_prp_enc_mem.csi = cam->csi;
+       if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+               enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.height;
+               enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.width;
+       }
+
+       if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV420P;
+               pr_info("YUV420\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YVU420P;
+               pr_info("YVU420\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV422P;
+               pr_info("YUV422P\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUYV;
+               pr_info("YUYV\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_UYVY;
+               pr_info("UYVY\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_NV12;
+               pr_info("NV12\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR24;
+               pr_info("BGR24\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB24;
+               pr_info("RGB24\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB565;
+               pr_info("RGB565\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR32;
+               pr_info("BGR32\n");
+       } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) {
+               enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB32;
+               pr_info("RGB32\n");
+       } else {
+               printk(KERN_ERR "format not supported\n");
+               return -EINVAL;
+       }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id) {
+                               enc.csi_prp_enc_mem.mipi_en = true;
+                               enc.csi_prp_enc_mem.mipi_vc =
+                               mipi_csi2_get_virtual_channel(mipi_csi2_info);
+                               enc.csi_prp_enc_mem.mipi_id =
+                               mipi_csi2_get_datatype(mipi_csi2_info);
+
+                               mipi_csi2_pixelclk_enable(mipi_csi2_info);
+                       } else {
+                               enc.csi_prp_enc_mem.mipi_en = false;
+                               enc.csi_prp_enc_mem.mipi_vc = 0;
+                               enc.csi_prp_enc_mem.mipi_id = 0;
+                       }
+               } else {
+                       enc.csi_prp_enc_mem.mipi_en = false;
+                       enc.csi_prp_enc_mem.mipi_vc = 0;
+                       enc.csi_prp_enc_mem.mipi_id = 0;
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       err = ipu_init_channel(cam->ipu, CSI_PRP_ENC_MEM, &enc);
+       if (err != 0) {
+               printk(KERN_ERR "ipu_init_channel %d\n", err);
+               return err;
+       }
+
+       grotation = cam->rotation;
+       if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+               if (cam->rot_enc_bufs_vaddr[0]) {
+                       dma_free_coherent(0, cam->rot_enc_buf_size[0],
+                                         cam->rot_enc_bufs_vaddr[0],
+                                         cam->rot_enc_bufs[0]);
+               }
+               if (cam->rot_enc_bufs_vaddr[1]) {
+                       dma_free_coherent(0, cam->rot_enc_buf_size[1],
+                                         cam->rot_enc_bufs_vaddr[1],
+                                         cam->rot_enc_bufs[1]);
+               }
+               cam->rot_enc_buf_size[0] =
+                   PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+               cam->rot_enc_bufs_vaddr[0] =
+                   (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[0],
+                                              &cam->rot_enc_bufs[0],
+                                              GFP_DMA | GFP_KERNEL);
+               if (!cam->rot_enc_bufs_vaddr[0]) {
+                       printk(KERN_ERR "alloc enc_bufs0\n");
+                       return -ENOMEM;
+               }
+               cam->rot_enc_buf_size[1] =
+                   PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+               cam->rot_enc_bufs_vaddr[1] =
+                   (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[1],
+                                              &cam->rot_enc_bufs[1],
+                                              GFP_DMA | GFP_KERNEL);
+               if (!cam->rot_enc_bufs_vaddr[1]) {
+                       dma_free_coherent(0, cam->rot_enc_buf_size[0],
+                                         cam->rot_enc_bufs_vaddr[0],
+                                         cam->rot_enc_bufs[0]);
+                       cam->rot_enc_bufs_vaddr[0] = NULL;
+                       cam->rot_enc_bufs[0] = 0;
+                       printk(KERN_ERR "alloc enc_bufs1\n");
+                       return -ENOMEM;
+               }
+
+               err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+                                             IPU_OUTPUT_BUFFER,
+                                             enc.csi_prp_enc_mem.out_pixel_fmt,
+                                             enc.csi_prp_enc_mem.out_width,
+                                             enc.csi_prp_enc_mem.out_height,
+                                             enc.csi_prp_enc_mem.out_width,
+                                             IPU_ROTATE_NONE,
+                                             cam->rot_enc_bufs[0],
+                                             cam->rot_enc_bufs[1], 0, 0, 0);
+               if (err != 0) {
+                       printk(KERN_ERR "CSI_PRP_ENC_MEM err\n");
+                       return err;
+               }
+
+               err = ipu_init_channel(cam->ipu, MEM_ROT_ENC_MEM, NULL);
+               if (err != 0) {
+                       printk(KERN_ERR "MEM_ROT_ENC_MEM channel err\n");
+                       return err;
+               }
+
+               err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
+                                             IPU_INPUT_BUFFER,
+                                             enc.csi_prp_enc_mem.out_pixel_fmt,
+                                             enc.csi_prp_enc_mem.out_width,
+                                             enc.csi_prp_enc_mem.out_height,
+                                             enc.csi_prp_enc_mem.out_width,
+                                             cam->rotation,
+                                             cam->rot_enc_bufs[0],
+                                             cam->rot_enc_bufs[1], 0, 0, 0);
+               if (err != 0) {
+                       printk(KERN_ERR "MEM_ROT_ENC_MEM input buffer\n");
+                       return err;
+               }
+
+               err =
+                   ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
+                                           IPU_OUTPUT_BUFFER,
+                                           enc.csi_prp_enc_mem.out_pixel_fmt,
+                                           enc.csi_prp_enc_mem.out_height,
+                                           enc.csi_prp_enc_mem.out_width,
+                                           cam->v2f.fmt.pix.bytesperline /
+                                           bytes_per_pixel(enc.csi_prp_enc_mem.
+                                                           out_pixel_fmt),
+                                           IPU_ROTATE_NONE,
+                                           dummy, dummy, 0,
+                                           cam->offset.u_offset,
+                                           cam->offset.v_offset);
+               if (err != 0) {
+                       printk(KERN_ERR "MEM_ROT_ENC_MEM output buffer\n");
+                       return err;
+               }
+
+               err = ipu_link_channels(cam->ipu,
+                                       CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
+               if (err < 0) {
+                       printk(KERN_ERR
+                              "link CSI_PRP_ENC_MEM-MEM_ROT_ENC_MEM\n");
+                       return err;
+               }
+
+               err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
+               if (err < 0) {
+                       printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
+                       return err;
+               }
+               err = ipu_enable_channel(cam->ipu, MEM_ROT_ENC_MEM);
+               if (err < 0) {
+                       printk(KERN_ERR "ipu_enable_channel MEM_ROT_ENC_MEM\n");
+                       return err;
+               }
+
+               ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+                                 IPU_OUTPUT_BUFFER, 0);
+               ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+                                 IPU_OUTPUT_BUFFER, 1);
+       } else {
+               err =
+                   ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+                                           IPU_OUTPUT_BUFFER,
+                                           enc.csi_prp_enc_mem.out_pixel_fmt,
+                                           enc.csi_prp_enc_mem.out_width,
+                                           enc.csi_prp_enc_mem.out_height,
+                                           cam->v2f.fmt.pix.bytesperline /
+                                           bytes_per_pixel(enc.csi_prp_enc_mem.
+                                                           out_pixel_fmt),
+                                           cam->rotation,
+                                           dummy, dummy, 0,
+                                           cam->offset.u_offset,
+                                           cam->offset.v_offset);
+               if (err != 0) {
+                       printk(KERN_ERR "CSI_PRP_ENC_MEM output buffer\n");
+                       return err;
+               }
+               err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
+               if (err < 0) {
+                       printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
+                       return err;
+               }
+       }
+
+       return err;
+}
+
+/*!
+ * function to update physical buffer address for encorder IDMA channel
+ *
+ * @param eba         physical buffer address for encorder IDMA channel
+ * @param buffer_num  int buffer 0 or buffer 1
+ *
+ * @return  status
+ */
+static int prp_enc_eba_update(struct ipu_soc *ipu, dma_addr_t eba,
+                             int *buffer_num)
+{
+       int err = 0;
+
+       pr_debug("eba %x\n", eba);
+       if (grotation >= IPU_ROTATE_90_RIGHT) {
+               err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
+                                               IPU_OUTPUT_BUFFER, *buffer_num,
+                                               eba);
+       } else {
+               err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
+                                               IPU_OUTPUT_BUFFER, *buffer_num,
+                                               eba);
+       }
+       if (err != 0) {
+               if (grotation >= IPU_ROTATE_90_RIGHT) {
+                       ipu_clear_buffer_ready(ipu, MEM_ROT_ENC_MEM,
+                                              IPU_OUTPUT_BUFFER,
+                                              *buffer_num);
+                       err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
+                                                       IPU_OUTPUT_BUFFER,
+                                                       *buffer_num,
+                                                       eba);
+               } else {
+                       ipu_clear_buffer_ready(ipu, CSI_PRP_ENC_MEM,
+                                              IPU_OUTPUT_BUFFER,
+                                              *buffer_num);
+                       err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
+                                                       IPU_OUTPUT_BUFFER,
+                                                       *buffer_num,
+                                                       eba);
+               }
+
+               if (err != 0) {
+                       pr_err("ERROR: v4l2 capture: fail to update "
+                              "buf%d\n", *buffer_num);
+                       return err;
+               }
+       }
+
+       if (grotation >= IPU_ROTATE_90_RIGHT) {
+               ipu_select_buffer(ipu, MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER,
+                                 *buffer_num);
+       } else {
+               ipu_select_buffer(ipu, CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER,
+                                 *buffer_num);
+       }
+
+       *buffer_num = (*buffer_num == 0) ? 1 : 0;
+       return 0;
+}
+
+/*!
+ * Enable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_enc_enabling_tasks(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+       CAMERA_TRACE("IPU:In prp_enc_enabling_tasks\n");
+
+       cam->dummy_frame.vaddress = dma_alloc_coherent(0,
+                              PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+                              &cam->dummy_frame.paddress,
+                              GFP_DMA | GFP_KERNEL);
+       if (cam->dummy_frame.vaddress == 0) {
+               pr_err("ERROR: v4l2 capture: Allocate dummy frame "
+                      "failed.\n");
+               return -ENOBUFS;
+       }
+       cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
+       cam->dummy_frame.buffer.length =
+           PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+       cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
+
+       if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+               err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF,
+                                     prp_enc_callback, 0, "Mxc Camera", cam);
+       } else {
+               err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF,
+                                     prp_enc_callback, 0, "Mxc Camera", cam);
+       }
+       if (err != 0) {
+               printk(KERN_ERR "Error registering rot irq\n");
+               return err;
+       }
+
+       err = prp_enc_setup(cam);
+       if (err != 0) {
+               printk(KERN_ERR "prp_enc_setup %d\n", err);
+               return err;
+       }
+
+       return err;
+}
+
+/*!
+ * Disable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+static int prp_enc_disabling_tasks(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+               ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, cam);
+               ipu_unlink_channels(cam->ipu, CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
+       }
+
+       err = ipu_disable_channel(cam->ipu, CSI_PRP_ENC_MEM, true);
+       if (cam->rotation >= IPU_ROTATE_90_RIGHT)
+               err |= ipu_disable_channel(cam->ipu, MEM_ROT_ENC_MEM, true);
+
+       ipu_uninit_channel(cam->ipu, CSI_PRP_ENC_MEM);
+       if (cam->rotation >= IPU_ROTATE_90_RIGHT)
+               ipu_uninit_channel(cam->ipu, MEM_ROT_ENC_MEM);
+
+       if (cam->dummy_frame.vaddress != 0) {
+               dma_free_coherent(0, cam->dummy_frame.buffer.length,
+                                 cam->dummy_frame.vaddress,
+                                 cam->dummy_frame.paddress);
+               cam->dummy_frame.vaddress = 0;
+       }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id)
+                               mipi_csi2_pixelclk_disable(mipi_csi2_info);
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_enc_enable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_enc_disable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       /* free csi eof irq firstly.
+        * when disable csi, wait for idmac eof.
+        * it requests eof irq again */
+       if (cam->rotation < IPU_ROTATE_90_RIGHT)
+               ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, cam);
+
+       return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select PRP-ENC as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+int prp_enc_select(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+
+       if (cam) {
+               cam->enc_update_eba = prp_enc_eba_update;
+               cam->enc_enable = prp_enc_enabling_tasks;
+               cam->enc_disable = prp_enc_disabling_tasks;
+               cam->enc_enable_csi = prp_enc_enable_csi;
+               cam->enc_disable_csi = prp_enc_disable_csi;
+       } else {
+               err = -EIO;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(prp_enc_select);
+
+/*!
+ * function to de-select PRP-ENC as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+int prp_enc_deselect(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+
+       if (cam) {
+               cam->enc_update_eba = NULL;
+               cam->enc_enable = NULL;
+               cam->enc_disable = NULL;
+               cam->enc_enable_csi = NULL;
+               cam->enc_disable_csi = NULL;
+               if (cam->rot_enc_bufs_vaddr[0]) {
+                       dma_free_coherent(0, cam->rot_enc_buf_size[0],
+                                         cam->rot_enc_bufs_vaddr[0],
+                                         cam->rot_enc_bufs[0]);
+                       cam->rot_enc_bufs_vaddr[0] = NULL;
+                       cam->rot_enc_bufs[0] = 0;
+               }
+               if (cam->rot_enc_bufs_vaddr[1]) {
+                       dma_free_coherent(0, cam->rot_enc_buf_size[1],
+                                         cam->rot_enc_bufs_vaddr[1],
+                                         cam->rot_enc_bufs[1]);
+                       cam->rot_enc_bufs_vaddr[1] = NULL;
+                       cam->rot_enc_bufs[1] = 0;
+               }
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(prp_enc_deselect);
+
+/*!
+ * Init the Encorder channels
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int prp_enc_init(void)
+{
+       return 0;
+}
+
+/*!
+ * Deinit the Encorder channels
+ *
+ */
+void __exit prp_enc_exit(void)
+{
+}
+
+module_init(prp_enc_init);
+module_exit(prp_enc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP ENC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_prp_sw.h b/drivers/media/platform/mxc/capture/ipu_prp_sw.h
new file mode 100644 (file)
index 0000000..f2f7fd8
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_prp_sw.h
+ *
+ * @brief This file contains the IPU PRP use case driver header.
+ *
+ * @ingroup IPU
+ */
+
+#ifndef _INCLUDE_IPU__PRP_SW_H_
+#define _INCLUDE_IPU__PRP_SW_H_
+
+int csi_enc_select(void *private);
+int csi_enc_deselect(void *private);
+int prp_enc_select(void *private);
+int prp_enc_deselect(void *private);
+#ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+int prp_vf_sdc_select(void *private);
+int prp_vf_sdc_deselect(void *private);
+int prp_vf_sdc_select_bg(void *private);
+int prp_vf_sdc_deselect_bg(void *private);
+#else
+int foreground_sdc_select(void *private);
+int foreground_sdc_deselect(void *private);
+int bg_overlay_sdc_select(void *private);
+int bg_overlay_sdc_deselect(void *private);
+#endif
+int prp_still_select(void *private);
+int prp_still_deselect(void *private);
+
+#endif
diff --git a/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c
new file mode 100644 (file)
index 0000000..8bf5344
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/* * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_prp_vf_sdc.c
+ *
+ * @brief IPU Use case for PRP-VF
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/ipu.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <mach/hardware.h>
+#include <mach/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int buffer_num;
+static struct ipu_soc *disp_ipu;
+
+static void get_disp_ipu(cam_data *cam)
+{
+       if (cam->output > 2)
+               disp_ipu = ipu_get_soc(1); /* using DISP4 */
+       else
+               disp_ipu = ipu_get_soc(0);
+}
+
+static irqreturn_t prpvf_rot_eof_callback(int irq, void *dev_id)
+{
+       cam_data *cam = dev_id;
+       pr_debug("buffer_num %d\n",  buffer_num);
+
+       if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+               ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
+                                 IPU_INPUT_BUFFER, buffer_num);
+               buffer_num = (buffer_num == 0) ? 1 : 0;
+               ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+                                 IPU_OUTPUT_BUFFER, buffer_num);
+       } else {
+               ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
+                                 IPU_INPUT_BUFFER, buffer_num);
+               buffer_num = (buffer_num == 0) ? 1 : 0;
+               ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+                                 IPU_OUTPUT_BUFFER, buffer_num);
+       }
+       return IRQ_HANDLED;
+}
+/*
+ * Function definitions
+ */
+
+/*!
+ * prpvf_start - start the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_start(void *private)
+{
+       struct fb_var_screeninfo fbvar;
+       struct fb_info *fbi = NULL;
+       cam_data *cam = (cam_data *) private;
+       ipu_channel_params_t vf;
+       u32 vf_out_format = 0;
+       u32 size = 2, temp = 0;
+       int err = 0, i = 0;
+       short *tmp, color;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       if (!cam) {
+               printk(KERN_ERR "private is NULL\n");
+               return -EIO;
+       }
+
+       if (cam->overlay_active == true) {
+               pr_debug("already started.\n");
+               return 0;
+       }
+
+       get_disp_ipu(cam);
+
+       for (i = 0; i < num_registered_fb; i++) {
+               char *idstr = registered_fb[i]->fix.id;
+               if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+                   ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+                       fbi = registered_fb[i];
+                       break;
+               }
+       }
+
+       if (fbi == NULL) {
+               printk(KERN_ERR "DISP FG fb not found\n");
+               return -EPERM;
+       }
+
+       fbvar = fbi->var;
+
+       /* Store the overlay frame buffer's original std */
+       cam->fb_origin_std = fbvar.nonstd;
+
+       if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
+               /* Use DP to do CSC so that we can get better performance */
+               vf_out_format = IPU_PIX_FMT_UYVY;
+               fbvar.nonstd = vf_out_format;
+               color = 0x80;
+       } else {
+               vf_out_format = IPU_PIX_FMT_RGB565;
+               fbvar.nonstd = 0;
+               color = 0x0;
+       }
+
+       fbvar.bits_per_pixel = 16;
+       fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
+       fbvar.yres = cam->win.w.height;
+       fbvar.yres_virtual = cam->win.w.height * 2;
+       fbvar.yoffset = 0;
+       fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
+       fbvar.activate |= FB_ACTIVATE_FORCE;
+       fb_set_var(fbi, &fbvar);
+
+       ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left,
+                       cam->win.w.top);
+
+       /* Fill black color for framebuffer */
+       tmp = (short *) fbi->screen_base;
+       for (i = 0; i < (fbi->fix.line_length * fbi->var.yres)/2;
+                       i++, tmp++)
+               *tmp = color;
+
+       console_lock();
+       fb_blank(fbi, FB_BLANK_UNBLANK);
+       console_unlock();
+
+       /* correct display ch buffer address */
+       ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+                               0, fbi->fix.smem_start +
+                               (fbi->fix.line_length * fbvar.yres));
+       ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+                                       1, fbi->fix.smem_start);
+
+       memset(&vf, 0, sizeof(ipu_channel_params_t));
+       ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
+                               &vf.csi_prp_vf_mem.in_height, cam->csi);
+       vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
+       vf.csi_prp_vf_mem.out_width = cam->win.w.width;
+       vf.csi_prp_vf_mem.out_height = cam->win.w.height;
+       vf.csi_prp_vf_mem.csi = cam->csi;
+       if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+               vf.csi_prp_vf_mem.out_width = cam->win.w.height;
+               vf.csi_prp_vf_mem.out_height = cam->win.w.width;
+       }
+       vf.csi_prp_vf_mem.out_pixel_fmt = vf_out_format;
+       size = cam->win.w.width * cam->win.w.height * size;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id) {
+                               vf.csi_prp_vf_mem.mipi_en = true;
+                               vf.csi_prp_vf_mem.mipi_vc =
+                               mipi_csi2_get_virtual_channel(mipi_csi2_info);
+                               vf.csi_prp_vf_mem.mipi_id =
+                               mipi_csi2_get_datatype(mipi_csi2_info);
+
+                               mipi_csi2_pixelclk_enable(mipi_csi2_info);
+                       } else {
+                               vf.csi_prp_vf_mem.mipi_en = false;
+                               vf.csi_prp_vf_mem.mipi_vc = 0;
+                               vf.csi_prp_vf_mem.mipi_id = 0;
+                       }
+               } else {
+                       vf.csi_prp_vf_mem.mipi_en = false;
+                       vf.csi_prp_vf_mem.mipi_vc = 0;
+                       vf.csi_prp_vf_mem.mipi_id = 0;
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
+       if (err != 0)
+               goto out_5;
+
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0],
+                                 (dma_addr_t) cam->vf_bufs[0]);
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1],
+                                 (dma_addr_t) cam->vf_bufs[1]);
+       }
+       cam->vf_bufs_size[0] = PAGE_ALIGN(size);
+       cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
+                                                          cam->vf_bufs_size[0],
+                                                          (dma_addr_t *) &
+                                                          cam->vf_bufs[0],
+                                                          GFP_DMA |
+                                                          GFP_KERNEL);
+       if (cam->vf_bufs_vaddr[0] == NULL) {
+               printk(KERN_ERR "Error to allocate vf buffer\n");
+               err = -ENOMEM;
+               goto out_4;
+       }
+       cam->vf_bufs_size[1] = PAGE_ALIGN(size);
+       cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
+                                                          cam->vf_bufs_size[1],
+                                                          (dma_addr_t *) &
+                                                          cam->vf_bufs[1],
+                                                          GFP_DMA |
+                                                          GFP_KERNEL);
+       if (cam->vf_bufs_vaddr[1] == NULL) {
+               printk(KERN_ERR "Error to allocate vf buffer\n");
+               err = -ENOMEM;
+               goto out_3;
+       }
+       pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
+
+       if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+               err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
+                                             IPU_OUTPUT_BUFFER,
+                                             vf_out_format,
+                                             vf.csi_prp_vf_mem.out_width,
+                                             vf.csi_prp_vf_mem.out_height,
+                                             vf.csi_prp_vf_mem.out_width,
+                                             IPU_ROTATE_NONE,
+                                             cam->vf_bufs[0], cam->vf_bufs[1],
+                                             0, 0, 0);
+               if (err != 0)
+                       goto out_3;
+
+               err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
+               if (err != 0) {
+                       printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
+                       goto out_3;
+               }
+
+               err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+                                             IPU_INPUT_BUFFER,
+                                             vf_out_format,
+                                             vf.csi_prp_vf_mem.out_width,
+                                             vf.csi_prp_vf_mem.out_height,
+                                             vf.csi_prp_vf_mem.out_width,
+                                             cam->vf_rotation,
+                                             cam->vf_bufs[0],
+                                             cam->vf_bufs[1],
+                                             0, 0, 0);
+               if (err != 0) {
+                       printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
+                       goto out_2;
+               }
+
+               if (cam->vf_rotation < IPU_ROTATE_90_RIGHT) {
+                       temp = vf.csi_prp_vf_mem.out_width;
+                       vf.csi_prp_vf_mem.out_width =
+                                               vf.csi_prp_vf_mem.out_height;
+                       vf.csi_prp_vf_mem.out_height = temp;
+               }
+
+               err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+                                             IPU_OUTPUT_BUFFER,
+                                             vf_out_format,
+                                             vf.csi_prp_vf_mem.out_height,
+                                             vf.csi_prp_vf_mem.out_width,
+                                             vf.csi_prp_vf_mem.out_height,
+                                             IPU_ROTATE_NONE,
+                                             fbi->fix.smem_start +
+                                             (fbi->fix.line_length *
+                                              fbi->var.yres),
+                                             fbi->fix.smem_start, 0, 0, 0);
+
+               if (err != 0) {
+                       printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
+                       goto out_2;
+               }
+
+               ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF);
+               err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF,
+                                     prpvf_rot_eof_callback,
+                             0, "Mxc Camera", cam);
+               if (err < 0) {
+                       printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_ROT_OUT_EOF\n");
+                       goto out_2;
+               }
+
+               err = ipu_link_channels(cam->ipu,
+                                       CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
+               if (err < 0) {
+                       printk(KERN_ERR
+                              "Error link CSI_PRP_VF_MEM-MEM_ROT_VF_MEM\n");
+                       goto out_1;
+               }
+
+               ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
+               ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
+
+               ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+                                 IPU_OUTPUT_BUFFER, 0);
+               ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+                                 IPU_OUTPUT_BUFFER, 1);
+               ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+                                 IPU_OUTPUT_BUFFER, 0);
+       } else {
+               err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
+                                             IPU_OUTPUT_BUFFER,
+                                             vf_out_format, cam->win.w.width,
+                                             cam->win.w.height,
+                                             cam->win.w.width,
+                                             cam->vf_rotation,
+                                             fbi->fix.smem_start +
+                                             (fbi->fix.line_length *
+                                              fbi->var.yres),
+                                             fbi->fix.smem_start, 0, 0, 0);
+               if (err != 0) {
+                       printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
+                       goto out_4;
+               }
+               ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+               err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
+                                     prpvf_rot_eof_callback,
+                             0, "Mxc Camera", cam);
+               if (err < 0) {
+                       printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_OUT_EOF\n");
+                       goto out_4;
+               }
+
+               ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
+
+               ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+                                 IPU_OUTPUT_BUFFER, 0);
+       }
+
+       cam->overlay_active = true;
+       return err;
+
+out_1:
+       ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
+out_2:
+       if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP)
+               ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+out_3:
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0],
+                                 (dma_addr_t) cam->vf_bufs[0]);
+               cam->vf_bufs_vaddr[0] = NULL;
+               cam->vf_bufs[0] = 0;
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1],
+                                 (dma_addr_t) cam->vf_bufs[1]);
+               cam->vf_bufs_vaddr[1] = NULL;
+               cam->vf_bufs[1] = 0;
+       }
+out_4:
+       ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+out_5:
+       return err;
+}
+
+/*!
+ * prpvf_stop - stop the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_stop(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0, i = 0;
+       struct fb_info *fbi = NULL;
+       struct fb_var_screeninfo fbvar;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       if (cam->overlay_active == false)
+               return 0;
+
+       for (i = 0; i < num_registered_fb; i++) {
+               char *idstr = registered_fb[i]->fix.id;
+               if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+                   ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+                       fbi = registered_fb[i];
+                       break;
+               }
+       }
+
+       if (fbi == NULL) {
+               printk(KERN_ERR "DISP FG fb not found\n");
+               return -EPERM;
+       }
+
+       if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+               ipu_unlink_channels(cam->ipu, CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
+               ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, cam);
+       }
+       buffer_num = 0;
+
+       ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
+
+       if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+               ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
+               ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+       }
+       ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+
+       console_lock();
+       fb_blank(fbi, FB_BLANK_POWERDOWN);
+       console_unlock();
+
+       /* Set the overlay frame buffer std to what it is used to be */
+       fbvar = fbi->var;
+       fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
+       fbvar.nonstd = cam->fb_origin_std;
+       fbvar.activate |= FB_ACTIVATE_FORCE;
+       fb_set_var(fbi, &fbvar);
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id)
+                               mipi_csi2_pixelclk_disable(mipi_csi2_info);
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0],
+                                 (dma_addr_t) cam->vf_bufs[0]);
+               cam->vf_bufs_vaddr[0] = NULL;
+               cam->vf_bufs[0] = 0;
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1],
+                                 (dma_addr_t) cam->vf_bufs[1]);
+               cam->vf_bufs_vaddr[1] = NULL;
+               cam->vf_bufs[1] = 0;
+       }
+
+       cam->overlay_active = false;
+       return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_vf_enable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_vf_disable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       /* free csi eof irq firstly.
+        * when disable csi, wait for idmac eof.
+        * it requests eof irq again */
+       if (cam->vf_rotation < IPU_ROTATE_VERT_FLIP)
+               ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
+
+       return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select PRP-VF as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int prp_vf_sdc_select(void *private)
+{
+       cam_data *cam;
+       int err = 0;
+       if (private) {
+               cam = (cam_data *) private;
+               cam->vf_start_sdc = prpvf_start;
+               cam->vf_stop_sdc = prpvf_stop;
+               cam->vf_enable_csi = prp_vf_enable_csi;
+               cam->vf_disable_csi = prp_vf_disable_csi;
+               cam->overlay_active = false;
+       } else
+               err = -EIO;
+
+       return err;
+}
+EXPORT_SYMBOL(prp_vf_sdc_select);
+
+/*!
+ * function to de-select PRP-VF as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  int
+ */
+int prp_vf_sdc_deselect(void *private)
+{
+       cam_data *cam;
+
+       if (private) {
+               cam = (cam_data *) private;
+               cam->vf_start_sdc = NULL;
+               cam->vf_stop_sdc = NULL;
+               cam->vf_enable_csi = NULL;
+               cam->vf_disable_csi = NULL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(prp_vf_sdc_deselect);
+
+/*!
+ * Init viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int prp_vf_sdc_init(void)
+{
+       return 0;
+}
+
+/*!
+ * Deinit viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+void __exit prp_vf_sdc_exit(void)
+{
+}
+
+module_init(prp_vf_sdc_init);
+module_exit(prp_vf_sdc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c
new file mode 100644 (file)
index 0000000..2667fca
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_prp_vf_sdc_bg.c
+ *
+ * @brief IPU Use case for PRP-VF back-ground
+ *
+ * @ingroup IPU
+ */
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/ipu.h>
+#include <linux/module.h>
+#include <mach/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int buffer_num;
+static int buffer_ready;
+static struct ipu_soc *disp_ipu;
+
+static void get_disp_ipu(cam_data *cam)
+{
+       if (cam->output > 2)
+               disp_ipu = ipu_get_soc(1); /* using DISP4 */
+       else
+               disp_ipu = ipu_get_soc(0);
+}
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * SDC V-Sync callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prpvf_sdc_vsync_callback(int irq, void *dev_id)
+{
+       cam_data *cam = dev_id;
+       if (buffer_ready > 0) {
+               ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+                                 IPU_OUTPUT_BUFFER, 0);
+               buffer_ready--;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*!
+ * VF EOF callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prpvf_vf_eof_callback(int irq, void *dev_id)
+{
+       cam_data *cam = dev_id;
+       pr_debug("buffer_ready %d buffer_num %d\n", buffer_ready, buffer_num);
+
+       ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+                         IPU_INPUT_BUFFER, buffer_num);
+       buffer_num = (buffer_num == 0) ? 1 : 0;
+       ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+                         IPU_OUTPUT_BUFFER, buffer_num);
+       buffer_ready++;
+       return IRQ_HANDLED;
+}
+
+/*!
+ * prpvf_start - start the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_start(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       ipu_channel_params_t vf;
+       u32 format;
+       u32 offset;
+       u32 bpp, size = 3;
+       int err = 0;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       if (!cam) {
+               printk(KERN_ERR "private is NULL\n");
+               return -EIO;
+       }
+
+       if (cam->overlay_active == true) {
+               pr_debug("already start.\n");
+               return 0;
+       }
+
+       get_disp_ipu(cam);
+
+       format = cam->v4l2_fb.fmt.pixelformat;
+       if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
+               bpp = 3, size = 3;
+               pr_info("BGR24\n");
+       } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
+               bpp = 2, size = 2;
+               pr_info("RGB565\n");
+       } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
+               bpp = 4, size = 4;
+               pr_info("BGR32\n");
+       } else {
+               printk(KERN_ERR
+                      "unsupported fix format from the framebuffer.\n");
+               return -EINVAL;
+       }
+
+       offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
+           size * cam->win.w.left;
+
+       if (cam->v4l2_fb.base == 0)
+               printk(KERN_ERR "invalid frame buffer address.\n");
+       else
+               offset += (u32) cam->v4l2_fb.base;
+
+       memset(&vf, 0, sizeof(ipu_channel_params_t));
+       ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
+                               &vf.csi_prp_vf_mem.in_height, cam->csi);
+       vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
+       vf.csi_prp_vf_mem.out_width = cam->win.w.width;
+       vf.csi_prp_vf_mem.out_height = cam->win.w.height;
+       vf.csi_prp_vf_mem.csi = cam->csi;
+       if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+               vf.csi_prp_vf_mem.out_width = cam->win.w.height;
+               vf.csi_prp_vf_mem.out_height = cam->win.w.width;
+       }
+       vf.csi_prp_vf_mem.out_pixel_fmt = format;
+       size = cam->win.w.width * cam->win.w.height * size;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id) {
+                               vf.csi_prp_vf_mem.mipi_en = true;
+                               vf.csi_prp_vf_mem.mipi_vc =
+                               mipi_csi2_get_virtual_channel(mipi_csi2_info);
+                               vf.csi_prp_vf_mem.mipi_id =
+                               mipi_csi2_get_datatype(mipi_csi2_info);
+
+                               mipi_csi2_pixelclk_enable(mipi_csi2_info);
+                       } else {
+                               vf.csi_prp_vf_mem.mipi_en = false;
+                               vf.csi_prp_vf_mem.mipi_vc = 0;
+                               vf.csi_prp_vf_mem.mipi_id = 0;
+                       }
+               } else {
+                       vf.csi_prp_vf_mem.mipi_en = false;
+                       vf.csi_prp_vf_mem.mipi_vc = 0;
+                       vf.csi_prp_vf_mem.mipi_id = 0;
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
+       if (err != 0)
+               goto out_4;
+
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+       }
+       cam->vf_bufs_size[0] = PAGE_ALIGN(size);
+       cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
+                                                          cam->vf_bufs_size[0],
+                                                          &cam->vf_bufs[0],
+                                                          GFP_DMA |
+                                                          GFP_KERNEL);
+       if (cam->vf_bufs_vaddr[0] == NULL) {
+               printk(KERN_ERR "Error to allocate vf buffer\n");
+               err = -ENOMEM;
+               goto out_3;
+       }
+       cam->vf_bufs_size[1] = PAGE_ALIGN(size);
+       cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
+                                                          cam->vf_bufs_size[1],
+                                                          &cam->vf_bufs[1],
+                                                          GFP_DMA |
+                                                          GFP_KERNEL);
+       if (cam->vf_bufs_vaddr[1] == NULL) {
+               printk(KERN_ERR "Error to allocate vf buffer\n");
+               err = -ENOMEM;
+               goto out_3;
+       }
+
+       err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
+                                     IPU_OUTPUT_BUFFER,
+                                     format, vf.csi_prp_vf_mem.out_width,
+                                     vf.csi_prp_vf_mem.out_height,
+                                     vf.csi_prp_vf_mem.out_width,
+                                     IPU_ROTATE_NONE,
+                                     cam->vf_bufs[0],
+                                     cam->vf_bufs[1],
+                                     0, 0, 0);
+       if (err != 0) {
+               printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
+               goto out_3;
+       }
+       err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
+       if (err != 0) {
+               printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
+               goto out_3;
+       }
+
+       err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+                                     IPU_INPUT_BUFFER,
+                                     format, vf.csi_prp_vf_mem.out_width,
+                                     vf.csi_prp_vf_mem.out_height,
+                                     vf.csi_prp_vf_mem.out_width,
+                                     cam->vf_rotation,
+                                     cam->vf_bufs[0],
+                                     cam->vf_bufs[1],
+                                     0, 0, 0);
+       if (err != 0) {
+               printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
+               goto out_2;
+       }
+
+       if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+               err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+                                             IPU_OUTPUT_BUFFER,
+                                             format,
+                                             vf.csi_prp_vf_mem.out_height,
+                                             vf.csi_prp_vf_mem.out_width,
+                                             cam->overlay_fb->var.xres * bpp,
+                                             IPU_ROTATE_NONE,
+                                             offset, 0, 0, 0, 0);
+
+               if (err != 0) {
+                       printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
+                       goto out_2;
+               }
+       } else {
+               err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+                                             IPU_OUTPUT_BUFFER,
+                                             format,
+                                             vf.csi_prp_vf_mem.out_width,
+                                             vf.csi_prp_vf_mem.out_height,
+                                             cam->overlay_fb->var.xres * bpp,
+                                             IPU_ROTATE_NONE,
+                                             offset, 0, 0, 0, 0);
+               if (err != 0) {
+                       printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
+                       goto out_2;
+               }
+       }
+
+       ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+       err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
+                             prpvf_vf_eof_callback,
+                             0, "Mxc Camera", cam);
+       if (err != 0) {
+               printk(KERN_ERR
+                      "Error registering IPU_IRQ_PRP_VF_OUT_EOF irq.\n");
+               goto out_2;
+       }
+
+       ipu_clear_irq(disp_ipu, IPU_IRQ_BG_SF_END);
+       err = ipu_request_irq(disp_ipu, IPU_IRQ_BG_SF_END,
+                             prpvf_sdc_vsync_callback,
+                             0, "Mxc Camera", cam);
+       if (err != 0) {
+               printk(KERN_ERR "Error registering IPU_IRQ_BG_SF_END irq.\n");
+               goto out_1;
+       }
+
+       ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
+       ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
+
+       buffer_num = 0;
+       buffer_ready = 0;
+       ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0);
+
+       cam->overlay_active = true;
+       return err;
+
+out_1:
+       ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
+out_2:
+       ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+out_3:
+       ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+out_4:
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+               cam->vf_bufs_vaddr[0] = NULL;
+               cam->vf_bufs[0] = 0;
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+               cam->vf_bufs_vaddr[1] = NULL;
+               cam->vf_bufs[1] = 0;
+       }
+       if (cam->rot_vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->rot_vf_buf_size[0],
+                                 cam->rot_vf_bufs_vaddr[0],
+                                 cam->rot_vf_bufs[0]);
+               cam->rot_vf_bufs_vaddr[0] = NULL;
+               cam->rot_vf_bufs[0] = 0;
+       }
+       if (cam->rot_vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->rot_vf_buf_size[1],
+                                 cam->rot_vf_bufs_vaddr[1],
+                                 cam->rot_vf_bufs[1]);
+               cam->rot_vf_bufs_vaddr[1] = NULL;
+               cam->rot_vf_bufs[1] = 0;
+       }
+       return err;
+}
+
+/*!
+ * prpvf_stop - stop the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_stop(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+#ifdef CONFIG_MXC_MIPI_CSI2
+       void *mipi_csi2_info;
+       int ipu_id;
+       int csi_id;
+#endif
+
+       if (cam->overlay_active == false)
+               return 0;
+
+       ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam);
+
+       ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
+       ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
+       ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+       ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+       mipi_csi2_info = mipi_csi2_get_info();
+
+       if (mipi_csi2_info) {
+               if (mipi_csi2_get_status(mipi_csi2_info)) {
+                       ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+                       csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+                       if (cam->ipu == ipu_get_soc(ipu_id)
+                               && cam->csi == csi_id)
+                               mipi_csi2_pixelclk_disable(mipi_csi2_info);
+               }
+       } else {
+               printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+                      __func__, __FILE__);
+               return -EPERM;
+       }
+#endif
+
+       if (cam->vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->vf_bufs_size[0],
+                                 cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+               cam->vf_bufs_vaddr[0] = NULL;
+               cam->vf_bufs[0] = 0;
+       }
+       if (cam->vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->vf_bufs_size[1],
+                                 cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+               cam->vf_bufs_vaddr[1] = NULL;
+               cam->vf_bufs[1] = 0;
+       }
+       if (cam->rot_vf_bufs_vaddr[0]) {
+               dma_free_coherent(0, cam->rot_vf_buf_size[0],
+                                 cam->rot_vf_bufs_vaddr[0],
+                                 cam->rot_vf_bufs[0]);
+               cam->rot_vf_bufs_vaddr[0] = NULL;
+               cam->rot_vf_bufs[0] = 0;
+       }
+       if (cam->rot_vf_bufs_vaddr[1]) {
+               dma_free_coherent(0, cam->rot_vf_buf_size[1],
+                                 cam->rot_vf_bufs_vaddr[1],
+                                 cam->rot_vf_bufs[1]);
+               cam->rot_vf_bufs_vaddr[1] = NULL;
+               cam->rot_vf_bufs[1] = 0;
+       }
+
+       buffer_num = 0;
+       buffer_ready = 0;
+       cam->overlay_active = false;
+       return 0;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_vf_enable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_vf_disable_csi(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       /* free csi eof irq firstly.
+        * when disable csi, wait for idmac eof.
+        * it requests eof irq again */
+       ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
+
+       return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select PRP-VF as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int prp_vf_sdc_select_bg(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       if (cam) {
+               cam->vf_start_sdc = prpvf_start;
+               cam->vf_stop_sdc = prpvf_stop;
+               cam->vf_enable_csi = prp_vf_enable_csi;
+               cam->vf_disable_csi = prp_vf_disable_csi;
+               cam->overlay_active = false;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(prp_vf_sdc_select_bg);
+
+/*!
+ * function to de-select PRP-VF as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int prp_vf_sdc_deselect_bg(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       if (cam) {
+               cam->vf_start_sdc = NULL;
+               cam->vf_stop_sdc = NULL;
+               cam->vf_enable_csi = NULL;
+               cam->vf_disable_csi = NULL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(prp_vf_sdc_deselect_bg);
+
+/*!
+ * Init viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int prp_vf_sdc_init_bg(void)
+{
+       return 0;
+}
+
+/*!
+ * Deinit viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+void __exit prp_vf_sdc_exit_bg(void)
+{
+}
+
+module_init(prp_vf_sdc_init_bg);
+module_exit(prp_vf_sdc_exit_bg);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_still.c b/drivers/media/platform/mxc/capture/ipu_still.c
new file mode 100644 (file)
index 0000000..b295a18
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_still.c
+ *
+ * @brief IPU Use case for still image capture
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/semaphore.h>
+#include <linux/sched.h>
+#include <linux/ipu.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int callback_eof_flag;
+#ifndef CONFIG_MXC_IPU_V1
+static int buffer_num;
+#endif
+
+#ifdef CONFIG_MXC_IPU_V1
+static int callback_flag;
+/*
+ * Function definitions
+ */
+/*!
+ * CSI EOF callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id)
+{
+       cam_data *cam = devid;
+       ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+                         callback_flag%2 ? 1 : 0);
+       if (callback_flag == 0)
+               ipu_enable_channel(cam->ipu, CSI_MEM);
+
+       callback_flag++;
+       return IRQ_HANDLED;
+}
+#endif
+
+/*!
+ * CSI callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prp_still_callback(int irq, void *dev_id)
+{
+       cam_data *cam = (cam_data *) dev_id;
+
+       callback_eof_flag++;
+       if (callback_eof_flag < 5) {
+#ifndef CONFIG_MXC_IPU_V1
+               buffer_num = (buffer_num == 0) ? 1 : 0;
+               ipu_select_buffer(cam->ipu, CSI_MEM,
+                                 IPU_OUTPUT_BUFFER, buffer_num);
+#endif
+       } else {
+               cam->still_counter++;
+               wake_up_interruptible(&cam->still_queue);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*!
+ * start csi->mem task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_still_start(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       u32 pixel_fmt;
+       int err;
+       ipu_channel_params_t params;
+
+       if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+               pixel_fmt = IPU_PIX_FMT_YUV420P;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
+               pixel_fmt = IPU_PIX_FMT_NV12;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P)
+               pixel_fmt = IPU_PIX_FMT_YUV422P;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
+               pixel_fmt = IPU_PIX_FMT_UYVY;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+               pixel_fmt = IPU_PIX_FMT_YUYV;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
+               pixel_fmt = IPU_PIX_FMT_BGR24;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
+               pixel_fmt = IPU_PIX_FMT_RGB24;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
+               pixel_fmt = IPU_PIX_FMT_RGB565;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
+               pixel_fmt = IPU_PIX_FMT_BGR32;
+       else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
+               pixel_fmt = IPU_PIX_FMT_RGB32;
+       else {
+               printk(KERN_ERR "format not supported\n");
+               return -EINVAL;
+       }
+
+       memset(&params, 0, sizeof(params));
+       err = ipu_init_channel(cam->ipu, CSI_MEM, &params);
+       if (err != 0)
+               return err;
+
+       err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+                                     pixel_fmt, cam->v2f.fmt.pix.width,
+                                     cam->v2f.fmt.pix.height,
+                                     cam->v2f.fmt.pix.width, IPU_ROTATE_NONE,
+                                     cam->still_buf[0], cam->still_buf[1], 0,
+                                     0, 0);
+       if (err != 0)
+               return err;
+
+#ifdef CONFIG_MXC_IPU_V1
+       ipu_clear_irq(IPU_IRQ_SENSOR_OUT_EOF);
+       err = ipu_request_irq(IPU_IRQ_SENSOR_OUT_EOF, prp_still_callback,
+                             0, "Mxc Camera", cam);
+       if (err != 0) {
+               printk(KERN_ERR "Error registering irq.\n");
+               return err;
+       }
+       callback_flag = 0;
+       callback_eof_flag = 0;
+       ipu_clear_irq(IPU_IRQ_SENSOR_EOF);
+       err = ipu_request_irq(IPU_IRQ_SENSOR_EOF, prp_csi_eof_callback,
+                             0, "Mxc Camera", cam);
+       if (err != 0) {
+               printk(KERN_ERR "Error IPU_IRQ_SENSOR_EOF\n");
+               return err;
+       }
+#else
+       callback_eof_flag = 0;
+       buffer_num = 0;
+
+       ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
+       err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
+                             prp_still_callback,
+                             0, "Mxc Camera", cam);
+       if (err != 0) {
+               printk(KERN_ERR "Error registering irq.\n");
+               return err;
+       }
+
+       ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0);
+       ipu_enable_channel(cam->ipu, CSI_MEM);
+       ipu_enable_csi(cam->ipu, cam->csi);
+#endif
+
+       return err;
+}
+
+/*!
+ * stop csi->mem encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_still_stop(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+
+#ifdef CONFIG_MXC_IPU_V1
+       ipu_free_irq(IPU_IRQ_SENSOR_EOF, NULL);
+       ipu_free_irq(IPU_IRQ_SENSOR_OUT_EOF, cam);
+#else
+       ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
+#endif
+
+       ipu_disable_csi(cam->ipu, cam->csi);
+       ipu_disable_channel(cam->ipu, CSI_MEM, true);
+       ipu_uninit_channel(cam->ipu, CSI_MEM);
+
+       return err;
+}
+
+/*!
+ * function to select CSI_MEM as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+int prp_still_select(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+
+       if (cam) {
+               cam->csi_start = prp_still_start;
+               cam->csi_stop = prp_still_stop;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(prp_still_select);
+
+/*!
+ * function to de-select CSI_MEM as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+int prp_still_deselect(void *private)
+{
+       cam_data *cam = (cam_data *) private;
+       int err = 0;
+
+       err = prp_still_stop(cam);
+
+       if (cam) {
+               cam->csi_start = NULL;
+               cam->csi_stop = NULL;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(prp_still_deselect);
+
+/*!
+ * Init the Encorder channels
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int prp_still_init(void)
+{
+       return 0;
+}
+
+/*!
+ * Deinit the Encorder channels
+ *
+ */
+void __exit prp_still_exit(void)
+{
+}
+
+module_init(prp_still_init);
+module_exit(prp_still_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP STILL IMAGE Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c
new file mode 100755 (executable)
index 0000000..22b90d3
--- /dev/null
@@ -0,0 +1,3110 @@
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file drivers/media/video/mxc/capture/mxc_v4l2_capture.c
+ *
+ * @brief Mxc Video For Linux 2 driver
+ *
+ * @ingroup MXC_V4L2_CAPTURE
+ */
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/semaphore.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/mxcfb.h>
+#include <linux/of_device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-int-device.h>
+#include <linux/fsl_devices.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#define init_MUTEX(sem)         sema_init(sem, 1)
+#define MXC_SENSOR_NUM 2
+
+static struct platform_device_id imx_v4l2_devtype[] = {
+       {
+               .name = "v4l2-capture-imx5",
+               .driver_data = IMX5_V4L2,
+       }, {
+               .name = "v4l2-capture-imx6",
+               .driver_data = IMX6_V4L2,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, imx_v4l2_devtype);
+
+static const struct of_device_id mxc_v4l2_dt_ids[] = {
+       {
+               .compatible = "fsl,imx6q-v4l2-capture",
+               .data = &imx_v4l2_devtype[IMX6_V4L2],
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, mxc_v4l2_dt_ids);
+
+static int video_nr = -1;
+
+/*! This data is used for the output to the display. */
+#define MXC_V4L2_CAPTURE_NUM_OUTPUTS   6
+#define MXC_V4L2_CAPTURE_NUM_INPUTS    2
+static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = {
+       {
+        .index = 0,
+        .name = "DISP3 BG",
+        .type = V4L2_OUTPUT_TYPE_ANALOG,
+        .audioset = 0,
+        .modulator = 0,
+        .std = V4L2_STD_UNKNOWN,
+        },
+       {
+        .index = 1,
+        .name = "DISP3 BG - DI1",
+        .type = V4L2_OUTPUT_TYPE_ANALOG,
+        .audioset = 0,
+        .modulator = 0,
+        .std = V4L2_STD_UNKNOWN,
+        },
+       {
+        .index = 2,
+        .name = "DISP3 FG",
+        .type = V4L2_OUTPUT_TYPE_ANALOG,
+        .audioset = 0,
+        .modulator = 0,
+        .std = V4L2_STD_UNKNOWN,
+        },
+       {
+        .index = 3,
+        .name = "DISP4 BG",
+        .type = V4L2_OUTPUT_TYPE_ANALOG,
+        .audioset = 0,
+        .modulator = 0,
+        .std = V4L2_STD_UNKNOWN,
+        },
+       {
+        .index = 4,
+        .name = "DISP4 BG - DI1",
+        .type = V4L2_OUTPUT_TYPE_ANALOG,
+        .audioset = 0,
+        .modulator = 0,
+        .std = V4L2_STD_UNKNOWN,
+        },
+       {
+        .index = 5,
+        .name = "DISP4 FG",
+        .type = V4L2_OUTPUT_TYPE_ANALOG,
+        .audioset = 0,
+        .modulator = 0,
+        .std = V4L2_STD_UNKNOWN,
+        },
+};
+
+static struct v4l2_input mxc_capture_inputs[MXC_V4L2_CAPTURE_NUM_INPUTS] = {
+       {
+        .index = 0,
+        .name = "CSI IC MEM",
+        .type = V4L2_INPUT_TYPE_CAMERA,
+        .audioset = 0,
+        .tuner = 0,
+        .std = V4L2_STD_UNKNOWN,
+        .status = 0,
+        },
+       {
+        .index = 1,
+        .name = "CSI MEM",
+        .type = V4L2_INPUT_TYPE_CAMERA,
+        .audioset = 0,
+        .tuner = 0,
+        .std = V4L2_STD_UNKNOWN,
+        .status = V4L2_IN_ST_NO_POWER,
+        },
+};
+
+/*! List of TV input video formats supported. The video formats is corresponding
+ * to the v4l2_id in video_fmt_t.
+ * Currently, only PAL and NTSC is supported. Needs to be expanded in the
+ * future.
+ */
+typedef enum {
+       TV_NTSC = 0,            /*!< Locked on (M) NTSC video signal. */
+       TV_PAL,                 /*!< (B, G, H, I, N)PAL video signal. */
+       TV_NOT_LOCKED,          /*!< Not locked on a signal. */
+} video_fmt_idx;
+
+/*! Number of video standards supported (including 'not locked' signal). */
+#define TV_STD_MAX             (TV_NOT_LOCKED + 1)
+
+/*! Video format structure. */
+typedef struct {
+       int v4l2_id;            /*!< Video for linux ID. */
+       char name[16];          /*!< Name (e.g., "NTSC", "PAL", etc.) */
+       u16 raw_width;          /*!< Raw width. */
+       u16 raw_height;         /*!< Raw height. */
+       u16 active_width;       /*!< Active width. */
+       u16 active_height;      /*!< Active height. */
+       u16 active_top;         /*!< Active top. */
+       u16 active_left;        /*!< Active left. */
+} video_fmt_t;
+
+/*!
+ * Description of video formats supported.
+ *
+ *  PAL: raw=720x625, active=720x576.
+ *  NTSC: raw=720x525, active=720x480.
+ */
+static video_fmt_t video_fmts[] = {
+       {                       /*! NTSC */
+        .v4l2_id = V4L2_STD_NTSC,
+        .name = "NTSC",
+        .raw_width = 720,              /* SENS_FRM_WIDTH */
+        .raw_height = 525,             /* SENS_FRM_HEIGHT */
+        .active_width = 720,           /* ACT_FRM_WIDTH */
+        .active_height = 480,          /* ACT_FRM_HEIGHT */
+        .active_top = 13,
+        .active_left = 0,
+        },
+       {                       /*! (B, G, H, I, N) PAL */
+        .v4l2_id = V4L2_STD_PAL,
+        .name = "PAL",
+        .raw_width = 720,
+        .raw_height = 625,
+        .active_width = 720,
+        .active_height = 576,
+        .active_top = 0,
+        .active_left = 0,
+        },
+       {                       /*! Unlocked standard */
+        .v4l2_id = V4L2_STD_ALL,
+        .name = "Autodetect",
+        .raw_width = 720,
+        .raw_height = 625,
+        .active_width = 720,
+        .active_height = 576,
+        .active_top = 0,
+        .active_left = 0,
+        },
+};
+
+/*!* Standard index of TV. */
+static video_fmt_idx video_index = TV_NOT_LOCKED;
+
+static int mxc_v4l2_master_attach(struct v4l2_int_device *slave);
+static void mxc_v4l2_master_detach(struct v4l2_int_device *slave);
+static int start_preview(cam_data *cam);
+static int stop_preview(cam_data *cam);
+
+/*! Information about this driver. */
+static struct v4l2_int_master mxc_v4l2_master = {
+       .attach = mxc_v4l2_master_attach,
+       .detach = mxc_v4l2_master_detach,
+};
+
+/***************************************************************************
+ * Functions for handling Frame buffers.
+ **************************************************************************/
+
+/*!
+ * Free frame buffers
+ *
+ * @param cam      Structure cam_data *
+ *
+ * @return status  0 success.
+ */
+static int mxc_free_frame_buf(cam_data *cam)
+{
+       int i;
+
+       pr_debug("MVC: In mxc_free_frame_buf\n");
+
+       for (i = 0; i < FRAME_NUM; i++) {
+               if (cam->frame[i].vaddress != 0) {
+                       dma_free_coherent(0, cam->frame[i].buffer.length,
+                                         cam->frame[i].vaddress,
+                                         cam->frame[i].paddress);
+                       cam->frame[i].vaddress = 0;
+               }
+       }
+
+       return 0;
+}
+
+/*!
+ * Allocate frame buffers
+ *
+ * @param cam      Structure cam_data*
+ * @param count    int number of buffer need to allocated
+ *
+ * @return status  -0 Successfully allocated a buffer, -ENOBUFS        failed.
+ */
+static int mxc_allocate_frame_buf(cam_data *cam, int count)
+{
+       int i;
+
+       pr_debug("In MVC:mxc_allocate_frame_buf - size=%d\n",
+               cam->v2f.fmt.pix.sizeimage);
+
+       for (i = 0; i < count; i++) {
+               cam->frame[i].vaddress =
+                   dma_alloc_coherent(0,
+                                      PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+                                      &cam->frame[i].paddress,
+                                      GFP_DMA | GFP_KERNEL);
+               if (cam->frame[i].vaddress == 0) {
+                       pr_err("ERROR: v4l2 capture: "
+                               "mxc_allocate_frame_buf failed.\n");
+                       mxc_free_frame_buf(cam);
+                       return -ENOBUFS;
+               }
+               cam->frame[i].buffer.index = i;
+               cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
+               cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cam->frame[i].buffer.length =
+                   PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+               cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP;
+               cam->frame[i].buffer.m.offset = cam->frame[i].paddress;
+               cam->frame[i].index = i;
+       }
+
+       return 0;
+}
+
+/*!
+ * Free frame buffers status
+ *
+ * @param cam    Structure cam_data *
+ *
+ * @return none
+ */
+static void mxc_free_frames(cam_data *cam)
+{
+       int i;
+
+       pr_debug("In MVC:mxc_free_frames\n");
+
+       for (i = 0; i < FRAME_NUM; i++)
+               cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
+
+       cam->enc_counter = 0;
+       INIT_LIST_HEAD(&cam->ready_q);
+       INIT_LIST_HEAD(&cam->working_q);
+       INIT_LIST_HEAD(&cam->done_q);
+}
+
+/*!
+ * Return the buffer status
+ *
+ * @param cam     Structure cam_data *
+ * @param buf     Structure v4l2_buffer *
+ *
+ * @return status  0 success, EINVAL failed.
+ */
+static int mxc_v4l2_buffer_status(cam_data *cam, struct v4l2_buffer *buf)
+{
+       pr_debug("In MVC:mxc_v4l2_buffer_status\n");
+
+       if (buf->index < 0 || buf->index >= FRAME_NUM) {
+               pr_err("ERROR: v4l2 capture: mxc_v4l2_buffer_status buffers "
+                      "not allocated\n");
+               return -EINVAL;
+       }
+
+       memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf));
+       return 0;
+}
+
+static int mxc_v4l2_release_bufs(cam_data *cam)
+{
+       pr_debug("In MVC:mxc_v4l2_release_bufs\n");
+       return 0;
+}
+
+static int mxc_v4l2_prepare_bufs(cam_data *cam, struct v4l2_buffer *buf)
+{
+       pr_debug("In MVC:mxc_v4l2_prepare_bufs\n");
+
+       if (buf->index < 0 || buf->index >= FRAME_NUM || buf->length <
+                       PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage)) {
+               pr_err("ERROR: v4l2 capture: mxc_v4l2_prepare_bufs buffers "
+                       "not allocated,index=%d, length=%d\n", buf->index,
+                       buf->length);
+               return -EINVAL;
+       }
+
+       cam->frame[buf->index].buffer.index = buf->index;
+       cam->frame[buf->index].buffer.flags = V4L2_BUF_FLAG_MAPPED;
+       cam->frame[buf->index].buffer.length = buf->length;
+       cam->frame[buf->index].buffer.m.offset = cam->frame[buf->index].paddress
+               = buf->m.offset;
+       cam->frame[buf->index].buffer.type = buf->type;
+       cam->frame[buf->index].buffer.memory = V4L2_MEMORY_USERPTR;
+       cam->frame[buf->index].index = buf->index;
+
+       return 0;
+}
+
+/***************************************************************************
+ * Functions for handling the video stream.
+ **************************************************************************/
+
+/*!
+ * Indicates whether the palette is supported.
+ *
+ * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32
+ *
+ * @return 0 if failed
+ */
+static inline int valid_mode(u32 palette)
+{
+       return ((palette == V4L2_PIX_FMT_RGB565) ||
+               (palette == V4L2_PIX_FMT_BGR24) ||
+               (palette == V4L2_PIX_FMT_RGB24) ||
+               (palette == V4L2_PIX_FMT_BGR32) ||
+               (palette == V4L2_PIX_FMT_RGB32) ||
+               (palette == V4L2_PIX_FMT_YUV422P) ||
+               (palette == V4L2_PIX_FMT_UYVY) ||
+               (palette == V4L2_PIX_FMT_YUYV) ||
+               (palette == V4L2_PIX_FMT_YUV420) ||
+               (palette == V4L2_PIX_FMT_YVU420) ||
+               (palette == V4L2_PIX_FMT_NV12));
+}
+
+/*!
+ * Start the encoder job
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int mxc_streamon(cam_data *cam)
+{
+       struct mxc_v4l_frame *frame;
+       unsigned long lock_flags;
+       int err = 0;
+
+       pr_debug("In MVC:mxc_streamon\n");
+
+       if (NULL == cam) {
+               pr_err("ERROR! cam parameter is NULL\n");
+               return -1;
+       }
+
+       if (cam->capture_on) {
+               pr_err("ERROR: v4l2 capture: Capture stream has been turned "
+                      " on\n");
+               return -1;
+       }
+
+       if (list_empty(&cam->ready_q)) {
+               pr_err("ERROR: v4l2 capture: mxc_streamon buffer has not been "
+                       "queued yet\n");
+               return -EINVAL;
+       }
+       if (cam->enc_update_eba &&
+               cam->ready_q.prev == cam->ready_q.next) {
+               pr_err("ERROR: v4l2 capture: mxc_streamon buffer need "
+                      "ping pong at least two buffers\n");
+               return -EINVAL;
+       }
+
+       cam->capture_pid = current->pid;
+
+       if (cam->overlay_on == true)
+               stop_preview(cam);
+
+       if (cam->enc_enable) {
+               err = cam->enc_enable(cam);
+               if (err != 0)
+                       return err;
+       }
+
+       spin_lock_irqsave(&cam->queue_int_lock, lock_flags);
+       cam->ping_pong_csi = 0;
+       cam->local_buf_num = 0;
+       if (cam->enc_update_eba) {
+               frame =
+                   list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
+               list_del(cam->ready_q.next);
+               list_add_tail(&frame->queue, &cam->working_q);
+               frame->ipu_buf_num = cam->ping_pong_csi;
+               err = cam->enc_update_eba(cam->ipu, frame->buffer.m.offset,
+                                         &cam->ping_pong_csi);
+
+               frame =
+                   list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
+               list_del(cam->ready_q.next);
+               list_add_tail(&frame->queue, &cam->working_q);
+               frame->ipu_buf_num = cam->ping_pong_csi;
+               err |= cam->enc_update_eba(cam->ipu, frame->buffer.m.offset,
+                                          &cam->ping_pong_csi);
+               spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
+       } else {
+               spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
+               return -EINVAL;
+       }
+
+       if (cam->overlay_on == true)
+               start_preview(cam);
+
+       if (cam->enc_enable_csi) {
+               err = cam->enc_enable_csi(cam);
+               if (err != 0)
+                       return err;
+       }
+
+       cam->capture_on = true;
+
+       return err;
+}
+
+/*!
+ * Shut down the encoder job
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int mxc_streamoff(cam_data *cam)
+{
+       int err = 0;
+
+       pr_debug("In MVC:mxc_streamoff\n");
+
+       if (cam->capture_on == false)
+               return 0;
+
+       /* For both CSI--MEM and CSI--IC--MEM
+        * 1. wait for idmac eof
+        * 2. disable csi first
+        * 3. disable idmac
+        * 4. disable smfc (CSI--MEM channel)
+        */
+       if (mxc_capture_inputs[cam->current_input].name != NULL) {
+               if (cam->enc_disable_csi) {
+                       err = cam->enc_disable_csi(cam);
+                       if (err != 0)
+                               return err;
+               }
+               if (cam->enc_disable) {
+                       err = cam->enc_disable(cam);
+                       if (err != 0)
+                               return err;
+               }
+       }
+
+       mxc_free_frames(cam);
+       mxc_capture_inputs[cam->current_input].status |= V4L2_IN_ST_NO_POWER;
+       cam->capture_on = false;
+       return err;
+}
+
+/*!
+ * Valid and adjust the overlay window size, position
+ *
+ * @param cam      structure cam_data *
+ * @param win      struct v4l2_window  *
+ *
+ * @return 0
+ */
+static int verify_preview(cam_data *cam, struct v4l2_window *win)
+{
+       int i = 0, width_bound = 0, height_bound = 0;
+       int *width, *height;
+       unsigned int ipu_ch = CHAN_NONE;
+       struct fb_info *bg_fbi = NULL, *fbi = NULL;
+       bool foregound_fb = false;
+       mm_segment_t old_fs;
+
+       pr_debug("In MVC: verify_preview\n");
+
+       do {
+               fbi = (struct fb_info *)registered_fb[i];
+               if (fbi == NULL) {
+                       pr_err("ERROR: verify_preview frame buffer NULL.\n");
+                       return -1;
+               }
+
+               /* Which DI supports 2 layers? */
+               if (((strncmp(fbi->fix.id, "DISP3 BG", 8) == 0) &&
+                                       (cam->output < 3)) ||
+                   ((strncmp(fbi->fix.id, "DISP4 BG", 8) == 0) &&
+                                       (cam->output >= 3))) {
+                       if (fbi->fbops->fb_ioctl) {
+                               old_fs = get_fs();
+                               set_fs(KERNEL_DS);
+                               fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN,
+                                               (unsigned long)&ipu_ch);
+                               set_fs(old_fs);
+                       }
+                       if (ipu_ch == MEM_BG_SYNC) {
+                               bg_fbi = fbi;
+                               pr_debug("Found background frame buffer.\n");
+                       }
+               }
+
+               /* Found the frame buffer to preview on. */
+               if (strcmp(fbi->fix.id,
+                           mxc_capture_outputs[cam->output].name) == 0) {
+                       if (((strcmp(fbi->fix.id, "DISP3 FG") == 0) &&
+                                               (cam->output < 3)) ||
+                           ((strcmp(fbi->fix.id, "DISP4 FG") == 0) &&
+                                               (cam->output >= 3)))
+                               foregound_fb = true;
+
+                       cam->overlay_fb = fbi;
+                       break;
+               }
+       } while (++i < FB_MAX);
+
+       if (foregound_fb) {
+               width_bound = bg_fbi->var.xres;
+               height_bound = bg_fbi->var.yres;
+
+               if (win->w.width + win->w.left > bg_fbi->var.xres ||
+                   win->w.height + win->w.top > bg_fbi->var.yres) {
+                       pr_err("ERROR: FG window position exceeds.\n");
+                       return -1;
+               }
+       } else {
+               /* 4 bytes alignment for BG */
+               width_bound = cam->overlay_fb->var.xres;
+               height_bound = cam->overlay_fb->var.yres;
+
+               if (cam->overlay_fb->var.bits_per_pixel == 24)
+                       win->w.left -= win->w.left % 4;
+               else if (cam->overlay_fb->var.bits_per_pixel == 16)
+                       win->w.left -= win->w.left % 2;
+
+               if (win->w.width + win->w.left > cam->overlay_fb->var.xres)
+                       win->w.width = cam->overlay_fb->var.xres - win->w.left;
+               if (win->w.height + win->w.top > cam->overlay_fb->var.yres)
+                       win->w.height = cam->overlay_fb->var.yres - win->w.top;
+       }
+
+       /* stride line limitation */
+       win->w.height -= win->w.height % 8;
+       win->w.width -= win->w.width % 8;
+
+       if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+               height = &win->w.width;
+               width = &win->w.height;
+       } else {
+               width = &win->w.width;
+               height = &win->w.height;
+       }
+
+       if (*width == 0 || *height == 0) {
+               pr_err("ERROR: v4l2 capture: width or height"
+                       " too small.\n");
+               return -EINVAL;
+       }
+
+       if ((cam->crop_bounds.width / *width > 8) ||
+           ((cam->crop_bounds.width / *width == 8) &&
+            (cam->crop_bounds.width % *width))) {
+               *width = cam->crop_bounds.width / 8;
+               if (*width % 8)
+                       *width += 8 - *width % 8;
+               if (*width + win->w.left > width_bound) {
+                       pr_err("ERROR: v4l2 capture: width exceeds "
+                               "resize limit.\n");
+                       return -1;
+               }
+               pr_err("ERROR: v4l2 capture: width exceeds limit. "
+                       "Resize to %d.\n",
+                       *width);
+       }
+
+       if ((cam->crop_bounds.height / *height > 8) ||
+           ((cam->crop_bounds.height / *height == 8) &&
+            (cam->crop_bounds.height % *height))) {
+               *height = cam->crop_bounds.height / 8;
+               if (*height % 8)
+                       *height += 8 - *height % 8;
+               if (*height + win->w.top > height_bound) {
+                       pr_err("ERROR: v4l2 capture: height exceeds "
+                               "resize limit.\n");
+                       return -1;
+               }
+               pr_err("ERROR: v4l2 capture: height exceeds limit "
+                       "resize to %d.\n",
+                       *height);
+       }
+
+       return 0;
+}
+
+/*!
+ * start the viewfinder job
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int start_preview(cam_data *cam)
+{
+       int err = 0;
+
+       pr_debug("MVC: start_preview\n");
+
+       if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)
+       #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+               err = prp_vf_sdc_select(cam);
+       #else
+               err = foreground_sdc_select(cam);
+       #endif
+       else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)
+       #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+               err = prp_vf_sdc_select_bg(cam);
+       #else
+               err = bg_overlay_sdc_select(cam);
+       #endif
+       if (err != 0)
+               return err;
+
+       if (cam->vf_start_sdc) {
+               err = cam->vf_start_sdc(cam);
+               if (err != 0)
+                       return err;
+       }
+
+       if (cam->vf_enable_csi)
+               err = cam->vf_enable_csi(cam);
+
+       pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+                __func__,
+                cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+       pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+                __func__,
+                cam->crop_bounds.width, cam->crop_bounds.height);
+       pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+                __func__,
+                cam->crop_defrect.width, cam->crop_defrect.height);
+       pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+                __func__,
+                cam->crop_current.width, cam->crop_current.height);
+
+       return err;
+}
+
+/*!
+ * shut down the viewfinder job
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int stop_preview(cam_data *cam)
+{
+       int err = 0;
+
+       if (cam->vf_disable_csi) {
+               err = cam->vf_disable_csi(cam);
+               if (err != 0)
+                       return err;
+       }
+
+       if (cam->vf_stop_sdc) {
+               err = cam->vf_stop_sdc(cam);
+               if (err != 0)
+                       return err;
+       }
+
+       if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)
+       #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+               err = prp_vf_sdc_deselect(cam);
+       #else
+               err = foreground_sdc_deselect(cam);
+       #endif
+       else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)
+       #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+               err = prp_vf_sdc_deselect_bg(cam);
+       #else
+               err = bg_overlay_sdc_deselect(cam);
+       #endif
+
+       return err;
+}
+
+/***************************************************************************
+ * VIDIOC Functions.
+ **************************************************************************/
+
+/*!
+ * V4L2 - mxc_v4l2_g_fmt function
+ *
+ * @param cam         structure cam_data *
+ *
+ * @param f           structure v4l2_format *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f)
+{
+       int retval = 0;
+
+       pr_debug("In MVC: mxc_v4l2_g_fmt type=%d\n", f->type);
+
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               pr_debug("   type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+               f->fmt.pix = cam->v2f.fmt.pix;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               pr_debug("   type is V4L2_BUF_TYPE_VIDEO_OVERLAY\n");
+               f->fmt.win = cam->win;
+               break;
+       default:
+               pr_debug("   type is invalid\n");
+               retval = -EINVAL;
+       }
+
+       pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+                __func__,
+                cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+       pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+                __func__,
+                cam->crop_bounds.width, cam->crop_bounds.height);
+       pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+                __func__,
+                cam->crop_defrect.width, cam->crop_defrect.height);
+       pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+                __func__,
+                cam->crop_current.width, cam->crop_current.height);
+
+       return retval;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_s_fmt function
+ *
+ * @param cam         structure cam_data *
+ *
+ * @param f           structure v4l2_format *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f)
+{
+       int retval = 0;
+       int size = 0;
+       int bytesperline = 0;
+       int *width, *height;
+
+       pr_debug("In MVC: mxc_v4l2_s_fmt\n");
+
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               pr_debug("   type=V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+               if (!valid_mode(f->fmt.pix.pixelformat)) {
+                       pr_err("ERROR: v4l2 capture: mxc_v4l2_s_fmt: format "
+                              "not supported\n");
+                       return -EINVAL;
+               }
+
+               /*
+                * Force the capture window resolution to be crop bounds
+                * for CSI MEM input mode.
+                */
+               if (strcmp(mxc_capture_inputs[cam->current_input].name,
+                          "CSI MEM") == 0) {
+                       f->fmt.pix.width = cam->crop_current.width;
+                       f->fmt.pix.height = cam->crop_current.height;
+               }
+
+               if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+                       height = &f->fmt.pix.width;
+                       width = &f->fmt.pix.height;
+               } else {
+                       width = &f->fmt.pix.width;
+                       height = &f->fmt.pix.height;
+               }
+
+               /* stride line limitation */
+               *width -= *width % 8;
+               *height -= *height % 8;
+
+               if (*width == 0 || *height == 0) {
+                       pr_err("ERROR: v4l2 capture: width or height"
+                               " too small.\n");
+                       return -EINVAL;
+               }
+
+               if ((cam->crop_current.width / *width > 8) ||
+                   ((cam->crop_current.width / *width == 8) &&
+                    (cam->crop_current.width % *width))) {
+                       *width = cam->crop_current.width / 8;
+                       if (*width % 8)
+                               *width += 8 - *width % 8;
+                       pr_err("ERROR: v4l2 capture: width exceeds limit "
+                               "resize to %d.\n",
+                              *width);
+               }
+
+               if ((cam->crop_current.height / *height > 8) ||
+                   ((cam->crop_current.height / *height == 8) &&
+                    (cam->crop_current.height % *height))) {
+                       *height = cam->crop_current.height / 8;
+                       if (*height % 8)
+                               *height += 8 - *height % 8;
+                       pr_err("ERROR: v4l2 capture: height exceeds limit "
+                              "resize to %d.\n",
+                              *height);
+               }
+
+               switch (f->fmt.pix.pixelformat) {
+               case V4L2_PIX_FMT_RGB565:
+                       size = f->fmt.pix.width * f->fmt.pix.height * 2;
+                       bytesperline = f->fmt.pix.width * 2;
+                       break;
+               case V4L2_PIX_FMT_BGR24:
+                       size = f->fmt.pix.width * f->fmt.pix.height * 3;
+                       bytesperline = f->fmt.pix.width * 3;
+                       break;
+               case V4L2_PIX_FMT_RGB24:
+                       size = f->fmt.pix.width * f->fmt.pix.height * 3;
+                       bytesperline = f->fmt.pix.width * 3;
+                       break;
+               case V4L2_PIX_FMT_BGR32:
+                       size = f->fmt.pix.width * f->fmt.pix.height * 4;
+                       bytesperline = f->fmt.pix.width * 4;
+                       break;
+               case V4L2_PIX_FMT_RGB32:
+                       size = f->fmt.pix.width * f->fmt.pix.height * 4;
+                       bytesperline = f->fmt.pix.width * 4;
+                       break;
+               case V4L2_PIX_FMT_YUV422P:
+                       size = f->fmt.pix.width * f->fmt.pix.height * 2;
+                       bytesperline = f->fmt.pix.width;
+                       break;
+               case V4L2_PIX_FMT_UYVY:
+               case V4L2_PIX_FMT_YUYV:
+                       size = f->fmt.pix.width * f->fmt.pix.height * 2;
+                       bytesperline = f->fmt.pix.width * 2;
+                       break;
+               case V4L2_PIX_FMT_YUV420:
+               case V4L2_PIX_FMT_YVU420:
+                       size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2;
+                       bytesperline = f->fmt.pix.width;
+                       break;
+               case V4L2_PIX_FMT_NV12:
+                       size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2;
+                       bytesperline = f->fmt.pix.width;
+                       break;
+               default:
+                       break;
+               }
+
+               if (f->fmt.pix.bytesperline < bytesperline)
+                       f->fmt.pix.bytesperline = bytesperline;
+               else
+                       bytesperline = f->fmt.pix.bytesperline;
+
+               if (f->fmt.pix.sizeimage < size)
+                       f->fmt.pix.sizeimage = size;
+               else
+                       size = f->fmt.pix.sizeimage;
+
+               cam->v2f.fmt.pix = f->fmt.pix;
+
+               if (cam->v2f.fmt.pix.priv != 0) {
+                       if (copy_from_user(&cam->offset,
+                                          (void *)cam->v2f.fmt.pix.priv,
+                                          sizeof(cam->offset))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+               }
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               pr_debug("   type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n");
+               retval = verify_preview(cam, &f->fmt.win);
+               cam->win = f->fmt.win;
+               break;
+       default:
+               retval = -EINVAL;
+       }
+
+       pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+                __func__,
+                cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+       pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+                __func__,
+                cam->crop_bounds.width, cam->crop_bounds.height);
+       pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+                __func__,
+                cam->crop_defrect.width, cam->crop_defrect.height);
+       pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+                __func__,
+                cam->crop_current.width, cam->crop_current.height);
+
+       return retval;
+}
+
+/*!
+ * get control param
+ *
+ * @param cam         structure cam_data *
+ *
+ * @param c           structure v4l2_control *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c)
+{
+       int status = 0;
+
+       pr_debug("In MVC:mxc_v4l2_g_ctrl\n");
+
+       /* probably don't need to store the values that can be retrieved,
+        * locally, but they are for now. */
+       switch (c->id) {
+       case V4L2_CID_HFLIP:
+               /* This is handled in the ipu. */
+               if (cam->rotation == IPU_ROTATE_HORIZ_FLIP)
+                       c->value = 1;
+               break;
+       case V4L2_CID_VFLIP:
+               /* This is handled in the ipu. */
+               if (cam->rotation == IPU_ROTATE_VERT_FLIP)
+                       c->value = 1;
+               break;
+       case V4L2_CID_MXC_ROT:
+               /* This is handled in the ipu. */
+               c->value = cam->rotation;
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               if (cam->sensor) {
+                       c->value = cam->bright;
+                       status = vidioc_int_g_ctrl(cam->sensor, c);
+                       cam->bright = c->value;
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       status = -ENODEV;
+               }
+               break;
+       case V4L2_CID_HUE:
+               if (cam->sensor) {
+                       c->value = cam->hue;
+                       status = vidioc_int_g_ctrl(cam->sensor, c);
+                       cam->hue = c->value;
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       status = -ENODEV;
+               }
+               break;
+       case V4L2_CID_CONTRAST:
+               if (cam->sensor) {
+                       c->value = cam->contrast;
+                       status = vidioc_int_g_ctrl(cam->sensor, c);
+                       cam->contrast = c->value;
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       status = -ENODEV;
+               }
+               break;
+       case V4L2_CID_SATURATION:
+               if (cam->sensor) {
+                       c->value = cam->saturation;
+                       status = vidioc_int_g_ctrl(cam->sensor, c);
+                       cam->saturation = c->value;
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       status = -ENODEV;
+               }
+               break;
+       case V4L2_CID_RED_BALANCE:
+               if (cam->sensor) {
+                       c->value = cam->red;
+                       status = vidioc_int_g_ctrl(cam->sensor, c);
+                       cam->red = c->value;
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       status = -ENODEV;
+               }
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               if (cam->sensor) {
+                       c->value = cam->blue;
+                       status = vidioc_int_g_ctrl(cam->sensor, c);
+                       cam->blue = c->value;
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       status = -ENODEV;
+               }
+               break;
+       case V4L2_CID_BLACK_LEVEL:
+               if (cam->sensor) {
+                       c->value = cam->ae_mode;
+                       status = vidioc_int_g_ctrl(cam->sensor, c);
+                       cam->ae_mode = c->value;
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       status = -ENODEV;
+               }
+               break;
+       default:
+               pr_err("ERROR: v4l2 capture: unsupported ioctrl!\n");
+       }
+
+       return status;
+}
+
+/*!
+ * V4L2 - set_control function
+ *          V4L2_CID_PRIVATE_BASE is the extention for IPU preprocessing.
+ *          0 for normal operation
+ *          1 for vertical flip
+ *          2 for horizontal flip
+ *          3 for horizontal and vertical flip
+ *          4 for 90 degree rotation
+ * @param cam         structure cam_data *
+ *
+ * @param c           structure v4l2_control *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c)
+{
+       int i, ret = 0;
+       int tmp_rotation = IPU_ROTATE_NONE;
+       struct sensor_data *sensor_data;
+
+       pr_debug("In MVC:mxc_v4l2_s_ctrl\n");
+
+       switch (c->id) {
+       case V4L2_CID_HFLIP:
+               /* This is done by the IPU */
+               if (c->value == 1) {
+                       if ((cam->rotation != IPU_ROTATE_VERT_FLIP) &&
+                           (cam->rotation != IPU_ROTATE_180))
+                               cam->rotation = IPU_ROTATE_HORIZ_FLIP;
+                       else
+                               cam->rotation = IPU_ROTATE_180;
+               } else {
+                       if (cam->rotation == IPU_ROTATE_HORIZ_FLIP)
+                               cam->rotation = IPU_ROTATE_NONE;
+                       if (cam->rotation == IPU_ROTATE_180)
+                               cam->rotation = IPU_ROTATE_VERT_FLIP;
+               }
+               break;
+       case V4L2_CID_VFLIP:
+               /* This is done by the IPU */
+               if (c->value == 1) {
+                       if ((cam->rotation != IPU_ROTATE_HORIZ_FLIP) &&
+                           (cam->rotation != IPU_ROTATE_180))
+                               cam->rotation = IPU_ROTATE_VERT_FLIP;
+                       else
+                               cam->rotation = IPU_ROTATE_180;
+               } else {
+                       if (cam->rotation == IPU_ROTATE_VERT_FLIP)
+                               cam->rotation = IPU_ROTATE_NONE;
+                       if (cam->rotation == IPU_ROTATE_180)
+                               cam->rotation = IPU_ROTATE_HORIZ_FLIP;
+               }
+               break;
+       case V4L2_CID_MXC_ROT:
+       case V4L2_CID_MXC_VF_ROT:
+               /* This is done by the IPU */
+               switch (c->value) {
+               case V4L2_MXC_ROTATE_NONE:
+                       tmp_rotation = IPU_ROTATE_NONE;
+                       break;
+               case V4L2_MXC_ROTATE_VERT_FLIP:
+                       tmp_rotation = IPU_ROTATE_VERT_FLIP;
+                       break;
+               case V4L2_MXC_ROTATE_HORIZ_FLIP:
+                       tmp_rotation = IPU_ROTATE_HORIZ_FLIP;
+                       break;
+               case V4L2_MXC_ROTATE_180:
+                       tmp_rotation = IPU_ROTATE_180;
+                       break;
+               case V4L2_MXC_ROTATE_90_RIGHT:
+                       tmp_rotation = IPU_ROTATE_90_RIGHT;
+                       break;
+               case V4L2_MXC_ROTATE_90_RIGHT_VFLIP:
+                       tmp_rotation = IPU_ROTATE_90_RIGHT_VFLIP;
+                       break;
+               case V4L2_MXC_ROTATE_90_RIGHT_HFLIP:
+                       tmp_rotation = IPU_ROTATE_90_RIGHT_HFLIP;
+                       break;
+               case V4L2_MXC_ROTATE_90_LEFT:
+                       tmp_rotation = IPU_ROTATE_90_LEFT;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+               if (c->id == V4L2_CID_MXC_VF_ROT)
+                       cam->vf_rotation = tmp_rotation;
+               else
+                       cam->rotation = tmp_rotation;
+               #else
+                       cam->rotation = tmp_rotation;
+               #endif
+
+               break;
+       case V4L2_CID_HUE:
+               if (cam->sensor) {
+                       cam->hue = c->value;
+                       ret = vidioc_int_s_ctrl(cam->sensor, c);
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       ret = -ENODEV;
+               }
+               break;
+       case V4L2_CID_CONTRAST:
+               if (cam->sensor) {
+                       cam->contrast = c->value;
+                       ret = vidioc_int_s_ctrl(cam->sensor, c);
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       ret = -ENODEV;
+               }
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               if (cam->sensor) {
+                       cam->bright = c->value;
+                       ret = vidioc_int_s_ctrl(cam->sensor, c);
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       ret = -ENODEV;
+               }
+               break;
+       case V4L2_CID_SATURATION:
+               if (cam->sensor) {
+                       cam->saturation = c->value;
+                       ret = vidioc_int_s_ctrl(cam->sensor, c);
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       ret = -ENODEV;
+               }
+               break;
+       case V4L2_CID_RED_BALANCE:
+               if (cam->sensor) {
+                       cam->red = c->value;
+                       ret = vidioc_int_s_ctrl(cam->sensor, c);
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       ret = -ENODEV;
+               }
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               if (cam->sensor) {
+                       cam->blue = c->value;
+                       ret = vidioc_int_s_ctrl(cam->sensor, c);
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       ret = -ENODEV;
+               }
+               break;
+       case V4L2_CID_EXPOSURE:
+               if (cam->sensor) {
+                       cam->ae_mode = c->value;
+                       ret = vidioc_int_s_ctrl(cam->sensor, c);
+               } else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       ret = -ENODEV;
+               }
+               break;
+       case V4L2_CID_MXC_FLASH:
+#ifdef CONFIG_MXC_IPU_V1
+               ipu_csi_flash_strobe(true);
+#endif
+               break;
+       case V4L2_CID_MXC_SWITCH_CAM:
+               if (cam->sensor == cam->all_sensors[c->value])
+                       break;
+
+               /* power down other cameraes before enable new one */
+               for (i = 0; i < cam->sensor_index; i++) {
+                       if (i != c->value) {
+                               vidioc_int_dev_exit(cam->all_sensors[i]);
+                               vidioc_int_s_power(cam->all_sensors[i], 0);
+                               if (cam->mclk_on[cam->mclk_source]) {
+                                       ipu_csi_enable_mclk_if(cam->ipu,
+                                                       CSI_MCLK_I2C,
+                                                       cam->mclk_source,
+                                                       false, false);
+                                       cam->mclk_on[cam->mclk_source] =
+                                                               false;
+                               }
+                       }
+               }
+               sensor_data = cam->all_sensors[c->value]->priv;
+               if (sensor_data->io_init)
+                       sensor_data->io_init();
+               cam->sensor = cam->all_sensors[c->value];
+               cam->mclk_source = sensor_data->mclk_source;
+               ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C,
+                                      cam->mclk_source, true, true);
+               cam->mclk_on[cam->mclk_source] = true;
+               vidioc_int_s_power(cam->sensor, 1);
+               vidioc_int_dev_init(cam->sensor);
+               break;
+       default:
+               pr_debug("   default case\n");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_s_param function
+ * Allows setting of capturemode and frame rate.
+ *
+ * @param cam         structure cam_data *
+ * @param parm        structure v4l2_streamparm *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm)
+{
+       struct v4l2_ifparm ifparm;
+       struct v4l2_format cam_fmt;
+       struct v4l2_streamparm currentparm;
+       ipu_csi_signal_cfg_t csi_param;
+       u32 current_fps, parm_fps;
+       int err = 0;
+
+       pr_debug("In mxc_v4l2_s_param\n");
+
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n");
+               return -EINVAL;
+       }
+
+       /* Stop the viewfinder */
+       if (cam->overlay_on == true)
+               stop_preview(cam);
+
+       currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       /* First check that this device can support the changes requested. */
+       err = vidioc_int_g_parm(cam->sensor, &currentparm);
+       if (err) {
+               pr_err("%s: vidioc_int_g_parm returned an error %d\n",
+                       __func__, err);
+               goto exit;
+       }
+
+       current_fps = currentparm.parm.capture.timeperframe.denominator
+                       / currentparm.parm.capture.timeperframe.numerator;
+       parm_fps = parm->parm.capture.timeperframe.denominator
+                       / parm->parm.capture.timeperframe.numerator;
+
+       pr_debug("   Current capabilities are %x\n",
+                       currentparm.parm.capture.capability);
+       pr_debug("   Current capturemode is %d  change to %d\n",
+                       currentparm.parm.capture.capturemode,
+                       parm->parm.capture.capturemode);
+       pr_debug("   Current framerate is %d  change to %d\n",
+                       current_fps, parm_fps);
+
+       /* This will change any camera settings needed. */
+       err = vidioc_int_s_parm(cam->sensor, parm);
+       if (err) {
+               pr_err("%s: vidioc_int_s_parm returned an error %d\n",
+                       __func__, err);
+               goto exit;
+       }
+
+       /* If resolution changed, need to re-program the CSI */
+       /* Get new values. */
+       vidioc_int_g_ifparm(cam->sensor, &ifparm);
+
+       csi_param.data_width = 0;
+       csi_param.clk_mode = 0;
+       csi_param.ext_vsync = 0;
+       csi_param.Vsync_pol = 0;
+       csi_param.Hsync_pol = 0;
+       csi_param.pixclk_pol = 0;
+       csi_param.data_pol = 0;
+       csi_param.sens_clksrc = 0;
+       csi_param.pack_tight = 0;
+       csi_param.force_eof = 0;
+       csi_param.data_en_pol = 0;
+       csi_param.data_fmt = 0;
+       csi_param.csi = cam->csi;
+       csi_param.mclk = 0;
+
+       /*This may not work on other platforms. Check when adding a new one.*/
+       /*The mclk clock was never set correclty in the ipu register*/
+       /*for now we are going to use this mclk as pixel clock*/
+       /*to set csi0_data_dest register.*/
+       /*This is a workaround which should be fixed*/
+       pr_debug("   clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr);
+       if (ifparm.u.bt656.clock_curr == 0) {
+               csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
+               /*protocol bt656 use 27Mhz pixel clock */
+               csi_param.mclk = 27000000;
+       } else {
+               csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
+       }
+
+       csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv;
+
+       if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) {
+               csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+       } else if (ifparm.u.bt656.mode
+                               == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) {
+               csi_param.data_width = IPU_CSI_DATA_WIDTH_10;
+       } else {
+               csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+       }
+
+       csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv;
+       csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv;
+       csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct;
+
+       /* if the capturemode changed, the size bounds will have changed. */
+       cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);
+       pr_debug("   g_fmt_cap returns widthxheight of input as %d x %d\n",
+                       cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height);
+
+       csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat;
+
+       cam->crop_bounds.top = cam->crop_bounds.left = 0;
+       cam->crop_bounds.width = cam_fmt.fmt.pix.width;
+       cam->crop_bounds.height = cam_fmt.fmt.pix.height;
+
+       /*
+        * Set the default current cropped resolution to be the same with
+        * the cropping boundary(except for tvin module).
+        */
+       if (cam->device_type != 1) {
+               cam->crop_current.width = cam->crop_bounds.width;
+               cam->crop_current.height = cam->crop_bounds.height;
+       }
+
+       /* This essentially loses the data at the left and bottom of the image
+        * giving a digital zoom image, if crop_current is less than the full
+        * size of the image. */
+       ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+                               cam->crop_current.height, cam->csi);
+       ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+                              cam->crop_current.top,
+                              cam->csi);
+       ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width,
+                              cam->crop_bounds.height,
+                              cam_fmt.fmt.pix.pixelformat, csi_param);
+
+
+exit:
+       if (cam->overlay_on == true)
+               start_preview(cam);
+
+       return err;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_s_std function
+ *
+ * Sets the TV standard to be used.
+ *
+ * @param cam        structure cam_data *
+ * @param parm       structure v4l2_streamparm *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_std(cam_data *cam, v4l2_std_id e)
+{
+       printk(KERN_ERR "In mxc_v4l2_s_std %Lx\n", e);
+       if (e == V4L2_STD_PAL) {
+               pr_debug("   Setting standard to PAL %Lx\n", V4L2_STD_PAL);
+               cam->standard.id = V4L2_STD_PAL;
+               video_index = TV_PAL;
+       } else if (e == V4L2_STD_NTSC) {
+               pr_debug("   Setting standard to NTSC %Lx\n",
+                               V4L2_STD_NTSC);
+               /* Get rid of the white dot line in NTSC signal input */
+               cam->standard.id = V4L2_STD_NTSC;
+               video_index = TV_NTSC;
+       } else {
+               cam->standard.id = V4L2_STD_ALL;
+               video_index = TV_NOT_LOCKED;
+               pr_err("ERROR: unrecognized std! %Lx (PAL=%Lx, NTSC=%Lx\n",
+                       e, V4L2_STD_PAL, V4L2_STD_NTSC);
+       }
+
+       cam->standard.index = video_index;
+       strcpy(cam->standard.name, video_fmts[video_index].name);
+       cam->crop_bounds.width = video_fmts[video_index].raw_width;
+       cam->crop_bounds.height = video_fmts[video_index].raw_height;
+       cam->crop_current.width = video_fmts[video_index].active_width;
+       cam->crop_current.height = video_fmts[video_index].active_height;
+       cam->crop_current.top = video_fmts[video_index].active_top;
+       cam->crop_current.left = video_fmts[video_index].active_left;
+
+       return 0;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_g_std function
+ *
+ * Gets the TV standard from the TV input device.
+ *
+ * @param cam        structure cam_data *
+ *
+ * @param e          structure v4l2_streamparm *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_g_std(cam_data *cam, v4l2_std_id *e)
+{
+       struct v4l2_format tv_fmt;
+
+       pr_debug("In mxc_v4l2_g_std\n");
+
+       if (cam->device_type == 1) {
+               /* Use this function to get what the TV-In device detects the
+                * format to be. pixelformat is used to return the std value
+                * since the interface has no vidioc_g_std.*/
+               tv_fmt.type = V4L2_BUF_TYPE_PRIVATE;
+               vidioc_int_g_fmt_cap(cam->sensor, &tv_fmt);
+
+               /* If the TV-in automatically detects the standard, then if it
+                * changes, the settings need to change. */
+               if (cam->standard_autodetect) {
+                       if (cam->standard.id != tv_fmt.fmt.pix.pixelformat) {
+                               pr_debug("MVC: mxc_v4l2_g_std: "
+                                       "Changing standard\n");
+                               mxc_v4l2_s_std(cam, tv_fmt.fmt.pix.pixelformat);
+                       }
+               }
+
+               *e = tv_fmt.fmt.pix.pixelformat;
+       }
+
+       return 0;
+}
+
+/*!
+ * Dequeue one V4L capture buffer
+ *
+ * @param cam         structure cam_data *
+ * @param buf         structure v4l2_buffer *
+ *
+ * @return  status    0 success, EINVAL invalid frame number,
+ *                    ETIME timeout, ERESTARTSYS interrupted by user
+ */
+static int mxc_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf)
+{
+       int retval = 0;
+       struct mxc_v4l_frame *frame;
+       unsigned long lock_flags;
+
+       pr_debug("In MVC:mxc_v4l_dqueue\n");
+
+       if (!wait_event_interruptible_timeout(cam->enc_queue,
+                                             cam->enc_counter != 0, 10 * HZ)) {
+               pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue timeout "
+                       "enc_counter %x\n",
+                      cam->enc_counter);
+               return -ETIME;
+       } else if (signal_pending(current)) {
+               pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue() "
+                       "interrupt received\n");
+               return -ERESTARTSYS;
+       }
+
+       if (down_interruptible(&cam->busy_lock))
+               return -EBUSY;
+
+       spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags);
+       cam->enc_counter--;
+
+       frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue);
+       list_del(cam->done_q.next);
+       if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) {
+               frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE;
+       } else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
+               pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: "
+                       "Buffer not filled.\n");
+               frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
+               retval = -EINVAL;
+       } else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) {
+               pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: "
+                       "Buffer not queued.\n");
+               retval = -EINVAL;
+       }
+
+       cam->frame[frame->index].buffer.field = cam->device_type ?
+                               V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
+
+       buf->bytesused = cam->v2f.fmt.pix.sizeimage;
+       buf->index = frame->index;
+       buf->flags = frame->buffer.flags;
+       buf->m = cam->frame[frame->index].buffer.m;
+       buf->timestamp = cam->frame[frame->index].buffer.timestamp;
+       buf->field = cam->frame[frame->index].buffer.field;
+       spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags);
+
+       up(&cam->busy_lock);
+       return retval;
+}
+
+/*!
+ * V4L interface - open function
+ *
+ * @param file         structure file *
+ *
+ * @return  status    0 success, ENODEV invalid device instance,
+ *                    ENODEV timeout, ERESTARTSYS interrupted by user
+ */
+static int mxc_v4l_open(struct file *file)
+{
+       struct v4l2_ifparm ifparm;
+       struct v4l2_format cam_fmt;
+       ipu_csi_signal_cfg_t csi_param;
+       struct video_device *dev = video_devdata(file);
+       cam_data *cam = video_get_drvdata(dev);
+       int err = 0;
+       struct sensor_data *sensor;
+
+       pr_debug("\nIn MVC: mxc_v4l_open\n");
+       pr_debug("   device name is %s\n", dev->name);
+
+       if (!cam) {
+               pr_err("ERROR: v4l2 capture: Internal error, "
+                       "cam_data not found!\n");
+               return -EBADF;
+       }
+
+       if (cam->sensor == NULL ||
+           cam->sensor->type != v4l2_int_type_slave) {
+               pr_err("ERROR: v4l2 capture: slave not found!\n");
+               return -EAGAIN;
+       }
+
+       sensor = cam->sensor->priv;
+       if (!sensor) {
+               pr_err("%s: Internal error, sensor_data is not found!\n", __func__);
+               return -EBADF;
+       }
+
+       down(&cam->busy_lock);
+       err = 0;
+       if (signal_pending(current))
+               goto oops;
+
+       if (cam->open_count++ == 0) {
+               wait_event_interruptible(cam->power_queue,
+                                        cam->low_power == false);
+
+               if (strcmp(mxc_capture_inputs[cam->current_input].name,
+                          "CSI MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+                       err = csi_enc_select(cam);
+#endif
+               } else if (strcmp(mxc_capture_inputs[cam->current_input].name,
+                                 "CSI IC MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
+                       err = prp_enc_select(cam);
+#endif
+               }
+
+               cam->enc_counter = 0;
+               INIT_LIST_HEAD(&cam->ready_q);
+               INIT_LIST_HEAD(&cam->working_q);
+               INIT_LIST_HEAD(&cam->done_q);
+
+               vidioc_int_g_ifparm(cam->sensor, &ifparm);
+
+               csi_param.sens_clksrc = 0;
+
+               csi_param.clk_mode = 0;
+               csi_param.data_pol = 0;
+               csi_param.ext_vsync = 0;
+
+               csi_param.pack_tight = 0;
+               csi_param.force_eof = 0;
+               csi_param.data_en_pol = 0;
+
+               csi_param.mclk = ifparm.u.bt656.clock_curr;
+
+               csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv;
+
+               if (ifparm.u.bt656.mode
+                               == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT)
+                       csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+               else if (ifparm.u.bt656.mode
+                               == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT)
+                       csi_param.data_width = IPU_CSI_DATA_WIDTH_10;
+               else
+                       csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+
+
+               csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv;
+               csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv;
+
+               csi_param.csi = cam->csi;
+
+               cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);
+
+               /* Reset the sizes.  Needed to prevent carryover of last
+                * operation.*/
+               cam->crop_bounds.top = cam->crop_bounds.left = 0;
+               cam->crop_bounds.width = cam_fmt.fmt.pix.width;
+               cam->crop_bounds.height = cam_fmt.fmt.pix.height;
+
+               /* This also is the max crop size for this device. */
+               cam->crop_defrect.top = cam->crop_defrect.left = 0;
+               cam->crop_defrect.width = cam_fmt.fmt.pix.width;
+               cam->crop_defrect.height = cam_fmt.fmt.pix.height;
+
+               /* At this point, this is also the current image size. */
+               cam->crop_current.top = cam->crop_current.left = 0;
+               cam->crop_current.width = cam_fmt.fmt.pix.width;
+               cam->crop_current.height = cam_fmt.fmt.pix.height;
+
+               pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+                       __func__,
+                       cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+               pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+                       __func__,
+                       cam->crop_bounds.width, cam->crop_bounds.height);
+               pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+                       __func__,
+                       cam->crop_defrect.width, cam->crop_defrect.height);
+               pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+                       __func__,
+                       cam->crop_current.width, cam->crop_current.height);
+
+               csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat;
+               pr_debug("On Open: Input to ipu size is %d x %d\n",
+                               cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height);
+               ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+                                       cam->crop_current.height,
+                                       cam->csi);
+               ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+                                       cam->crop_current.top,
+                                       cam->csi);
+               ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width,
+                                       cam->crop_bounds.height,
+                                       cam_fmt.fmt.pix.pixelformat,
+                                       csi_param);
+               clk_prepare_enable(sensor->sensor_clk);
+               vidioc_int_s_power(cam->sensor, 1);
+               vidioc_int_init(cam->sensor);
+               vidioc_int_dev_init(cam->sensor);
+       }
+
+       file->private_data = dev;
+
+oops:
+       up(&cam->busy_lock);
+       return err;
+}
+
+/*!
+ * V4L interface - close function
+ *
+ * @param file     struct file *
+ *
+ * @return         0 success
+ */
+static int mxc_v4l_close(struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       int err = 0;
+       cam_data *cam = video_get_drvdata(dev);
+       struct sensor_data *sensor;
+       pr_debug("In MVC:mxc_v4l_close\n");
+
+       if (!cam) {
+               pr_err("ERROR: v4l2 capture: Internal error, "
+                       "cam_data not found!\n");
+               return -EBADF;
+       }
+
+       if (!cam->sensor) {
+               pr_err("%s: Internal error, camera is not found!\n", __func__);
+               return -EBADF;
+       }
+
+       sensor = cam->sensor->priv;
+       if (!sensor) {
+               pr_err("%s: Internal error, sensor_data is not found!\n", __func__);
+               return -EBADF;
+       }
+
+       down(&cam->busy_lock);
+
+       /* for the case somebody hit the ctrl C */
+       if (cam->overlay_pid == current->pid && cam->overlay_on) {
+               err = stop_preview(cam);
+               cam->overlay_on = false;
+       }
+       if (cam->capture_pid == current->pid) {
+               err |= mxc_streamoff(cam);
+               wake_up_interruptible(&cam->enc_queue);
+       }
+
+       if (--cam->open_count == 0) {
+               vidioc_int_s_power(cam->sensor, 0);
+               clk_disable_unprepare(sensor->sensor_clk);
+               wait_event_interruptible(cam->power_queue,
+                                        cam->low_power == false);
+               pr_debug("mxc_v4l_close: release resource\n");
+
+               if (strcmp(mxc_capture_inputs[cam->current_input].name,
+                          "CSI MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+                       err |= csi_enc_deselect(cam);
+#endif
+               } else if (strcmp(mxc_capture_inputs[cam->current_input].name,
+                                 "CSI IC MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
+                       err |= prp_enc_deselect(cam);
+#endif
+               }
+
+               mxc_free_frame_buf(cam);
+               file->private_data = NULL;
+
+               /* capture off */
+               wake_up_interruptible(&cam->enc_queue);
+               mxc_free_frames(cam);
+               cam->enc_counter++;
+       }
+
+       up(&cam->busy_lock);
+
+       return err;
+}
+
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC) || \
+    defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) || \
+    defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+/*
+ * V4L interface - read function
+ *
+ * @param file       struct file *
+ * @param read buf   char *
+ * @param count      size_t
+ * @param ppos       structure loff_t *
+ *
+ * @return           bytes read
+ */
+static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count,
+                           loff_t *ppos)
+{
+       int err = 0;
+       u8 *v_address[2];
+       struct video_device *dev = video_devdata(file);
+       cam_data *cam = video_get_drvdata(dev);
+
+       if (down_interruptible(&cam->busy_lock))
+               return -EINTR;
+
+       /* Stop the viewfinder */
+       if (cam->overlay_on == true)
+               stop_preview(cam);
+
+       v_address[0] = dma_alloc_coherent(0,
+                                      PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+                                      &cam->still_buf[0],
+                                      GFP_DMA | GFP_KERNEL);
+
+       v_address[1] = dma_alloc_coherent(0,
+                                      PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+                                      &cam->still_buf[1],
+                                      GFP_DMA | GFP_KERNEL);
+
+       if (!v_address[0] || !v_address[1]) {
+               err = -ENOBUFS;
+               goto exit0;
+       }
+
+       err = prp_still_select(cam);
+       if (err != 0) {
+               err = -EIO;
+               goto exit0;
+       }
+
+       cam->still_counter = 0;
+       err = cam->csi_start(cam);
+       if (err != 0) {
+               err = -EIO;
+               goto exit1;
+       }
+
+       if (!wait_event_interruptible_timeout(cam->still_queue,
+                                             cam->still_counter != 0,
+                                             10 * HZ)) {
+               pr_err("ERROR: v4l2 capture: mxc_v4l_read timeout counter %x\n",
+                      cam->still_counter);
+               err = -ETIME;
+               goto exit1;
+       }
+       err = copy_to_user(buf, v_address[1], cam->v2f.fmt.pix.sizeimage);
+
+exit1:
+       prp_still_deselect(cam);
+
+exit0:
+       if (v_address[0] != 0)
+               dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[0],
+                                 cam->still_buf[0]);
+       if (v_address[1] != 0)
+               dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[1],
+                                 cam->still_buf[1]);
+
+       cam->still_buf[0] = cam->still_buf[1] = 0;
+
+       if (cam->overlay_on == true)
+               start_preview(cam);
+
+       up(&cam->busy_lock);
+       if (err < 0)
+               return err;
+
+       return cam->v2f.fmt.pix.sizeimage - err;
+}
+#endif
+
+/*!
+ * V4L interface - ioctl function
+ *
+ * @param file       struct file*
+ *
+ * @param ioctlnr    unsigned int
+ *
+ * @param arg        void*
+ *
+ * @return           0 success, ENODEV for invalid device instance,
+ *                   -1 for other errors.
+ */
+static long mxc_v4l_do_ioctl(struct file *file,
+                           unsigned int ioctlnr, void *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       cam_data *cam = video_get_drvdata(dev);
+       int retval = 0;
+       unsigned long lock_flags;
+
+       pr_debug("In MVC: mxc_v4l_do_ioctl %x\n", ioctlnr);
+       wait_event_interruptible(cam->power_queue, cam->low_power == false);
+       /* make this _really_ smp-safe */
+       if (ioctlnr != VIDIOC_DQBUF)
+               if (down_interruptible(&cam->busy_lock))
+                       return -EBUSY;
+
+       switch (ioctlnr) {
+       /*!
+        * V4l2 VIDIOC_QUERYCAP ioctl
+        */
+       case VIDIOC_QUERYCAP: {
+               struct v4l2_capability *cap = arg;
+               pr_debug("   case VIDIOC_QUERYCAP\n");
+               strcpy(cap->driver, "mxc_v4l2");
+               cap->version = KERNEL_VERSION(0, 1, 11);
+               cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+                                   V4L2_CAP_VIDEO_OVERLAY |
+                                   V4L2_CAP_STREAMING |
+                                   V4L2_CAP_READWRITE;
+               cap->card[0] = '\0';
+               cap->bus_info[0] = '\0';
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_G_FMT ioctl
+        */
+       case VIDIOC_G_FMT: {
+               struct v4l2_format *gf = arg;
+               pr_debug("   case VIDIOC_G_FMT\n");
+               retval = mxc_v4l2_g_fmt(cam, gf);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_S_FMT ioctl
+        */
+       case VIDIOC_S_FMT: {
+               struct v4l2_format *sf = arg;
+               pr_debug("   case VIDIOC_S_FMT\n");
+               retval = mxc_v4l2_s_fmt(cam, sf);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_REQBUFS ioctl
+        */
+       case VIDIOC_REQBUFS: {
+               struct v4l2_requestbuffers *req = arg;
+               pr_debug("   case VIDIOC_REQBUFS\n");
+
+               if (req->count > FRAME_NUM) {
+                       pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: "
+                              "not enough buffers\n");
+                       req->count = FRAME_NUM;
+               }
+
+               if ((req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
+                       pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: "
+                              "wrong buffer type\n");
+                       retval = -EINVAL;
+                       break;
+               }
+
+               mxc_streamoff(cam);
+               if (req->memory & V4L2_MEMORY_MMAP) {
+                       mxc_free_frame_buf(cam);
+                       retval = mxc_allocate_frame_buf(cam, req->count);
+               }
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_QUERYBUF ioctl
+        */
+       case VIDIOC_QUERYBUF: {
+               struct v4l2_buffer *buf = arg;
+               int index = buf->index;
+               pr_debug("   case VIDIOC_QUERYBUF\n");
+
+               if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       pr_err("ERROR: v4l2 capture: "
+                              "VIDIOC_QUERYBUFS: "
+                              "wrong buffer type\n");
+                       retval = -EINVAL;
+                       break;
+               }
+
+               if (buf->memory & V4L2_MEMORY_MMAP) {
+                       memset(buf, 0, sizeof(buf));
+                       buf->index = index;
+               }
+
+               down(&cam->param_lock);
+               if (buf->memory & V4L2_MEMORY_USERPTR) {
+                       mxc_v4l2_release_bufs(cam);
+                       retval = mxc_v4l2_prepare_bufs(cam, buf);
+               }
+
+               if (buf->memory & V4L2_MEMORY_MMAP)
+                       retval = mxc_v4l2_buffer_status(cam, buf);
+               up(&cam->param_lock);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_QBUF ioctl
+        */
+       case VIDIOC_QBUF: {
+               struct v4l2_buffer *buf = arg;
+               int index = buf->index;
+               pr_debug("   case VIDIOC_QBUF\n");
+
+               spin_lock_irqsave(&cam->queue_int_lock, lock_flags);
+               if ((cam->frame[index].buffer.flags & 0x7) ==
+                   V4L2_BUF_FLAG_MAPPED) {
+                       cam->frame[index].buffer.flags |=
+                           V4L2_BUF_FLAG_QUEUED;
+                       list_add_tail(&cam->frame[index].queue,
+                                     &cam->ready_q);
+               } else if (cam->frame[index].buffer.
+                          flags & V4L2_BUF_FLAG_QUEUED) {
+                       pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: "
+                              "buffer already queued\n");
+                       retval = -EINVAL;
+               } else if (cam->frame[index].buffer.
+                          flags & V4L2_BUF_FLAG_DONE) {
+                       pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: "
+                              "overwrite done buffer.\n");
+                       cam->frame[index].buffer.flags &=
+                           ~V4L2_BUF_FLAG_DONE;
+                       cam->frame[index].buffer.flags |=
+                           V4L2_BUF_FLAG_QUEUED;
+                       retval = -EINVAL;
+               }
+
+               buf->flags = cam->frame[index].buffer.flags;
+               spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_DQBUF ioctl
+        */
+       case VIDIOC_DQBUF: {
+               struct v4l2_buffer *buf = arg;
+               pr_debug("   case VIDIOC_DQBUF\n");
+
+               if ((cam->enc_counter == 0) &&
+                       (file->f_flags & O_NONBLOCK)) {
+                       retval = -EAGAIN;
+                       break;
+               }
+
+               retval = mxc_v4l_dqueue(cam, buf);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_STREAMON ioctl
+        */
+       case VIDIOC_STREAMON: {
+               pr_debug("   case VIDIOC_STREAMON\n");
+               retval = mxc_streamon(cam);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_STREAMOFF ioctl
+        */
+       case VIDIOC_STREAMOFF: {
+               pr_debug("   case VIDIOC_STREAMOFF\n");
+               retval = mxc_streamoff(cam);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_G_CTRL ioctl
+        */
+       case VIDIOC_G_CTRL: {
+               pr_debug("   case VIDIOC_G_CTRL\n");
+               retval = mxc_v4l2_g_ctrl(cam, arg);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_S_CTRL ioctl
+        */
+       case VIDIOC_S_CTRL: {
+               pr_debug("   case VIDIOC_S_CTRL\n");
+               retval = mxc_v4l2_s_ctrl(cam, arg);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_CROPCAP ioctl
+        */
+       case VIDIOC_CROPCAP: {
+               struct v4l2_cropcap *cap = arg;
+               pr_debug("   case VIDIOC_CROPCAP\n");
+               if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                   cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
+                       retval = -EINVAL;
+                       break;
+               }
+               cap->bounds = cam->crop_bounds;
+               cap->defrect = cam->crop_defrect;
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_G_CROP ioctl
+        */
+       case VIDIOC_G_CROP: {
+               struct v4l2_crop *crop = arg;
+               pr_debug("   case VIDIOC_G_CROP\n");
+
+               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
+                       retval = -EINVAL;
+                       break;
+               }
+               crop->c = cam->crop_current;
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_S_CROP ioctl
+        */
+       case VIDIOC_S_CROP: {
+               struct v4l2_crop *crop = arg;
+               struct v4l2_rect *b = &cam->crop_bounds;
+               pr_debug("   case VIDIOC_S_CROP\n");
+
+               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
+                       retval = -EINVAL;
+                       break;
+               }
+
+               crop->c.top = (crop->c.top < b->top) ? b->top
+                             : crop->c.top;
+               if (crop->c.top > b->top + b->height)
+                       crop->c.top = b->top + b->height - 1;
+               if (crop->c.height > b->top + b->height - crop->c.top)
+                       crop->c.height =
+                               b->top + b->height - crop->c.top;
+
+               crop->c.left = (crop->c.left < b->left) ? b->left
+                   : crop->c.left;
+               if (crop->c.left > b->left + b->width)
+                       crop->c.left = b->left + b->width - 1;
+               if (crop->c.width > b->left - crop->c.left + b->width)
+                       crop->c.width =
+                               b->left - crop->c.left + b->width;
+
+               crop->c.width -= crop->c.width % 8;
+               crop->c.left -= crop->c.left % 4;
+               cam->crop_current = crop->c;
+
+               pr_debug("   Cropping Input to ipu size %d x %d\n",
+                               cam->crop_current.width,
+                               cam->crop_current.height);
+               ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+                                       cam->crop_current.height,
+                                       cam->csi);
+               ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+                                      cam->crop_current.top,
+                                      cam->csi);
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_OVERLAY ioctl
+        */
+       case VIDIOC_OVERLAY: {
+               int *on = arg;
+               pr_debug("   VIDIOC_OVERLAY on=%d\n", *on);
+               if (*on) {
+                       cam->overlay_on = true;
+                       cam->overlay_pid = current->pid;
+                       retval = start_preview(cam);
+               }
+               if (!*on) {
+                       retval = stop_preview(cam);
+                       cam->overlay_on = false;
+               }
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_G_FBUF ioctl
+        */
+       case VIDIOC_G_FBUF: {
+               struct v4l2_framebuffer *fb = arg;
+               pr_debug("   case VIDIOC_G_FBUF\n");
+               *fb = cam->v4l2_fb;
+               fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY;
+               break;
+       }
+
+       /*!
+        * V4l2 VIDIOC_S_FBUF ioctl
+        */
+       case VIDIOC_S_FBUF: {
+               struct v4l2_framebuffer *fb = arg;
+               pr_debug("   case VIDIOC_S_FBUF\n");
+               cam->v4l2_fb = *fb;
+               break;
+       }
+
+       case VIDIOC_G_PARM: {
+               struct v4l2_streamparm *parm = arg;
+               pr_debug("   case VIDIOC_G_PARM\n");
+               if (cam->sensor)
+                       retval = vidioc_int_g_parm(cam->sensor, parm);
+               else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       retval = -ENODEV;
+               }
+               break;
+       }
+
+       case VIDIOC_S_PARM:  {
+               struct v4l2_streamparm *parm = arg;
+               pr_debug("   case VIDIOC_S_PARM\n");
+               if (cam->sensor)
+                       retval = mxc_v4l2_s_param(cam, parm);
+               else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       retval = -ENODEV;
+               }
+               break;
+       }
+
+       /* linux v4l2 bug, kernel c0485619 user c0405619 */
+       case VIDIOC_ENUMSTD: {
+               struct v4l2_standard *e = arg;
+               pr_debug("   case VIDIOC_ENUMSTD\n");
+               *e = cam->standard;
+               break;
+       }
+
+       case VIDIOC_G_STD: {
+               v4l2_std_id *e = arg;
+               pr_debug("   case VIDIOC_G_STD\n");
+               if (cam->sensor)
+                       retval = mxc_v4l2_g_std(cam, e);
+               else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       retval = -ENODEV;
+               }
+               break;
+       }
+
+       case VIDIOC_S_STD: {
+               v4l2_std_id *e = arg;
+               pr_debug("   case VIDIOC_S_STD\n");
+               retval = mxc_v4l2_s_std(cam, *e);
+
+               break;
+       }
+
+       case VIDIOC_ENUMOUTPUT: {
+               struct v4l2_output *output = arg;
+               pr_debug("   case VIDIOC_ENUMOUTPUT\n");
+               if (output->index >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) {
+                       retval = -EINVAL;
+                       break;
+               }
+               *output = mxc_capture_outputs[output->index];
+
+               break;
+       }
+       case VIDIOC_G_OUTPUT: {
+               int *p_output_num = arg;
+               pr_debug("   case VIDIOC_G_OUTPUT\n");
+               *p_output_num = cam->output;
+               break;
+       }
+
+       case VIDIOC_S_OUTPUT: {
+               int *p_output_num = arg;
+               pr_debug("   case VIDIOC_S_OUTPUT\n");
+               if (*p_output_num >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) {
+                       retval = -EINVAL;
+                       break;
+               }
+               cam->output = *p_output_num;
+               break;
+       }
+
+       case VIDIOC_ENUMINPUT: {
+               struct v4l2_input *input = arg;
+               pr_debug("   case VIDIOC_ENUMINPUT\n");
+               if (input->index >= MXC_V4L2_CAPTURE_NUM_INPUTS) {
+                       retval = -EINVAL;
+                       break;
+               }
+               *input = mxc_capture_inputs[input->index];
+               break;
+       }
+
+       case VIDIOC_G_INPUT: {
+               int *index = arg;
+               pr_debug("   case VIDIOC_G_INPUT\n");
+               *index = cam->current_input;
+               break;
+       }
+
+       case VIDIOC_S_INPUT: {
+               int *index = arg;
+               pr_debug("   case VIDIOC_S_INPUT\n");
+               if (*index >= MXC_V4L2_CAPTURE_NUM_INPUTS) {
+                       retval = -EINVAL;
+                       break;
+               }
+
+               if (*index == cam->current_input)
+                       break;
+
+               if ((mxc_capture_inputs[cam->current_input].status &
+                   V4L2_IN_ST_NO_POWER) == 0) {
+                       retval = mxc_streamoff(cam);
+                       if (retval)
+                               break;
+                       mxc_capture_inputs[cam->current_input].status |=
+                                                       V4L2_IN_ST_NO_POWER;
+               }
+
+               if (strcmp(mxc_capture_inputs[*index].name, "CSI MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+                       retval = csi_enc_select(cam);
+                       if (retval)
+                               break;
+#endif
+               } else if (strcmp(mxc_capture_inputs[*index].name,
+                                 "CSI IC MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
+                       retval = prp_enc_select(cam);
+                       if (retval)
+                               break;
+#endif
+               }
+
+               mxc_capture_inputs[*index].status &= ~V4L2_IN_ST_NO_POWER;
+               cam->current_input = *index;
+               break;
+       }
+       case VIDIOC_ENUM_FMT: {
+               struct v4l2_fmtdesc *f = arg;
+               if (cam->sensor)
+                       retval = vidioc_int_enum_fmt_cap(cam->sensor, f);
+               else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       retval = -ENODEV;
+               }
+               break;
+       }
+       case VIDIOC_ENUM_FRAMESIZES: {
+               struct v4l2_frmsizeenum *fsize = arg;
+               if (cam->sensor)
+                       retval = vidioc_int_enum_framesizes(cam->sensor, fsize);
+               else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       retval = -ENODEV;
+               }
+               break;
+       }
+       case VIDIOC_DBG_G_CHIP_IDENT: {
+               struct v4l2_dbg_chip_ident *p = arg;
+               p->ident = V4L2_IDENT_NONE;
+               p->revision = 0;
+               if (cam->sensor)
+                       retval = vidioc_int_g_chip_ident(cam->sensor, (int *)p);
+               else {
+                       pr_err("ERROR: v4l2 capture: slave not found!\n");
+                       retval = -ENODEV;
+               }
+               break;
+       }
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_QUERYCTRL:
+       case VIDIOC_G_TUNER:
+       case VIDIOC_S_TUNER:
+       case VIDIOC_G_FREQUENCY:
+       case VIDIOC_S_FREQUENCY:
+       default:
+               pr_debug("   case default or not supported\n");
+               retval = -EINVAL;
+               break;
+       }
+
+       if (ioctlnr != VIDIOC_DQBUF)
+               up(&cam->busy_lock);
+       return retval;
+}
+
+/*
+ * V4L interface - ioctl function
+ *
+ * @return  None
+ */
+static long mxc_v4l_ioctl(struct file *file, unsigned int cmd,
+                        unsigned long arg)
+{
+       pr_debug("In MVC:mxc_v4l_ioctl\n");
+       return video_usercopy(file, cmd, arg, mxc_v4l_do_ioctl);
+}
+
+/*!
+ * V4L interface - mmap function
+ *
+ * @param file        structure file *
+ *
+ * @param vma         structure vm_area_struct *
+ *
+ * @return status     0 Success, EINTR busy lock error, ENOBUFS remap_page error
+ */
+static int mxc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *dev = video_devdata(file);
+       unsigned long size;
+       int res = 0;
+       cam_data *cam = video_get_drvdata(dev);
+
+       pr_debug("In MVC:mxc_mmap\n");
+       pr_debug("   pgoff=0x%lx, start=0x%lx, end=0x%lx\n",
+                vma->vm_pgoff, vma->vm_start, vma->vm_end);
+
+       /* make this _really_ smp-safe */
+       if (down_interruptible(&cam->busy_lock))
+               return -EINTR;
+
+       size = vma->vm_end - vma->vm_start;
+       vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+       if (remap_pfn_range(vma, vma->vm_start,
+                           vma->vm_pgoff, size, vma->vm_page_prot)) {
+               pr_err("ERROR: v4l2 capture: mxc_mmap: "
+                       "remap_pfn_range failed\n");
+               res = -ENOBUFS;
+               goto mxc_mmap_exit;
+       }
+
+       vma->vm_flags &= ~VM_IO;        /* using shared anonymous pages */
+
+mxc_mmap_exit:
+       up(&cam->busy_lock);
+       return res;
+}
+
+/*!
+ * V4L interface - poll function
+ *
+ * @param file       structure file *
+ *
+ * @param wait       structure poll_table_struct *
+ *
+ * @return  status   POLLIN | POLLRDNORM
+ */
+static unsigned int mxc_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct video_device *dev = video_devdata(file);
+       cam_data *cam = video_get_drvdata(dev);
+       wait_queue_head_t *queue = NULL;
+       int res = POLLIN | POLLRDNORM;
+
+       pr_debug("In MVC:mxc_poll\n");
+
+       if (down_interruptible(&cam->busy_lock))
+               return -EINTR;
+
+       queue = &cam->enc_queue;
+       poll_wait(file, queue, wait);
+
+       up(&cam->busy_lock);
+
+       return res;
+}
+
+/*!
+ * This structure defines the functions to be called in this driver.
+ */
+static struct v4l2_file_operations mxc_v4l_fops = {
+       .owner = THIS_MODULE,
+       .open = mxc_v4l_open,
+       .release = mxc_v4l_close,
+       .read = mxc_v4l_read,
+       .ioctl = mxc_v4l_ioctl,
+       .mmap = mxc_mmap,
+       .poll = mxc_poll,
+};
+
+static struct video_device mxc_v4l_template = {
+       .name = "Mxc Camera",
+       .fops = &mxc_v4l_fops,
+       .release = video_device_release,
+};
+
+/*!
+ * This function can be used to release any platform data on closing.
+ */
+static void camera_platform_release(struct device *device)
+{
+}
+
+/*!
+ * Camera V4l2 callback function.
+ *
+ * @param mask      u32
+ *
+ * @param dev       void device structure
+ *
+ * @return status
+ */
+static void camera_callback(u32 mask, void *dev)
+{
+       struct mxc_v4l_frame *done_frame;
+       struct mxc_v4l_frame *ready_frame;
+       struct timeval cur_time;
+
+       cam_data *cam = (cam_data *) dev;
+       if (cam == NULL)
+               return;
+
+       pr_debug("In MVC:camera_callback\n");
+
+       spin_lock(&cam->queue_int_lock);
+       spin_lock(&cam->dqueue_int_lock);
+       if (!list_empty(&cam->working_q)) {
+               do_gettimeofday(&cur_time);
+
+               done_frame = list_entry(cam->working_q.next,
+                                       struct mxc_v4l_frame,
+                                       queue);
+
+               if (done_frame->ipu_buf_num != cam->local_buf_num)
+                       goto next;
+
+               /*
+                * Set the current time to done frame buffer's
+                * timestamp. Users can use this information to judge
+                * the frame's usage.
+                */
+               done_frame->buffer.timestamp = cur_time;
+
+               if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
+                       done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE;
+                       done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
+
+                       /* Added to the done queue */
+                       list_del(cam->working_q.next);
+                       list_add_tail(&done_frame->queue, &cam->done_q);
+
+                       /* Wake up the queue */
+                       cam->enc_counter++;
+                       wake_up_interruptible(&cam->enc_queue);
+               } else
+                       pr_err("ERROR: v4l2 capture: camera_callback: "
+                               "buffer not queued\n");
+       }
+
+next:
+       if (!list_empty(&cam->ready_q)) {
+               ready_frame = list_entry(cam->ready_q.next,
+                                        struct mxc_v4l_frame,
+                                        queue);
+               if (cam->enc_update_eba)
+                       if (cam->enc_update_eba(cam->ipu,
+                                               ready_frame->buffer.m.offset,
+                                               &cam->ping_pong_csi) == 0) {
+                               list_del(cam->ready_q.next);
+                               list_add_tail(&ready_frame->queue,
+                                             &cam->working_q);
+                               ready_frame->ipu_buf_num = cam->local_buf_num;
+                       }
+       } else {
+               if (cam->enc_update_eba)
+                       cam->enc_update_eba(
+                               cam->ipu, cam->dummy_frame.buffer.m.offset,
+                               &cam->ping_pong_csi);
+       }
+
+       cam->local_buf_num = (cam->local_buf_num == 0) ? 1 : 0;
+       spin_unlock(&cam->dqueue_int_lock);
+       spin_unlock(&cam->queue_int_lock);
+
+       return;
+}
+
+/*!
+ * initialize cam_data structure
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int init_camera_struct(cam_data *cam, struct platform_device *pdev)
+{
+       const struct of_device_id *of_id =
+                       of_match_device(mxc_v4l2_dt_ids, &pdev->dev);
+       struct device_node *np = pdev->dev.of_node;
+       int ipu_id, csi_id, mclk_source;
+       int ret = 0;
+
+       pr_debug("In MVC: init_camera_struct\n");
+
+       ret = of_property_read_u32(np, "ipu_id", &ipu_id);
+       if (ret) {
+               dev_err(&pdev->dev, "ipu_id missing or invalid\n");
+               return ret;
+       }
+
+       ret = of_property_read_u32(np, "csi_id", &csi_id);
+       if (ret) {
+               dev_err(&pdev->dev, "csi_id missing or invalid\n");
+               return ret;
+       }
+
+       ret = of_property_read_u32(np, "mclk_source", &mclk_source);
+       if (ret) {
+               dev_err(&pdev->dev, "sensor mclk missing or invalid\n");
+               return ret;
+       }
+
+       /* Default everything to 0 */
+       memset(cam, 0, sizeof(cam_data));
+
+       /* get devtype to distinguish if the cpu is imx5 or imx6
+        * IMX5_V4L2 specify the cpu is imx5
+        * IMX6_V4L2 specify the cpu is imx6q or imx6sdl
+        */
+       if (of_id)
+               pdev->id_entry = of_id->data;
+       cam->devtype = pdev->id_entry->driver_data;
+
+       cam->ipu = ipu_get_soc(ipu_id);
+       if (cam->ipu == NULL) {
+               pr_err("ERROR: v4l2 capture: failed to get ipu\n");
+               return -EINVAL;
+       } else if (cam->ipu == ERR_PTR(-ENODEV)) {
+               pr_err("ERROR: v4l2 capture: get invalid ipu\n");
+               return -ENODEV;
+       }
+
+       init_MUTEX(&cam->param_lock);
+       init_MUTEX(&cam->busy_lock);
+
+       cam->video_dev = video_device_alloc();
+       if (cam->video_dev == NULL)
+               return -ENODEV;
+
+       *(cam->video_dev) = mxc_v4l_template;
+
+       video_set_drvdata(cam->video_dev, cam);
+       dev_set_drvdata(&pdev->dev, (void *)cam);
+       cam->video_dev->minor = -1;
+
+       init_waitqueue_head(&cam->enc_queue);
+       init_waitqueue_head(&cam->still_queue);
+
+       /* setup cropping */
+       cam->crop_bounds.left = 0;
+       cam->crop_bounds.width = 640;
+       cam->crop_bounds.top = 0;
+       cam->crop_bounds.height = 480;
+       cam->crop_current = cam->crop_defrect = cam->crop_bounds;
+       ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+                               cam->crop_current.height, cam->csi);
+       ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+                               cam->crop_current.top, cam->csi);
+       cam->streamparm.parm.capture.capturemode = 0;
+
+       cam->standard.index = 0;
+       cam->standard.id = V4L2_STD_UNKNOWN;
+       cam->standard.frameperiod.denominator = 30;
+       cam->standard.frameperiod.numerator = 1;
+       cam->standard.framelines = 480;
+       cam->standard_autodetect = true;
+       cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod;
+       cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+       cam->overlay_on = false;
+       cam->capture_on = false;
+       cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY;
+
+       cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2;
+       cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2;
+       cam->v2f.fmt.pix.width = 288;
+       cam->v2f.fmt.pix.height = 352;
+       cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+       cam->win.w.width = 160;
+       cam->win.w.height = 160;
+       cam->win.w.left = 0;
+       cam->win.w.top = 0;
+
+       cam->ipu_id = ipu_id;
+       cam->csi = csi_id;
+       cam->mclk_source = mclk_source;
+       cam->mclk_on[cam->mclk_source] = false;
+
+       cam->enc_callback = camera_callback;
+       init_waitqueue_head(&cam->power_queue);
+       spin_lock_init(&cam->queue_int_lock);
+       spin_lock_init(&cam->dqueue_int_lock);
+
+       cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL);
+       cam->self->module = THIS_MODULE;
+       sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi);
+       cam->self->type = v4l2_int_type_master;
+       cam->self->u.master = &mxc_v4l2_master;
+
+       return 0;
+}
+
+static ssize_t show_streaming(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct video_device *video_dev = container_of(dev,
+                                               struct video_device, dev);
+       cam_data *cam = video_get_drvdata(video_dev);
+
+       if (cam->capture_on)
+               return sprintf(buf, "stream on\n");
+       else
+               return sprintf(buf, "stream off\n");
+}
+static DEVICE_ATTR(fsl_v4l2_capture_property, S_IRUGO, show_streaming, NULL);
+
+static ssize_t show_overlay(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct video_device *video_dev = container_of(dev,
+                                               struct video_device, dev);
+       cam_data *cam = video_get_drvdata(video_dev);
+
+       if (cam->overlay_on)
+               return sprintf(buf, "overlay on\n");
+       else
+               return sprintf(buf, "overlay off\n");
+}
+static DEVICE_ATTR(fsl_v4l2_overlay_property, S_IRUGO, show_overlay, NULL);
+
+static ssize_t show_csi(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct video_device *video_dev = container_of(dev,
+                                               struct video_device, dev);
+       cam_data *cam = video_get_drvdata(video_dev);
+
+       return sprintf(buf, "ipu%d_csi%d\n", cam->ipu_id, cam->csi);
+}
+static DEVICE_ATTR(fsl_csi_property, S_IRUGO, show_csi, NULL);
+
+/*!
+ * This function is called to probe the devices if registered.
+ *
+ * @param   pdev  the device structure used to give information on which device
+ *                to probe
+ *
+ * @return  The function returns 0 on success and -1 on failure.
+ */
+static int mxc_v4l2_probe(struct platform_device *pdev)
+{
+       /* Create cam and initialize it. */
+       cam_data *cam = kmalloc(sizeof(cam_data), GFP_KERNEL);
+       if (cam == NULL) {
+               pr_err("ERROR: v4l2 capture: failed to register camera\n");
+               return -1;
+       }
+
+       init_camera_struct(cam, pdev);
+       pdev->dev.release = camera_platform_release;
+
+       /* Set up the v4l2 device and register it*/
+       cam->self->priv = cam;
+       v4l2_int_device_register(cam->self);
+
+       /* register v4l video device */
+       if (video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr)
+           == -1) {
+               kfree(cam);
+               cam = NULL;
+               pr_err("ERROR: v4l2 capture: video_register_device failed\n");
+               return -1;
+       }
+       pr_debug("   Video device registered: %s #%d\n",
+                cam->video_dev->name, cam->video_dev->minor);
+
+       if (device_create_file(&cam->video_dev->dev,
+                       &dev_attr_fsl_v4l2_capture_property))
+               dev_err(&pdev->dev, "Error on creating sysfs file"
+                       " for capture\n");
+
+       if (device_create_file(&cam->video_dev->dev,
+                       &dev_attr_fsl_v4l2_overlay_property))
+               dev_err(&pdev->dev, "Error on creating sysfs file"
+                       " for overlay\n");
+
+       if (device_create_file(&cam->video_dev->dev,
+                       &dev_attr_fsl_csi_property))
+               dev_err(&pdev->dev, "Error on creating sysfs file"
+                       " for csi number\n");
+
+       return 0;
+}
+
+/*!
+ * This function is called to remove the devices when device unregistered.
+ *
+ * @param   pdev  the device structure used to give information on which device
+ *                to remove
+ *
+ * @return  The function returns 0 on success and -1 on failure.
+ */
+static int mxc_v4l2_remove(struct platform_device *pdev)
+{
+       cam_data *cam = (cam_data *)platform_get_drvdata(pdev);
+       if (cam->open_count) {
+               pr_err("ERROR: v4l2 capture:camera open "
+                       "-- setting ops to NULL\n");
+               return -EBUSY;
+       } else {
+               device_remove_file(&cam->video_dev->dev,
+                       &dev_attr_fsl_v4l2_capture_property);
+               device_remove_file(&cam->video_dev->dev,
+                       &dev_attr_fsl_v4l2_overlay_property);
+               device_remove_file(&cam->video_dev->dev,
+                       &dev_attr_fsl_csi_property);
+
+               pr_info("V4L2 freeing image input device\n");
+               v4l2_int_device_unregister(cam->self);
+               video_unregister_device(cam->video_dev);
+
+               mxc_free_frame_buf(cam);
+               kfree(cam);
+       }
+
+       pr_info("V4L2 unregistering video\n");
+       return 0;
+}
+
+/*!
+ * This function is called to put the sensor in a low power state.
+ * Refer to the document driver-model/driver.txt in the kernel source tree
+ * for more information.
+ *
+ * @param   pdev  the device structure used to give information on which I2C
+ *                to suspend
+ * @param   state the power state the device is entering
+ *
+ * @return  The function returns 0 on success and -1 on failure.
+ */
+static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       cam_data *cam = platform_get_drvdata(pdev);
+
+       pr_debug("In MVC:mxc_v4l2_suspend\n");
+
+       if (cam == NULL)
+               return -1;
+
+       down(&cam->busy_lock);
+
+       cam->low_power = true;
+
+       if (cam->overlay_on == true)
+               stop_preview(cam);
+       if ((cam->capture_on == true) && cam->enc_disable)
+               cam->enc_disable(cam);
+
+       if (cam->sensor && cam->open_count) {
+               if (cam->mclk_on[cam->mclk_source]) {
+                       ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C,
+                                              cam->mclk_source,
+                                              false, false);
+                       cam->mclk_on[cam->mclk_source] = false;
+               }
+               vidioc_int_s_power(cam->sensor, 0);
+       }
+
+       up(&cam->busy_lock);
+
+       return 0;
+}
+
+/*!
+ * This function is called to bring the sensor back from a low power state.
+ * Refer to the document driver-model/driver.txt in the kernel source tree
+ * for more information.
+ *
+ * @param   pdev   the device structure
+ *
+ * @return  The function returns 0 on success and -1 on failure
+ */
+static int mxc_v4l2_resume(struct platform_device *pdev)
+{
+       cam_data *cam = platform_get_drvdata(pdev);
+
+       pr_debug("In MVC:mxc_v4l2_resume\n");
+
+       if (cam == NULL)
+               return -1;
+
+       down(&cam->busy_lock);
+
+       cam->low_power = false;
+       wake_up_interruptible(&cam->power_queue);
+
+       if (cam->sensor && cam->open_count) {
+               vidioc_int_s_power(cam->sensor, 1);
+
+               if (!cam->mclk_on[cam->mclk_source]) {
+                       ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C,
+                                              cam->mclk_source,
+                                              true, true);
+                       cam->mclk_on[cam->mclk_source] = true;
+               }
+       }
+
+       if (cam->overlay_on == true)
+               start_preview(cam);
+       if (cam->capture_on == true)
+               mxc_streamon(cam);
+
+       up(&cam->busy_lock);
+
+       return 0;
+}
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxc_v4l2_driver = {
+       .driver = {
+                  .name = "mxc_v4l2_capture",
+                  .owner = THIS_MODULE,
+                  .of_match_table = mxc_v4l2_dt_ids,
+                  },
+       .id_table = imx_v4l2_devtype,
+       .probe = mxc_v4l2_probe,
+       .remove = mxc_v4l2_remove,
+       .suspend = mxc_v4l2_suspend,
+       .resume = mxc_v4l2_resume,
+       .shutdown = NULL,
+};
+
+/*!
+ * Initializes the camera driver.
+ */
+static int mxc_v4l2_master_attach(struct v4l2_int_device *slave)
+{
+       cam_data *cam = slave->u.slave->master->priv;
+       struct v4l2_format cam_fmt;
+       int i;
+       struct sensor_data *sdata = slave->priv;
+
+       pr_debug("In MVC: mxc_v4l2_master_attach\n");
+       pr_debug("   slave.name = %s\n", slave->name);
+       pr_debug("   master.name = %s\n", slave->u.slave->master->name);
+
+       if (slave == NULL) {
+               pr_err("ERROR: v4l2 capture: slave parameter not valid.\n");
+               return -1;
+       }
+
+       if (sdata->csi != cam->csi) {
+               pr_debug("%s: csi doesn't match\n", __func__);
+               return -1;
+       }
+
+       cam->sensor = slave;
+
+       if (cam->sensor_index < MXC_SENSOR_NUM) {
+               cam->all_sensors[cam->sensor_index] = slave;
+               cam->sensor_index++;
+       } else {
+               pr_err("ERROR: v4l2 capture: slave number exceeds the maximum.\n");
+               return -1;
+       }
+
+       for (i = 0; i < cam->sensor_index; i++) {
+               vidioc_int_dev_exit(cam->all_sensors[i]);
+               vidioc_int_s_power(cam->all_sensors[i], 0);
+       }
+
+       cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);
+
+       /* Used to detect TV in (type 1) vs. camera (type 0)*/
+       cam->device_type = cam_fmt.fmt.pix.priv;
+
+       /* Set the input size to the ipu for this device */
+       cam->crop_bounds.top = cam->crop_bounds.left = 0;
+       cam->crop_bounds.width = cam_fmt.fmt.pix.width;
+       cam->crop_bounds.height = cam_fmt.fmt.pix.height;
+
+       /* This also is the max crop size for this device. */
+       cam->crop_defrect.top = cam->crop_defrect.left = 0;
+       cam->crop_defrect.width = cam_fmt.fmt.pix.width;
+       cam->crop_defrect.height = cam_fmt.fmt.pix.height;
+
+       /* At this point, this is also the current image size. */
+       cam->crop_current.top = cam->crop_current.left = 0;
+       cam->crop_current.width = cam_fmt.fmt.pix.width;
+       cam->crop_current.height = cam_fmt.fmt.pix.height;
+
+       pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+                __func__,
+                cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+       pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+                __func__,
+                cam->crop_bounds.width, cam->crop_bounds.height);
+       pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+                __func__,
+                cam->crop_defrect.width, cam->crop_defrect.height);
+       pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+                __func__,
+                cam->crop_current.width, cam->crop_current.height);
+
+       return 0;
+}
+
+/*!
+ * Disconnects the camera driver.
+ */
+static void mxc_v4l2_master_detach(struct v4l2_int_device *slave)
+{
+       unsigned int i;
+       cam_data *cam = slave->u.slave->master->priv;
+
+       pr_debug("In MVC:mxc_v4l2_master_detach\n");
+
+       if (cam->sensor_index > 1) {
+               for (i = 0; i < cam->sensor_index; i++) {
+                       if (cam->all_sensors[i] != slave)
+                               continue;
+                       /* Move all the sensors behind this
+                        * sensor one step forward
+                        */
+                       for (; i < cam->sensor_index - 1; i++)
+                               cam->all_sensors[i] = cam->all_sensors[i+1];
+                       break;
+               }
+               /* Point current sensor to the last one */
+               cam->sensor = cam->all_sensors[cam->sensor_index - 2];
+       } else
+               cam->sensor = NULL;
+
+       cam->sensor_index--;
+       vidioc_int_dev_exit(slave);
+}
+
+/*!
+ * Entry point for the V4L2
+ *
+ * @return  Error code indicating success or failure
+ */
+static __init int camera_init(void)
+{
+       u8 err = 0;
+
+       pr_debug("In MVC:camera_init\n");
+
+       /* Register the device driver structure. */
+       err = platform_driver_register(&mxc_v4l2_driver);
+       if (err != 0) {
+               pr_err("ERROR: v4l2 capture:camera_init: "
+                       "platform_driver_register failed.\n");
+               return err;
+       }
+
+       return err;
+}
+
+/*!
+ * Exit and cleanup for the V4L2
+ */
+static void __exit camera_exit(void)
+{
+       pr_debug("In MVC: camera_exit\n");
+
+       platform_driver_unregister(&mxc_v4l2_driver);
+}
+
+module_init(camera_init);
+module_exit(camera_exit);
+
+module_param(video_nr, int, 0444);
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("V4L2 capture driver for Mxc based cameras");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");