summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandor Yu <R01008@freescale.com>2014-11-10 15:36:49 +0800
committerNitin Garg <nitin.garg@freescale.com>2015-04-14 14:01:01 -0500
commite562678d5358bcf7939714c93a52c6e07b5e3d60 (patch)
tree066602f9ed4a0db03c4133c878f5589c397b456c
parent3fc2e5ca16709b2cda19d0098216b0a7812f0725 (diff)
MLK-9779-01 camera: imx6sx/sl CSI/VADC driver in subdev
CSI and VADC driver rewrite with v4l2 subdev architecture. - mx6s_capture.c driver support imx6sx and imx6sl csi module. - No PXP function included in csi driver, csi driver not support csc, crop and resize function. - Both csi and vadc driver register device tree. - v4l2 subdev bridge device drivers register device with asynchronous. Signed-off-by: Sandor Yu <R01008@freescale.com>
-rw-r--r--drivers/media/platform/Kconfig1
-rw-r--r--drivers/media/platform/Makefile1
-rw-r--r--drivers/media/platform/mxc/subdev/Kconfig21
-rw-r--r--drivers/media/platform/mxc/subdev/Makefile4
-rw-r--r--drivers/media/platform/mxc/subdev/mx6s_capture.c1694
-rw-r--r--drivers/media/platform/mxc/subdev/mxc_vadc.c752
-rw-r--r--drivers/media/platform/mxc/subdev/mxc_vadc.h236
7 files changed, 2709 insertions, 0 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index c8eac2e7ab08..f4994cb2c85e 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -130,6 +130,7 @@ config VIDEO_MXC_CAPTURE
source "drivers/media/platform/mxc/capture/Kconfig"
source "drivers/media/platform/mxc/output/Kconfig"
+source "drivers/media/platform/mxc/subdev/Kconfig"
source "drivers/media/platform/soc_camera/Kconfig"
source "drivers/media/platform/exynos4-is/Kconfig"
source "drivers/media/platform/s5p-tv/Kconfig"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 094a575bb2f3..e934a36436ec 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -52,6 +52,7 @@ obj-y += davinci/
obj-$(CONFIG_ARCH_OMAP) += omap/
obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/capture/
+obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/subdev/
obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mxc/output/
ccflags-y += -I$(srctree)/drivers/media/i2c
diff --git a/drivers/media/platform/mxc/subdev/Kconfig b/drivers/media/platform/mxc/subdev/Kconfig
new file mode 100644
index 000000000000..d3fc164e9f33
--- /dev/null
+++ b/drivers/media/platform/mxc/subdev/Kconfig
@@ -0,0 +1,21 @@
+if VIDEO_MXC_CAPTURE
+
+config VIDEO_MXC_CSI_CAMERA
+ tristate "CSI camera support"
+ depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
+ ---help---
+ This is the video4linux2 capture driver based on CSI module.
+
+config MXC_CAMERA_OV5640
+ tristate "OmniVision ov5640 camera support"
+ depends on VIDEO_MXC_CAPTURE && I2C
+ ---help---
+ If you plan to use the ov5640 Camera with your MXC system, say Y here.
+
+config MXC_VADC
+ tristate "mxc VADC support"
+ depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
+ ---help---
+ If you plan to use the VADC with your MXC system, say Y here.
+
+endif
diff --git a/drivers/media/platform/mxc/subdev/Makefile b/drivers/media/platform/mxc/subdev/Makefile
new file mode 100644
index 000000000000..7ace6919fd3f
--- /dev/null
+++ b/drivers/media/platform/mxc/subdev/Makefile
@@ -0,0 +1,4 @@
+#Makefile for mxc csi driver
+
+obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += mx6s_capture.o
+obj-$(CONFIG_MXC_VADC) += mxc_vadc.o
diff --git a/drivers/media/platform/mxc/subdev/mx6s_capture.c b/drivers/media/platform/mxc/subdev/mx6s_capture.c
new file mode 100644
index 000000000000..63b5e14e89b5
--- /dev/null
+++ b/drivers/media/platform/mxc/subdev/mx6s_capture.c
@@ -0,0 +1,1694 @@
+/*
+ * Copyright (C) 2014 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 mx6s_csi.c
+ *
+ * @brief mx6sx CMOS Sensor interface functions
+ *
+ * @ingroup CSI
+ */
+#include <asm/dma.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/gcd.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-of.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define MX6S_CAM_DRV_NAME "mx6s-csi"
+#define MX6S_CAM_VERSION "0.0.1"
+#define MX6S_CAM_DRIVER_DESCRIPTION "i.MX6S_CSI"
+
+#define MAX_VIDEO_MEM 16
+
+/* reset values */
+#define CSICR1_RESET_VAL 0x40000800
+#define CSICR2_RESET_VAL 0x0
+#define CSICR3_RESET_VAL 0x0
+
+/* csi control reg 1 */
+#define BIT_SWAP16_EN (0x1 << 31)
+#define BIT_EXT_VSYNC (0x1 << 30)
+#define BIT_EOF_INT_EN (0x1 << 29)
+#define BIT_PRP_IF_EN (0x1 << 28)
+#define BIT_CCIR_MODE (0x1 << 27)
+#define BIT_COF_INT_EN (0x1 << 26)
+#define BIT_SF_OR_INTEN (0x1 << 25)
+#define BIT_RF_OR_INTEN (0x1 << 24)
+#define BIT_SFF_DMA_DONE_INTEN (0x1 << 22)
+#define BIT_STATFF_INTEN (0x1 << 21)
+#define BIT_FB2_DMA_DONE_INTEN (0x1 << 20)
+#define BIT_FB1_DMA_DONE_INTEN (0x1 << 19)
+#define BIT_RXFF_INTEN (0x1 << 18)
+#define BIT_SOF_POL (0x1 << 17)
+#define BIT_SOF_INTEN (0x1 << 16)
+#define BIT_MCLKDIV (0xF << 12)
+#define BIT_HSYNC_POL (0x1 << 11)
+#define BIT_CCIR_EN (0x1 << 10)
+#define BIT_MCLKEN (0x1 << 9)
+#define BIT_FCC (0x1 << 8)
+#define BIT_PACK_DIR (0x1 << 7)
+#define BIT_CLR_STATFIFO (0x1 << 6)
+#define BIT_CLR_RXFIFO (0x1 << 5)
+#define BIT_GCLK_MODE (0x1 << 4)
+#define BIT_INV_DATA (0x1 << 3)
+#define BIT_INV_PCLK (0x1 << 2)
+#define BIT_REDGE (0x1 << 1)
+#define BIT_PIXEL_BIT (0x1 << 0)
+
+#define SHIFT_MCLKDIV 12
+
+/* control reg 3 */
+#define BIT_FRMCNT (0xFFFF << 16)
+#define BIT_FRMCNT_RST (0x1 << 15)
+#define BIT_DMA_REFLASH_RFF (0x1 << 14)
+#define BIT_DMA_REFLASH_SFF (0x1 << 13)
+#define BIT_DMA_REQ_EN_RFF (0x1 << 12)
+#define BIT_DMA_REQ_EN_SFF (0x1 << 11)
+#define BIT_STATFF_LEVEL (0x7 << 8)
+#define BIT_HRESP_ERR_EN (0x1 << 7)
+#define BIT_RXFF_LEVEL (0x7 << 4)
+#define BIT_TWO_8BIT_SENSOR (0x1 << 3)
+#define BIT_ZERO_PACK_EN (0x1 << 2)
+#define BIT_ECC_INT_EN (0x1 << 1)
+#define BIT_ECC_AUTO_EN (0x1 << 0)
+
+#define SHIFT_FRMCNT 16
+#define SHIFT_RXFIFO_LEVEL 4
+
+/* csi status reg */
+#define BIT_ADDR_CH_ERR_INT (0x1 << 28)
+#define BIT_FIELD0_INT (0x1 << 27)
+#define BIT_FIELD1_INT (0x1 << 26)
+#define BIT_SFF_OR_INT (0x1 << 25)
+#define BIT_RFF_OR_INT (0x1 << 24)
+#define BIT_DMA_TSF_DONE_SFF (0x1 << 22)
+#define BIT_STATFF_INT (0x1 << 21)
+#define BIT_DMA_TSF_DONE_FB2 (0x1 << 20)
+#define BIT_DMA_TSF_DONE_FB1 (0x1 << 19)
+#define BIT_RXFF_INT (0x1 << 18)
+#define BIT_EOF_INT (0x1 << 17)
+#define BIT_SOF_INT (0x1 << 16)
+#define BIT_F2_INT (0x1 << 15)
+#define BIT_F1_INT (0x1 << 14)
+#define BIT_COF_INT (0x1 << 13)
+#define BIT_HRESP_ERR_INT (0x1 << 7)
+#define BIT_ECC_INT (0x1 << 1)
+#define BIT_DRDY (0x1 << 0)
+
+/* csi control reg 18 */
+#define BIT_CSI_ENABLE (0x1 << 31)
+#define BIT_BASEADDR_CHG_ERR_EN (0x1 << 9)
+#define BIT_BASEADDR_SWITCH_SEL (0x1 << 5)
+#define BIT_BASEADDR_SWITCH_EN (0x1 << 4)
+#define BIT_PARALLEL24_EN (0x1 << 3)
+#define BIT_DEINTERLACE_EN (0x1 << 2)
+#define BIT_TVDECODER_IN_EN (0x1 << 1)
+#define BIT_NTSC_EN (0x1 << 0)
+
+#define CSI_MCLK_VF 1
+#define CSI_MCLK_ENC 2
+#define CSI_MCLK_RAW 4
+#define CSI_MCLK_I2C 8
+
+#define CSI_CSICR1 0x0
+#define CSI_CSICR2 0x4
+#define CSI_CSICR3 0x8
+#define CSI_STATFIFO 0xC
+#define CSI_CSIRXFIFO 0x10
+#define CSI_CSIRXCNT 0x14
+#define CSI_CSISR 0x18
+
+#define CSI_CSIDBG 0x1C
+#define CSI_CSIDMASA_STATFIFO 0x20
+#define CSI_CSIDMATS_STATFIFO 0x24
+#define CSI_CSIDMASA_FB1 0x28
+#define CSI_CSIDMASA_FB2 0x2C
+#define CSI_CSIFBUF_PARA 0x30
+#define CSI_CSIIMAG_PARA 0x34
+
+#define CSI_CSICR18 0x48
+#define CSI_CSICR19 0x4c
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+#define MX6SX_MAX_SENSORS 1
+
+struct csi_signal_cfg_t {
+ unsigned data_width:3;
+ unsigned clk_mode:2;
+ unsigned ext_vsync:1;
+ unsigned Vsync_pol:1;
+ unsigned Hsync_pol:1;
+ unsigned pixclk_pol:1;
+ unsigned data_pol:1;
+ unsigned sens_clksrc:1;
+};
+
+struct csi_config_t {
+ /* control reg 1 */
+ unsigned int swap16_en:1;
+ unsigned int ext_vsync:1;
+ unsigned int eof_int_en:1;
+ unsigned int prp_if_en:1;
+ unsigned int ccir_mode:1;
+ unsigned int cof_int_en:1;
+ unsigned int sf_or_inten:1;
+ unsigned int rf_or_inten:1;
+ unsigned int sff_dma_done_inten:1;
+ unsigned int statff_inten:1;
+ unsigned int fb2_dma_done_inten:1;
+ unsigned int fb1_dma_done_inten:1;
+ unsigned int rxff_inten:1;
+ unsigned int sof_pol:1;
+ unsigned int sof_inten:1;
+ unsigned int mclkdiv:4;
+ unsigned int hsync_pol:1;
+ unsigned int ccir_en:1;
+ unsigned int mclken:1;
+ unsigned int fcc:1;
+ unsigned int pack_dir:1;
+ unsigned int gclk_mode:1;
+ unsigned int inv_data:1;
+ unsigned int inv_pclk:1;
+ unsigned int redge:1;
+ unsigned int pixel_bit:1;
+
+ /* control reg 3 */
+ unsigned int frmcnt:16;
+ unsigned int frame_reset:1;
+ unsigned int dma_reflash_rff:1;
+ unsigned int dma_reflash_sff:1;
+ unsigned int dma_req_en_rff:1;
+ unsigned int dma_req_en_sff:1;
+ unsigned int statff_level:3;
+ unsigned int hresp_err_en:1;
+ unsigned int rxff_level:3;
+ unsigned int two_8bit_sensor:1;
+ unsigned int zero_pack_en:1;
+ unsigned int ecc_int_en:1;
+ unsigned int ecc_auto_en:1;
+ /* fifo counter */
+ unsigned int rxcnt;
+};
+
+/*
+ * Basic structures
+ */
+struct mx6s_fmt {
+ char name[32];
+ u32 fourcc; /* v4l2 format id */
+ u32 pixelformat;
+ enum v4l2_mbus_pixelcode mbus_code;
+ int bpp;
+};
+
+static struct mx6s_fmt formats[] = {
+ {
+ .name = "UYVY-16",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .bpp = 2,
+ }, {
+ .name = "YUYV-16",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .bpp = 2,
+ }, {
+ .name = "YUV-444 (X-Y-U-V)",
+ .fourcc = V4L2_PIX_FMT_YUV444,
+ .pixelformat = V4L2_PIX_FMT_YUV444,
+ .mbus_code = V4L2_MBUS_FMT_AYUV8_1X32,
+ .bpp = 4,
+ }
+};
+
+struct mx6s_buf_internal {
+ struct list_head queue;
+ int bufnum;
+ bool discard;
+};
+
+/* buffer for one video frame */
+struct mx6s_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_buffer vb;
+ struct mx6s_buf_internal internal;
+};
+
+struct mx6s_csi_dev {
+ struct device *dev;
+ struct video_device *vdev;
+ struct v4l2_subdev *sd;
+ struct v4l2_device v4l2_dev;
+
+ struct vb2_queue vb2_vidq;
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ struct mutex lock;
+ spinlock_t slock;
+
+ /* clock */
+ struct clk *clk_disp_axi;
+ struct clk *clk_disp_dcic;
+ struct clk *clk_csi_mclk;
+
+ void __iomem *regbase;
+ int irq;
+
+ u32 type;
+ u32 bytesperline;
+ v4l2_std_id std;
+ struct mx6s_fmt *fmt;
+ struct v4l2_pix_format pix;
+ enum v4l2_mbus_pixelcode mbus_code;
+
+ unsigned int frame_count;
+
+ struct list_head capture;
+ struct list_head active_bufs;
+ struct list_head discard;
+
+ void *discard_buffer;
+ dma_addr_t discard_buffer_dma;
+ size_t discard_size;
+ struct mx6s_buf_internal buf_discard[2];
+
+ struct v4l2_async_subdev asd;
+ struct v4l2_async_notifier subdev_notifier;
+ struct v4l2_async_subdev *async_subdevs[2];
+};
+
+static inline int csi_read(struct mx6s_csi_dev *csi, unsigned int offset)
+{
+ return __raw_readl(csi->regbase + offset);
+}
+static inline void csi_write(struct mx6s_csi_dev *csi, unsigned int value,
+ unsigned int offset)
+{
+ __raw_writel(value, csi->regbase + offset);
+}
+
+static inline struct mx6s_csi_dev
+ *notifier_to_mx6s_dev(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct mx6s_csi_dev, subdev_notifier);
+}
+
+struct mx6s_fmt *format_by_fourcc(int fourcc)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == fourcc)
+ return formats + i;
+ }
+
+ printk(KERN_INFO"unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+ return NULL;
+}
+
+static struct mx6s_buffer *mx6s_ibuf_to_buf(struct mx6s_buf_internal *int_buf)
+{
+ return container_of(int_buf, struct mx6s_buffer, internal);
+}
+
+void csi_clk_enable(struct mx6s_csi_dev *csi_dev)
+{
+ clk_prepare_enable(csi_dev->clk_disp_axi);
+ clk_prepare_enable(csi_dev->clk_disp_dcic);
+ clk_prepare_enable(csi_dev->clk_csi_mclk);
+}
+
+void csi_clk_disable(struct mx6s_csi_dev *csi_dev)
+{
+ clk_disable_unprepare(csi_dev->clk_csi_mclk);
+ clk_disable_unprepare(csi_dev->clk_disp_dcic);
+ clk_disable_unprepare(csi_dev->clk_disp_axi);
+}
+
+static void csihw_reset(struct mx6s_csi_dev *csi_dev)
+{
+ __raw_writel(__raw_readl(csi_dev->regbase + CSI_CSICR3)
+ | BIT_FRMCNT_RST,
+ csi_dev->regbase + CSI_CSICR3);
+
+ __raw_writel(CSICR1_RESET_VAL, csi_dev->regbase + CSI_CSICR1);
+ __raw_writel(CSICR2_RESET_VAL, csi_dev->regbase + CSI_CSICR2);
+ __raw_writel(CSICR3_RESET_VAL, csi_dev->regbase + CSI_CSICR3);
+}
+
+static void csisw_reset(struct mx6s_csi_dev *csi_dev)
+{
+ int cr1, cr3, cr18, isr;
+
+ /* Disable csi */
+ cr18 = csi_read(csi_dev, CSI_CSICR18);
+ cr18 &= ~BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+
+ /* Clear RX FIFO */
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1);
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1);
+
+ /* DMA reflash */
+ cr3 = csi_read(csi_dev, CSI_CSICR3);
+ cr3 |= BIT_DMA_REFLASH_RFF | BIT_FRMCNT_RST;
+ csi_write(csi_dev, cr3, CSI_CSICR3);
+
+ msleep(2);
+
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1);
+
+ isr = csi_read(csi_dev, CSI_CSISR);
+ csi_write(csi_dev, isr, CSI_CSISR);
+
+ /* Ensable csi */
+ cr18 |= BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+}
+
+/*!
+ * csi_init_interface
+ * Init csi interface
+ */
+static void csi_init_interface(struct mx6s_csi_dev *csi_dev)
+{
+ unsigned int val = 0;
+ unsigned int imag_para;
+
+ val |= BIT_SOF_POL;
+ val |= BIT_REDGE;
+ val |= BIT_GCLK_MODE;
+ val |= BIT_HSYNC_POL;
+ val |= BIT_FCC;
+ val |= 1 << SHIFT_MCLKDIV;
+ val |= BIT_MCLKEN;
+ __raw_writel(val, csi_dev->regbase + CSI_CSICR1);
+
+ imag_para = (640 << 16) | 960;
+ __raw_writel(imag_para, csi_dev->regbase + CSI_CSIIMAG_PARA);
+
+ val = BIT_DMA_REFLASH_RFF;
+ __raw_writel(val, csi_dev->regbase + CSI_CSICR3);
+}
+
+static void csi_enable_int(struct mx6s_csi_dev *csi_dev, int arg)
+{
+ unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1);
+
+ cr1 |= BIT_SOF_INTEN;
+ if (arg == 1) {
+ /* still capture needs DMA intterrupt */
+ cr1 |= BIT_FB1_DMA_DONE_INTEN;
+ cr1 |= BIT_FB2_DMA_DONE_INTEN;
+ }
+ __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1);
+}
+
+static void csi_disable_int(struct mx6s_csi_dev *csi_dev)
+{
+ unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1);
+
+ cr1 &= ~BIT_SOF_INTEN;
+ cr1 &= ~BIT_FB1_DMA_DONE_INTEN;
+ cr1 &= ~BIT_FB2_DMA_DONE_INTEN;
+ __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1);
+}
+
+static void csi_enable(struct mx6s_csi_dev *csi_dev, int arg)
+{
+ unsigned long cr = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+
+ if (arg == 1)
+ cr |= BIT_CSI_ENABLE;
+ else
+ cr &= ~BIT_CSI_ENABLE;
+ __raw_writel(cr, csi_dev->regbase + CSI_CSICR18);
+}
+
+static void csi_buf_stride_set(struct mx6s_csi_dev *csi_dev, u32 stride)
+{
+ __raw_writel(stride, csi_dev->regbase + CSI_CSIFBUF_PARA);
+}
+
+static void csi_deinterlace_enable(struct mx6s_csi_dev *csi_dev, bool enable)
+{
+ unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+
+ if (enable == true)
+ cr18 |= BIT_DEINTERLACE_EN;
+ else
+ cr18 &= ~BIT_DEINTERLACE_EN;
+
+ __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18);
+}
+
+static void csi_deinterlace_mode(struct mx6s_csi_dev *csi_dev, int mode)
+{
+ unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+
+ if (mode == V4L2_STD_NTSC)
+ cr18 |= BIT_NTSC_EN;
+ else
+ cr18 &= ~BIT_NTSC_EN;
+
+ __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18);
+}
+
+static void csi_tvdec_enable(struct mx6s_csi_dev *csi_dev, bool enable)
+{
+ unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+ unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1);
+
+ if (enable == true) {
+ cr18 |= (BIT_TVDECODER_IN_EN |
+ BIT_BASEADDR_SWITCH_EN |
+ BIT_BASEADDR_SWITCH_SEL |
+ BIT_BASEADDR_CHG_ERR_EN);
+ cr1 |= BIT_CCIR_MODE;
+ cr1 &= ~(BIT_SOF_POL | BIT_REDGE);
+ } else {
+ cr18 &= ~(BIT_TVDECODER_IN_EN |
+ BIT_BASEADDR_SWITCH_EN |
+ BIT_BASEADDR_SWITCH_SEL |
+ BIT_BASEADDR_CHG_ERR_EN);
+ cr1 &= ~BIT_CCIR_MODE;
+ cr1 |= BIT_SOF_POL | BIT_REDGE;
+ }
+
+ __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18);
+ __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1);
+}
+
+static void csi_dmareq_rff_enable(struct mx6s_csi_dev *csi_dev)
+{
+ unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3);
+ unsigned long cr2 = __raw_readl(csi_dev->regbase + CSI_CSICR2);
+
+ /* Burst Type of DMA Transfer from RxFIFO. INCR16 */
+ cr2 |= 0xC0000000;
+
+ cr3 |= BIT_DMA_REQ_EN_RFF;
+ cr3 |= BIT_HRESP_ERR_EN;
+ cr3 &= ~BIT_RXFF_LEVEL;
+ cr3 |= 0x2 << 4;
+
+ __raw_writel(cr3, csi_dev->regbase + CSI_CSICR3);
+ __raw_writel(cr2, csi_dev->regbase + CSI_CSICR2);
+}
+
+static void csi_dmareq_rff_disable(struct mx6s_csi_dev *csi_dev)
+{
+ unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3);
+
+ cr3 &= ~BIT_DMA_REQ_EN_RFF;
+ cr3 &= ~BIT_HRESP_ERR_EN;
+ __raw_writel(cr3, csi_dev->regbase + CSI_CSICR3);
+}
+
+static void csi_set_32bit_imagpara(struct mx6s_csi_dev *csi,
+ int width, int height)
+{
+ int imag_para = 0;
+ unsigned long cr3 = __raw_readl(csi->regbase + CSI_CSICR3);
+
+ imag_para = (width << 16) | height;
+ __raw_writel(imag_para, csi->regbase + CSI_CSIIMAG_PARA);
+
+ /* reflash the embeded DMA controller */
+ __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, csi->regbase + CSI_CSICR3);
+}
+
+static void csi_set_16bit_imagpara(struct mx6s_csi_dev *csi,
+ int width, int height)
+{
+ int imag_para = 0;
+ unsigned long cr3 = __raw_readl(csi->regbase + CSI_CSICR3);
+
+ imag_para = (width << 16) | (height * 2);
+ __raw_writel(imag_para, csi->regbase + CSI_CSIIMAG_PARA);
+
+ /* reflash the embeded DMA controller */
+ __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, csi->regbase + CSI_CSICR3);
+}
+
+/*
+ * Videobuf operations
+ */
+static int mx6s_videobuf_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *count, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq);
+
+ dev_dbg(csi_dev->dev, "count=%d, size=%d\n", *count, sizes[0]);
+
+ /* TODO: support for VIDIOC_CREATE_BUFS not ready */
+ if (fmt != NULL)
+ return -ENOTTY;
+
+ alloc_ctxs[0] = csi_dev->alloc_ctx;
+
+ sizes[0] = csi_dev->pix.sizeimage;
+
+ pr_debug("size=%d\n", sizes[0]);
+ if (0 == *count)
+ *count = 32;
+ if (!*num_planes &&
+ sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
+ *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
+
+ *num_planes = 1;
+
+ return 0;
+}
+
+static int mx6s_videobuf_prepare(struct vb2_buffer *vb)
+{
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue);
+ int ret = 0;
+
+ dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+#ifdef DEBUG
+ /*
+ * This can be useful if you want to see if we actually fill
+ * the buffer with something
+ */
+ memset((void *)vb2_plane_vaddr(vb, 0),
+ 0xaa, vb2_get_plane_payload(vb, 0));
+#endif
+
+ vb2_set_plane_payload(vb, 0, csi_dev->pix.sizeimage);
+ if (vb2_plane_vaddr(vb, 0) &&
+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static void mx6s_videobuf_queue(struct vb2_buffer *vb)
+{
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct mx6s_buffer *buf = container_of(vb, struct mx6s_buffer, vb);
+ unsigned long flags;
+
+ dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+ spin_lock_irqsave(&csi_dev->slock, flags);
+
+ list_add_tail(&buf->internal.queue, &csi_dev->capture);
+
+ spin_unlock_irqrestore(&csi_dev->slock, flags);
+}
+
+static void mx6s_update_csi_buf(struct mx6s_csi_dev *csi_dev,
+ unsigned long phys, int bufnum)
+{
+ if (bufnum == 1)
+ csi_write(csi_dev, phys, CSI_CSIDMASA_FB2);
+ else
+ csi_write(csi_dev, phys, CSI_CSIDMASA_FB1);
+}
+
+static void mx6s_csi_init(struct mx6s_csi_dev *csi_dev)
+{
+ csi_clk_enable(csi_dev);
+ csihw_reset(csi_dev);
+ csi_init_interface(csi_dev);
+ csi_dmareq_rff_disable(csi_dev);
+}
+
+static void mx6s_csi_deinit(struct mx6s_csi_dev *csi_dev)
+{
+ csihw_reset(csi_dev);
+ csi_init_interface(csi_dev);
+ csi_dmareq_rff_disable(csi_dev);
+ csi_clk_disable(csi_dev);
+}
+
+static void mx6s_csi_enable(struct mx6s_csi_dev *csi_dev)
+{
+ struct v4l2_pix_format *pix = &csi_dev->pix;
+
+ csisw_reset(csi_dev);
+
+ if (pix->field == V4L2_FIELD_INTERLACED)
+ csi_tvdec_enable(csi_dev, true);
+
+ csi_dmareq_rff_enable(csi_dev);
+ csi_enable_int(csi_dev, 1);
+ csi_enable(csi_dev, 1);
+
+}
+
+static void mx6s_csi_disable(struct mx6s_csi_dev *csi_dev)
+{
+ struct v4l2_pix_format *pix = &csi_dev->pix;
+
+ csi_dmareq_rff_disable(csi_dev);
+ csi_disable_int(csi_dev);
+
+ /* set CSI_CSIDMASA_FB1 and CSI_CSIDMASA_FB2 to default value */
+ csi_write(csi_dev, 0, CSI_CSIDMASA_FB1);
+ csi_write(csi_dev, 0, CSI_CSIDMASA_FB2);
+
+ csi_buf_stride_set(csi_dev, 0);
+
+ if (pix->field == V4L2_FIELD_INTERLACED) {
+ csi_deinterlace_enable(csi_dev, false);
+ csi_tvdec_enable(csi_dev, false);
+ }
+
+ csi_enable(csi_dev, 0);
+}
+
+static int mx6s_configure_csi(struct mx6s_csi_dev *csi_dev)
+{
+ struct v4l2_pix_format *pix = &csi_dev->pix;
+
+ if (pix->field == V4L2_FIELD_INTERLACED) {
+ csi_deinterlace_enable(csi_dev, true);
+ csi_buf_stride_set(csi_dev, csi_dev->pix.width);
+ csi_deinterlace_mode(csi_dev, csi_dev->std);
+ } else {
+ csi_deinterlace_enable(csi_dev, false);
+ csi_buf_stride_set(csi_dev, 0);
+ }
+
+ switch (csi_dev->fmt->pixelformat) {
+ case V4L2_PIX_FMT_YUV444:
+ csi_set_32bit_imagpara(csi_dev, pix->width, pix->height);
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ csi_set_16bit_imagpara(csi_dev, pix->width, pix->height);
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ csi_set_16bit_imagpara(csi_dev, pix->width, pix->height);
+ break;
+ default:
+ pr_debug(" case not supported\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mx6s_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq);
+ struct vb2_buffer *vb;
+ struct mx6s_buffer *buf;
+ unsigned long phys;
+ unsigned long flags;
+
+ if (count < 2)
+ return -ENOBUFS;
+
+ /*
+ * I didn't manage to properly enable/disable
+ * a per frame basis during running transfers,
+ * thus we allocate a buffer here and use it to
+ * discard frames when no buffer is available.
+ * Feel free to work on this ;)
+ */
+ csi_dev->discard_size = csi_dev->pix.sizeimage;
+ csi_dev->discard_buffer = dma_alloc_coherent(csi_dev->v4l2_dev.dev,
+ PAGE_ALIGN(csi_dev->discard_size),
+ &csi_dev->discard_buffer_dma,
+ GFP_DMA | GFP_KERNEL);
+ if (!csi_dev->discard_buffer)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&csi_dev->slock, flags);
+
+ csi_dev->buf_discard[0].discard = true;
+ list_add_tail(&csi_dev->buf_discard[0].queue,
+ &csi_dev->discard);
+
+ csi_dev->buf_discard[1].discard = true;
+ list_add_tail(&csi_dev->buf_discard[1].queue,
+ &csi_dev->discard);
+
+ /* csi buf 0 */
+ buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer,
+ internal.queue);
+ buf->internal.bufnum = 0;
+ vb = &buf->vb;
+
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+ mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum);
+ list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs);
+
+ /* csi buf 1 */
+ buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer,
+ internal.queue);
+ buf->internal.bufnum = 1;
+ vb = &buf->vb;
+
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum);
+ list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs);
+
+ spin_unlock_irqrestore(&csi_dev->slock, flags);
+
+ return 0;
+}
+
+static int mx6s_stop_streaming(struct vb2_queue *vq)
+{
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq);
+ unsigned long flags;
+ struct mx6s_buffer *buf, *tmp;
+ void *b;
+
+ spin_lock_irqsave(&csi_dev->slock, flags);
+
+
+ list_for_each_entry_safe(buf, tmp,
+ &csi_dev->active_bufs, internal.queue) {
+ list_del_init(&buf->internal.queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+
+ INIT_LIST_HEAD(&csi_dev->capture);
+ INIT_LIST_HEAD(&csi_dev->active_bufs);
+ INIT_LIST_HEAD(&csi_dev->discard);
+
+ b = csi_dev->discard_buffer;
+ csi_dev->discard_buffer = NULL;
+
+ spin_unlock_irqrestore(&csi_dev->slock, flags);
+
+ dma_free_coherent(csi_dev->v4l2_dev.dev,
+ csi_dev->discard_size, b,
+ csi_dev->discard_buffer_dma);
+
+ return 0;
+}
+
+static struct vb2_ops mx6s_videobuf_ops = {
+ .queue_setup = mx6s_videobuf_setup,
+ .buf_prepare = mx6s_videobuf_prepare,
+ .buf_queue = mx6s_videobuf_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = mx6s_start_streaming,
+ .stop_streaming = mx6s_stop_streaming,
+};
+
+static void mx6s_csi_frame_done(struct mx6s_csi_dev *csi_dev,
+ int bufnum, bool err)
+{
+ struct mx6s_buf_internal *ibuf;
+ struct mx6s_buffer *buf;
+ struct vb2_buffer *vb;
+ unsigned long phys;
+
+ ibuf = list_first_entry(&csi_dev->active_bufs, struct mx6s_buf_internal,
+ queue);
+
+ if (ibuf->discard) {
+ /*
+ * Discard buffer must not be returned to user space.
+ * Just return it to the discard queue.
+ */
+ list_move_tail(csi_dev->active_bufs.next, &csi_dev->discard);
+ } else {
+ buf = mx6s_ibuf_to_buf(ibuf);
+
+ vb = &buf->vb;
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ if (bufnum == 1) {
+ if (csi_read(csi_dev, CSI_CSIDMASA_FB2) != phys) {
+ dev_err(csi_dev->dev, "%lx != %x\n", phys,
+ csi_read(csi_dev, CSI_CSIDMASA_FB2));
+ }
+ } else {
+ if (csi_read(csi_dev, CSI_CSIDMASA_FB1) != phys) {
+ dev_err(csi_dev->dev, "%lx != %x\n", phys,
+ csi_read(csi_dev, CSI_CSIDMASA_FB1));
+ }
+ }
+ dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb,
+ vb2_plane_vaddr(vb, 0),
+ vb2_get_plane_payload(vb, 0));
+
+ list_del_init(&buf->internal.queue);
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
+ vb->v4l2_buf.sequence = csi_dev->frame_count;
+ if (err)
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ else
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ }
+
+ csi_dev->frame_count++;
+
+ /* Config discard buffer to active_bufs */
+ if (list_empty(&csi_dev->capture)) {
+ if (list_empty(&csi_dev->discard)) {
+ dev_warn(csi_dev->dev,
+ "%s: trying to access empty discard list\n",
+ __func__);
+ return;
+ }
+
+ ibuf = list_first_entry(&csi_dev->discard,
+ struct mx6s_buf_internal, queue);
+ ibuf->bufnum = bufnum;
+
+ list_move_tail(csi_dev->discard.next, &csi_dev->active_bufs);
+
+ mx6s_update_csi_buf(csi_dev,
+ csi_dev->discard_buffer_dma, bufnum);
+ return;
+ }
+
+ buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer,
+ internal.queue);
+
+ buf->internal.bufnum = bufnum;
+
+ list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs);
+
+ vb = &buf->vb;
+
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ mx6s_update_csi_buf(csi_dev, phys, bufnum);
+}
+
+static irqreturn_t mx6s_csi_irq_handler(int irq, void *data)
+{
+ struct mx6s_csi_dev *csi_dev = data;
+ unsigned long status;
+ u32 cr1, cr3, cr18;
+
+ spin_lock(&csi_dev->slock);
+
+ status = csi_read(csi_dev, CSI_CSISR);
+ csi_write(csi_dev, status, CSI_CSISR);
+
+ if (list_empty(&csi_dev->active_bufs)) {
+ dev_warn(csi_dev->dev,
+ "%s: called while active list is empty\n",
+ __func__);
+
+ spin_unlock(&csi_dev->slock);
+ return IRQ_HANDLED;
+ }
+
+ if (status & BIT_HRESP_ERR_INT) {
+ /* software reset */
+
+ /* Disable csi */
+ cr18 = csi_read(csi_dev, CSI_CSICR18);
+ cr18 &= ~BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+
+ /* Clear RX FIFO */
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1);
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1);
+
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1);
+
+ /* DMA reflash */
+ cr3 = csi_read(csi_dev, CSI_CSICR3);
+ cr3 |= BIT_DMA_REFLASH_RFF;
+ csi_write(csi_dev, cr3, CSI_CSICR3);
+
+ /* Ensable csi */
+ cr18 |= BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+
+ pr_warning("Hresponse error is detected.\n");
+ }
+
+ if (status & BIT_ADDR_CH_ERR_INT) {
+ /* Disable csi */
+ cr18 = csi_read(csi_dev, CSI_CSICR18);
+ cr18 &= ~BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+
+ /* DMA reflash */
+ cr3 = csi_read(csi_dev, CSI_CSICR3);
+ cr3 |= BIT_DMA_REFLASH_RFF;
+ csi_write(csi_dev, cr3, CSI_CSICR3);
+
+ /* Ensable csi */
+ cr18 |= BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+
+ pr_debug("base address switching Change Err.\n");
+ }
+
+ if ((status & BIT_DMA_TSF_DONE_FB1) &&
+ (status & BIT_DMA_TSF_DONE_FB2)) {
+ /* For both FB1 and FB2 interrupter bits set case,
+ * CSI DMA is work in one of FB1 and FB2 buffer,
+ * but software can not know the state.
+ * Skip it to avoid base address updated
+ * when csi work in field0 and field1 will write to
+ * new base address.
+ * PDM TKT230775 */
+ pr_debug("Skip two frames\n");
+ } else if (status & BIT_DMA_TSF_DONE_FB1) {
+ mx6s_csi_frame_done(csi_dev, 0, false);
+ } else if (status & BIT_DMA_TSF_DONE_FB2) {
+ mx6s_csi_frame_done(csi_dev, 1, false);
+ }
+
+ spin_unlock(&csi_dev->slock);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * File operations for the device
+ */
+static int mx6s_csi_open(struct file *file)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct vb2_queue *q = &csi_dev->vb2_vidq;
+ int ret = 0;
+
+ file->private_data = csi_dev;
+
+ if (mutex_lock_interruptible(&csi_dev->lock))
+ return -ERESTARTSYS;
+
+ csi_dev->alloc_ctx = vb2_dma_contig_init_ctx(csi_dev->dev);
+ if (IS_ERR(csi_dev->alloc_ctx))
+ goto unlock;
+
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->drv_priv = csi_dev;
+ q->ops = &mx6s_videobuf_ops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct mx6s_buffer);
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &csi_dev->lock;
+
+ ret = vb2_queue_init(q);
+ if (ret < 0)
+ goto eallocctx;
+
+ mx6s_csi_init(csi_dev);
+
+ mutex_unlock(&csi_dev->lock);
+
+ return ret;
+eallocctx:
+ vb2_dma_contig_cleanup_ctx(csi_dev->alloc_ctx);
+unlock:
+ mutex_unlock(&csi_dev->lock);
+ return ret;
+}
+
+static int mx6s_csi_close(struct file *file)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ mutex_lock(&csi_dev->lock);
+
+ vb2_queue_release(&csi_dev->vb2_vidq);
+
+ mx6s_csi_deinit(csi_dev);
+
+ vb2_dma_contig_cleanup_ctx(csi_dev->alloc_ctx);
+ mutex_unlock(&csi_dev->lock);
+
+ file->private_data = NULL;
+ return 0;
+}
+
+static ssize_t mx6s_csi_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ int ret;
+
+ dev_dbg(csi_dev->dev, "read called, buf %p\n", buf);
+
+ mutex_lock(&csi_dev->lock);
+ ret = vb2_read(&csi_dev->vb2_vidq, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ mutex_unlock(&csi_dev->lock);
+ return ret;
+}
+
+static int mx6s_csi_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ int ret;
+
+ if (mutex_lock_interruptible(&csi_dev->lock))
+ return -ERESTARTSYS;
+ ret = vb2_mmap(&csi_dev->vb2_vidq, vma);
+ mutex_unlock(&csi_dev->lock);
+
+ pr_debug("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ ret);
+
+ return ret;
+}
+
+static struct v4l2_file_operations mx6s_csi_fops = {
+ .owner = THIS_MODULE,
+ .open = mx6s_csi_open,
+ .release = mx6s_csi_close,
+ .read = mx6s_csi_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = mx6s_csi_mmap,
+};
+
+/*
+ * Video node IOCTLs
+ */
+static int mx6s_vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
+
+ /* default is camera */
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(inp->name, "Camera");
+
+ return 0;
+}
+
+static int mx6s_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int mx6s_vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int mx6s_vidioc_querystd(struct file *file, void *priv, v4l2_std_id *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ v4l2_subdev_call(sd, video, querystd, a);
+ return 0;
+}
+
+static int mx6s_vidioc_s_std(struct file *file, void *priv, v4l2_std_id a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ v4l2_subdev_call(sd, core, s_std, a);
+
+ return 0;
+}
+
+static int mx6s_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ v4l2_subdev_call(sd, core, g_std, a);
+
+ return 0;
+}
+
+static int mx6s_vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ return vb2_reqbufs(&csi_dev->vb2_vidq, p);
+}
+
+static int mx6s_vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ return vb2_querybuf(&csi_dev->vb2_vidq, p);
+}
+
+static int mx6s_vidioc_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ return vb2_qbuf(&csi_dev->vb2_vidq, p);
+}
+
+static int mx6s_vidioc_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ return vb2_dqbuf(&csi_dev->vb2_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mx6s_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ int index = f->index;
+
+ WARN_ON(priv != file->private_data);
+
+ if (f->index > NUM_FORMATS)
+ return -EINVAL;
+
+ strlcpy(f->description, formats[index].name, sizeof(f->description));
+ f->pixelformat = formats[index].fourcc;
+ return 0;
+
+}
+
+static int mx6s_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct mx6s_fmt *fmt;
+ int ret;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ dev_err(csi_dev->dev, "Fourcc format (0x%08x) invalid.",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ v4l2_fill_mbus_format(&mbus_fmt, pix, fmt->mbus_code);
+ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(pix, &mbus_fmt);
+
+ if (pix->field != V4L2_FIELD_INTERLACED)
+ pix->field = V4L2_FIELD_NONE;
+
+ pix->sizeimage = fmt->bpp * pix->height * pix->width;
+ pix->bytesperline = fmt->bpp * pix->width;
+
+ return ret;
+}
+
+/*
+ * The real work of figuring out a workable format.
+ */
+
+static int mx6s_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ int ret;
+
+ ret = mx6s_vidioc_try_fmt_vid_cap(file, csi_dev, f);
+ if (ret < 0)
+ return ret;
+
+ csi_dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ csi_dev->pix.width = f->fmt.pix.width;
+ csi_dev->pix.height = f->fmt.pix.height;
+ csi_dev->pix.sizeimage = f->fmt.pix.sizeimage;
+ csi_dev->pix.field = f->fmt.pix.field;
+ csi_dev->type = f->type;
+ dev_dbg(csi_dev->dev, "set to pixelformat '%4.6s'\n",
+ (char *)&csi_dev->fmt->name);
+
+ /* Config csi */
+ mx6s_configure_csi(csi_dev);
+
+ return 0;
+}
+
+static int mx6s_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ f->fmt.pix = csi_dev->pix;
+
+ return 0;
+}
+
+static int mx6s_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ /* cap->name is set by the friendly caller:-> */
+ strlcpy(cap->driver, MX6S_CAM_DRIVER_DESCRIPTION, sizeof(cap->driver));
+ strlcpy(cap->card, MX6S_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ dev_name(csi_dev->dev));
+
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+static int mx6s_vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+ int ret;
+
+ WARN_ON(priv != file->private_data);
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ ret = vb2_streamon(&csi_dev->vb2_vidq, i);
+
+ mx6s_csi_enable(csi_dev);
+
+ if (!ret)
+ v4l2_subdev_call(sd, video, s_stream, 1);
+
+ return ret;
+}
+
+static int mx6s_vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ WARN_ON(priv != file->private_data);
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /*
+ * This calls buf_release from host driver's videobuf_queue_ops for all
+ * remaining buffers. When the last buffer is freed, stop capture
+ */
+ vb2_streamoff(&csi_dev->vb2_vidq, i);
+
+ v4l2_subdev_call(sd, video, s_stream, 0);
+
+ mx6s_csi_disable(csi_dev);
+
+ return 0;
+}
+
+static int mx6s_vidioc_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ dev_dbg(csi_dev->dev, "VIDIOC_CROPCAP not implemented\n");
+
+ return 0;
+}
+
+static int mx6s_vidioc_g_crop(struct file *file, void *priv,
+ struct v4l2_crop *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ dev_dbg(csi_dev->dev, "VIDIOC_G_CROP not implemented\n");
+
+ return 0;
+}
+
+static int mx6s_vidioc_s_crop(struct file *file, void *priv,
+ const struct v4l2_crop *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ dev_dbg(csi_dev->dev, "VIDIOC_S_CROP not implemented\n");
+
+ return 0;
+}
+
+static int mx6s_vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ v4l2_subdev_call(sd, video, g_parm, a);
+ return 0;
+}
+
+static int mx6s_vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ v4l2_subdev_call(sd, video, s_parm, a);
+
+ return 0;
+}
+
+static int mx6s_vidioc_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ v4l2_subdev_call(sd, video, enum_framesizes, fsize);
+ return 0;
+}
+
+static int mx6s_vidioc_enum_frameintervals(struct file *file, void *priv,
+ struct v4l2_frmivalenum *interval)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ v4l2_subdev_call(sd, video, enum_frameintervals, interval);
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops mx6s_csi_ioctl_ops = {
+ .vidioc_querycap = mx6s_vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = mx6s_vidioc_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = mx6s_vidioc_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = mx6s_vidioc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = mx6s_vidioc_s_fmt_vid_cap,
+ .vidioc_cropcap = mx6s_vidioc_cropcap,
+ .vidioc_s_crop = mx6s_vidioc_s_crop,
+ .vidioc_g_crop = mx6s_vidioc_g_crop,
+ .vidioc_reqbufs = mx6s_vidioc_reqbufs,
+ .vidioc_querybuf = mx6s_vidioc_querybuf,
+ .vidioc_qbuf = mx6s_vidioc_qbuf,
+ .vidioc_dqbuf = mx6s_vidioc_dqbuf,
+ .vidioc_g_std = mx6s_vidioc_g_std,
+ .vidioc_s_std = mx6s_vidioc_s_std,
+ .vidioc_querystd = mx6s_vidioc_querystd,
+ .vidioc_enum_input = mx6s_vidioc_enum_input,
+ .vidioc_g_input = mx6s_vidioc_g_input,
+ .vidioc_s_input = mx6s_vidioc_s_input,
+ .vidioc_streamon = mx6s_vidioc_streamon,
+ .vidioc_streamoff = mx6s_vidioc_streamoff,
+ .vidioc_g_parm = mx6s_vidioc_g_parm,
+ .vidioc_s_parm = mx6s_vidioc_s_parm,
+ .vidioc_enum_framesizes = mx6s_vidioc_enum_framesizes,
+ .vidioc_enum_frameintervals = mx6s_vidioc_enum_frameintervals,
+};
+
+static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct mx6s_csi_dev *csi_dev = notifier_to_mx6s_dev(notifier);
+
+ /* Find platform data for this sensor subdev */
+ if (csi_dev->asd.match.of.node == subdev->dev->of_node)
+ csi_dev->sd = subdev;
+
+ if (subdev == NULL)
+ return -EINVAL;
+
+ v4l2_info(&csi_dev->v4l2_dev, "Registered sensor subdevice: %s\n",
+ subdev->name);
+
+ return 0;
+}
+
+static int mx6sx_register_subdevs(struct mx6s_csi_dev *csi_dev)
+{
+ struct device_node *parent = csi_dev->dev->of_node;
+ struct device_node *node, *port, *rem;
+ int ret;
+
+ /* Attach sensors linked to csi receivers */
+ for_each_available_child_of_node(parent, node) {
+ if (of_node_cmp(node->name, "port"))
+ continue;
+
+ /* The csi node can have only port subnode. */
+ port = of_get_next_child(node, NULL);
+ if (!port)
+ continue;
+ rem = v4l2_of_get_remote_port_parent(port);
+ of_node_put(port);
+ if (rem == NULL) {
+ v4l2_info(&csi_dev->v4l2_dev,
+ "Remote device at %s not found\n",
+ port->full_name);
+ return -1;
+ }
+
+ csi_dev->asd.match_type = V4L2_ASYNC_MATCH_OF;
+ csi_dev->asd.match.of.node = rem;
+ csi_dev->async_subdevs[0] = &csi_dev->asd;
+
+ of_node_put(rem);
+ break;
+ }
+
+ csi_dev->subdev_notifier.subdevs = csi_dev->async_subdevs;
+ csi_dev->subdev_notifier.num_subdevs = 1;
+ csi_dev->subdev_notifier.bound = subdev_notifier_bound;
+
+ ret = v4l2_async_notifier_register(&csi_dev->v4l2_dev,
+ &csi_dev->subdev_notifier);
+ if (ret)
+ dev_err(csi_dev->dev,
+ "Error register async notifier regoster\n");
+
+ return ret;
+}
+
+static int mx6s_csi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mx6s_csi_dev *csi_dev;
+ struct video_device *vdev;
+ struct resource *res;
+ int ret = 0;
+
+ dev_dbg(dev, "initialising\n");
+
+ /* Prepare our private structure */
+ csi_dev = devm_kzalloc(dev, sizeof(struct mx6s_csi_dev), GFP_ATOMIC);
+ if (!csi_dev) {
+ dev_err(dev, "Can't allocate private structure\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ csi_dev->irq = platform_get_irq(pdev, 0);
+ if (res == NULL || csi_dev->irq < 0) {
+ dev_err(dev, "Missing platform resources data\n");
+ return -ENODEV;
+ }
+
+ csi_dev->regbase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(csi_dev->regbase)) {
+ dev_err(dev, "Failed platform resources map\n");
+ return -ENODEV;
+ }
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&csi_dev->capture);
+ INIT_LIST_HEAD(&csi_dev->active_bufs);
+ INIT_LIST_HEAD(&csi_dev->discard);
+
+ csi_dev->clk_disp_axi = devm_clk_get(dev, "disp-axi");
+ if (IS_ERR(csi_dev->clk_disp_axi)) {
+ dev_err(dev, "Could not get csi axi clock\n");
+ return -ENODEV;
+ }
+
+ csi_dev->clk_disp_dcic = devm_clk_get(dev, "disp_dcic");
+ if (IS_ERR(csi_dev->clk_disp_dcic)) {
+ dev_err(dev, "Could not get disp dcic clock\n");
+ return -ENODEV;
+ }
+
+ csi_dev->clk_csi_mclk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(csi_dev->clk_csi_mclk)) {
+ dev_err(dev, "Could not get csi mclk clock\n");
+ return -ENODEV;
+ }
+
+ csi_dev->dev = dev;
+
+ snprintf(csi_dev->v4l2_dev.name,
+ sizeof(csi_dev->v4l2_dev.name), "CSI");
+
+ ret = v4l2_device_register(dev, &csi_dev->v4l2_dev);
+ if (ret < 0) {
+ dev_err(dev, "v4l2_device_register() failed: %d\n", ret);
+ return -ENODEV;
+ }
+
+ /* initialize locks */
+ mutex_init(&csi_dev->lock);
+ spin_lock_init(&csi_dev->slock);
+
+ /* Allocate memory for video device */
+ vdev = video_device_alloc();
+ if (vdev == NULL) {
+ ret = -ENOMEM;
+ goto err_vdev;
+ }
+
+ snprintf(vdev->name, sizeof(vdev->name), "mx6s-csi");
+
+ vdev->v4l2_dev = &csi_dev->v4l2_dev;
+ vdev->fops = &mx6s_csi_fops;
+ vdev->ioctl_ops = &mx6s_csi_ioctl_ops;
+ vdev->release = video_device_release;
+ vdev->lock = &csi_dev->lock;
+
+ vdev->queue = &csi_dev->vb2_vidq;
+
+ csi_dev->vdev = vdev;
+
+ video_set_drvdata(csi_dev->vdev, csi_dev);
+ mutex_lock(&csi_dev->lock);
+
+ ret = video_register_device(csi_dev->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ video_device_release(csi_dev->vdev);
+ mutex_unlock(&csi_dev->lock);
+ goto err_vdev;
+ }
+
+ /* install interrupt handler */
+ if (devm_request_irq(dev, csi_dev->irq, mx6s_csi_irq_handler,
+ 0, "csi", (void *)csi_dev)) {
+ mutex_unlock(&csi_dev->lock);
+ dev_err(dev, "Request CSI IRQ failed.\n");
+ ret = -ENODEV;
+ goto err_irq;
+ }
+
+ mutex_unlock(&csi_dev->lock);
+
+ ret = mx6sx_register_subdevs(csi_dev);
+ if (ret < 0)
+ goto err_irq;
+
+ return 0;
+
+err_irq:
+ video_unregister_device(csi_dev->vdev);
+err_vdev:
+ v4l2_device_unregister(&csi_dev->v4l2_dev);
+ return ret;
+}
+
+static int mx6s_csi_remove(struct platform_device *pdev)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+ struct mx6s_csi_dev *csi_dev =
+ container_of(v4l2_dev, struct mx6s_csi_dev, v4l2_dev);
+
+ v4l2_async_notifier_unregister(&csi_dev->subdev_notifier);
+
+ video_unregister_device(csi_dev->vdev);
+ v4l2_device_unregister(&csi_dev->v4l2_dev);
+ return 0;
+}
+
+static const struct of_device_id mx6s_csi_dt_ids[] = {
+ { .compatible = "fsl,imx6s-csi", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mx6s_csi_dt_ids);
+
+static struct platform_driver mx6s_csi_driver = {
+ .driver = {
+ .name = MX6S_CAM_DRV_NAME,
+ .of_match_table = of_match_ptr(mx6s_csi_dt_ids),
+ },
+ .probe = mx6s_csi_probe,
+ .remove = mx6s_csi_remove,
+};
+
+module_platform_driver(mx6s_csi_driver);
+
+MODULE_DESCRIPTION("i.MX6Sx SoC Camera Host driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MX6S_CAM_VERSION);
diff --git a/drivers/media/platform/mxc/subdev/mxc_vadc.c b/drivers/media/platform/mxc/subdev/mxc_vadc.c
new file mode 100644
index 000000000000..666be710c2c4
--- /dev/null
+++ b/drivers/media/platform/mxc/subdev/mxc_vadc.c
@@ -0,0 +1,752 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include "mxc_vadc.h"
+
+/* Resource names for the VADC driver. */
+#define VAFE_REGS_ADDR_RES_NAME "vadc-vafe"
+#define VDEC_REGS_ADDR_RES_NAME "vadc-vdec"
+
+#define reg32_write(addr, val) __raw_writel(val, addr)
+#define reg32_read(addr) __raw_readl(addr)
+#define reg32setbit(addr, bitpos) \
+ reg32_write((addr), (reg32_read((addr)) | (1<<(bitpos))))
+
+#define reg32clrbit(addr, bitpos) \
+ reg32_write((addr), (reg32_read((addr)) & (0xFFFFFFFF ^ (1<<(bitpos)))))
+
+#define GPC_CNTR 0x00
+#define IMX6SX_GPC_CNTR_VADC_ANALOG_OFF_MASK BIT(17)
+#define IMX6SX_GPC_CNTR_VADC_POWER_DOWN_MASK BIT(18)
+
+void __iomem *vafe_regbase;
+void __iomem *vdec_regbase;
+
+
+/* List of input video formats supported. The video formats is corresponding
+ * with v4l2 id in video_fmt
+ */
+enum video_fmt_idx {
+ VADC_NTSC = 0, /* Locked on (M) NTSC video signal. */
+ VADC_PAL, /* (B, G, H, I, N)PAL video signal. */
+};
+
+/* Number of video standards supported (including 'not locked' signal). */
+#define VADC_STD_MAX (VADC_PAL + 1)
+
+/* Video format structure. */
+struct video_fmt{
+ v4l2_std_id v4l2_std; /* 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 framerates;
+};
+
+/*
+ * Maintains the information on the current state of the sensor.
+ */
+struct vadc_state {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev sd;
+ struct video_fmt *fmt;
+
+ struct clk *vadc_clk;
+ struct clk *csi_clk;
+ struct regmap *gpr;
+ void __iomem *gpc_reg;
+
+ u32 vadc_in;
+ u32 csi_id;
+};
+
+static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std);
+
+/* Description of video formats supported.
+ *
+ * PAL: raw=720x625, active=720x576.
+ * NTSC: raw=720x525, active=720x480.
+ */
+static struct video_fmt video_fmts[] = {
+ /* NTSC */
+ {
+ .v4l2_std = V4L2_STD_NTSC,
+ .name = "NTSC",
+ .raw_width = 720,
+ .raw_height = 525,
+ .active_width = 720,
+ .active_height = 480,
+ .framerates = 30,
+ },
+ /* (B, G, H, I, N) PAL */
+ {
+ .v4l2_std = V4L2_STD_PAL,
+ .name = "PAL",
+ .raw_width = 720,
+ .raw_height = 625,
+ .active_width = 720,
+ .active_height = 576,
+ .framerates = 25,
+ },
+};
+
+static void afe_voltage_clampingmode(void)
+{
+ reg32_write(AFE_CLAMP, 0x07);
+ reg32_write(AFE_CLMPAMP, 0x60);
+ reg32_write(AFE_CLMPDAT, 0xF0);
+}
+
+static void afe_alwayson_clampingmode(void)
+{
+ reg32_write(AFE_CLAMP, 0x15);
+ reg32_write(AFE_CLMPDAT, 0x08);
+ reg32_write(AFE_CLMPAMP, 0x00);
+}
+
+static void afe_init(void)
+{
+ pr_debug("%s\n", __func__);
+
+ reg32_write(AFE_PDBUF, 0x1f);
+ reg32_write(AFE_PDADC, 0x0f);
+ reg32_write(AFE_PDSARH, 0x01);
+ reg32_write(AFE_PDSARL, 0xff);
+ reg32_write(AFE_PDADCRFH, 0x01);
+ reg32_write(AFE_PDADCRFL, 0xff);
+ reg32_write(AFE_ICTRL, 0x3a);
+ reg32_write(AFE_ICTLSTG, 0x1e);
+
+ reg32_write(AFE_RCTRLSTG, 0x1e);
+ reg32_write(AFE_INPBUF, 0x035);
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_ADCDGN, 0x40);
+ reg32_write(AFE_TSTSEL, 0x10);
+
+ reg32_write(AFE_ACCTST, 0x07);
+
+ reg32_write(AFE_BGREG, 0x08);
+
+ reg32_write(AFE_ADCGN, 0x09);
+
+ /* set current controlled clamping
+ * always on, low current */
+ reg32_write(AFE_CLAMP, 0x11);
+ reg32_write(AFE_CLMPAMP, 0x08);
+}
+
+static void vdec_mode_timing_init(int std)
+{
+ if (std == V4L2_STD_NTSC) {
+ /* NTSC 720x480 */
+ reg32_write(VDEC_HACTS, 0x66);
+ reg32_write(VDEC_HACTE, 0x24);
+
+ reg32_write(VDEC_VACTS, 0x29);
+ reg32_write(VDEC_VACTE, 0x04);
+
+ /* set V Position */
+ reg32_write(VDEC_VRTPOS, 0x2);
+ } else if (std == V4L2_STD_PAL) {
+ /* PAL 720x576 */
+ reg32_write(VDEC_HACTS, 0x66);
+ reg32_write(VDEC_HACTE, 0x24);
+
+ reg32_write(VDEC_VACTS, 0x29);
+ reg32_write(VDEC_VACTE, 0x04);
+
+ /* set V Position */
+ reg32_write(VDEC_VRTPOS, 0x6);
+ } else
+ pr_debug("Error not support video mode\n");
+
+ /* set H Position */
+ reg32_write(VDEC_HZPOS, 0x60);
+
+ /* set H ignore start */
+ reg32_write(VDEC_HSIGS, 0xf8);
+
+ /* set H ignore end */
+ reg32_write(VDEC_HSIGE, 0x18);
+}
+
+/*
+* vdec_init()
+* Initialises the VDEC registers
+* Returns: nothing
+*/
+static void vdec_init(struct vadc_state *vadc)
+{
+ v4l2_std_id std;
+
+ pr_debug("%s\n", __func__);
+
+ /* Get work mode PAL or NTSC */
+ vadc_querystd(&vadc->sd, &std);
+
+ vdec_mode_timing_init(std);
+
+ /* vcr detect threshold high, automatic detections */
+ reg32_write(VDEC_VSCON2, 0);
+
+ reg32_write(VDEC_BASE + 0x110, 0x01);
+
+ /* set the noramp mode on the Hloop PLL. */
+ reg32_write(VDEC_BASE+(0x14*4), 0x10);
+
+ /* set the YC relative delay.*/
+ reg32_write(VDEC_YCDEL, 0x90);
+
+ /* setup the Hpll */
+ reg32_write(VDEC_BASE+(0x13*4), 0x13);
+
+ /* setup the 2d comb */
+ /* set the gain of the Hdetail output to 3
+ * set the notch alpha gain to 1 */
+ reg32_write(VDEC_CFC2, 0x34);
+
+ /* setup various 2d comb bits.*/
+ reg32_write(VDEC_BASE+(0x02*4), 0x01);
+ reg32_write(VDEC_BASE+(0x03*4), 0x18);
+ reg32_write(VDEC_BASE+(0x04*4), 0x34);
+
+ /* set the start of the burst gate */
+ reg32_write(VDEC_BRSTGT, 0x30);
+
+ /* set 1f motion gain */
+ reg32_write(VDEC_BASE+(0x0f*4), 0x20);
+
+ /* set the 1F chroma motion detector thresh
+ * for colour reverse detection */
+ reg32_write(VDEC_THSH1, 0x02);
+ reg32_write(VDEC_BASE+(0x4a*4), 0x20);
+ reg32_write(VDEC_BASE+(0x4b*4), 0x08);
+
+ reg32_write(VDEC_BASE+(0x4c*4), 0x08);
+
+ /* set the threshold for the narrow/wide adaptive chroma BW */
+ reg32_write(VDEC_BASE+(0x20*4), 0x20);
+
+ /* turn up the colour with the new colour gain reg */
+ /* hue: */
+ reg32_write(VDEC_HUE, 0x00);
+
+ /* cbgain: 22 B4 */
+ reg32_write(VDEC_CBGN, 0xb4);
+ /* cr gain 80 */
+ reg32_write(VDEC_CRGN, 0x80);
+ /* luma gain (contrast) */
+ reg32_write(VDEC_CNTR, 0x80);
+
+ /* setup the signed black level register, brightness */
+ reg32_write(VDEC_BRT, 0x00);
+
+ /* filter the standard detection
+ * enable the comb for the ntsc443 */
+ reg32_write(VDEC_STDDBG, 0x20);
+
+ /* setup chroma kill thresh for no chroma */
+ reg32_write(VDEC_CHBTH, 0x0);
+
+ /* set chroma loop to wider BW
+ * no set it to normal BW. i fixed the bw problem.*/
+ reg32_write(VDEC_YCDEL, 0x00);
+
+ /* set the compensation in the chroma loop for the Hloop
+ * set the ratio for the nonarithmetic 3d comb modes.*/
+ reg32_write(VDEC_BASE + (0x1d*4), 0x90);
+
+ /* set the threshold for the nonarithmetic mode for the 2d comb
+ * the higher the value the more Fc Fh offset
+ * we will tolerate before turning off the comb. */
+ reg32_write(VDEC_BASE + (0x33*4), 0xa0);
+
+ /* setup the bluescreen output colour */
+ reg32_write(VDEC_BASE + (0x3d*4), 35);
+ reg32_write(VDEC_BLSCRCR, 114);
+ reg32_write(VDEC_BLSCRCB, 212);
+
+ /* disable the active blanking */
+ reg32_write(VDEC_BASE + (0x15*4), 0x02);
+
+ /* setup the luma agc for automatic gain. */
+ reg32_write(VDEC_LMAGC2, 0x5e);
+ reg32_write(VDEC_LMAGC1, 0x81);
+
+ /* setup chroma agc */
+ reg32_write(VDEC_CHAGC2, 0xa0);
+ reg32_write(VDEC_CHAGC1, 0x01);
+
+ /* setup the MV thresh lower nibble
+ * setup the sync top cap, upper nibble */
+ reg32_write(VDEC_BASE + (0x3a*4), 0x80);
+ reg32_write(VDEC_SHPIMP, 0x00);
+
+ /* setup the vsync block */
+ reg32_write(VDEC_VSCON1, 0x87);
+
+ /* set the nosignal threshold
+ * set the vsync threshold */
+ reg32_write(VDEC_VSSGTH, 0x35);
+
+ /* set length for min hphase filter
+ * (or saturate limit if saturate is chosen) */
+ reg32_write(VDEC_BASE + (0x45*4), 0x40);
+
+ /* enable the internal resampler,
+ * select min filter not saturate for
+ * hphase noise filter for vcr detect.
+ * enable vcr pause mode different field lengths */
+ reg32_write(VDEC_BASE + (0x46*4), 0x90);
+
+ /* disable VCR detection, lock to the Hsync rather than the Vsync */
+ reg32_write(VDEC_VSCON2, 0x04);
+
+ /* set tiplevel goal for dc clamp. */
+ reg32_write(VDEC_BASE + (0x3c*4), 0xB0);
+
+ /* override SECAM detection and force SECAM off */
+ reg32_write(VDEC_BASE + (0x2f*4), 0x20);
+
+ /* Set r3d_hardblend in 3D control2 reg */
+ reg32_write(VDEC_BASE + (0x0c*4), 0x04);
+}
+
+/* set Input selector & input pull-downs */
+static void vadc_s_routing(int vadc_in)
+{
+ switch (vadc_in) {
+ case 0:
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_OFFDRV, 0x00);
+ reg32_write(AFE_INPCONFIG, 0x1e);
+ break;
+ case 1:
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_OFFDRV, 0x00);
+ reg32_write(AFE_INPCONFIG, 0x2d);
+ break;
+ case 2:
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_OFFDRV, 0x00);
+ reg32_write(AFE_INPCONFIG, 0x4b);
+ break;
+ case 3:
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_OFFDRV, 0x00);
+ reg32_write(AFE_INPCONFIG, 0x87);
+ break;
+ default:
+ pr_debug("error video input %d\n", vadc_in);
+ }
+}
+
+static void vadc_power_up(struct vadc_state *state)
+{
+ /* Power on vadc analog */
+ reg32clrbit(state->gpc_reg + GPC_CNTR, 17);
+
+ /* Power down vadc ext power */
+ reg32clrbit(state->gpc_reg + GPC_CNTR, 18);
+
+ /* software reset afe */
+ regmap_update_bits(state->gpr, IOMUXC_GPR1,
+ IMX6SX_GPR1_VADC_SW_RST_MASK,
+ IMX6SX_GPR1_VADC_SW_RST_RESET);
+
+ msleep(10);
+
+ /* clock config for vadc */
+ reg32_write(VDEC_BASE + 0x320, 0xe3);
+ reg32_write(VDEC_BASE + 0x324, 0x38);
+ reg32_write(VDEC_BASE + 0x328, 0x8e);
+ reg32_write(VDEC_BASE + 0x32c, 0x23);
+
+ /* Release reset bit */
+ regmap_update_bits(state->gpr, IOMUXC_GPR1,
+ IMX6SX_GPR1_VADC_SW_RST_MASK,
+ IMX6SX_GPR1_VADC_SW_RST_RELEASE);
+
+ /* Power on vadc ext power */
+ reg32setbit(state->gpc_reg + GPC_CNTR, 18);
+}
+
+static void vadc_power_down(struct vadc_state *state)
+{
+ /* Power down vadc analog */
+ reg32setbit(state->gpc_reg + GPC_CNTR, 17);
+
+ /* Power down vadc ext power */
+ reg32clrbit(state->gpc_reg + GPC_CNTR, 18);
+
+}
+static void vadc_init(struct vadc_state *vadc)
+{
+ pr_debug("%s\n", __func__);
+
+ vadc_power_up(vadc);
+
+ afe_init();
+
+ /* select Video Input 0-3 */
+ vadc_s_routing(vadc->vadc_in);
+
+ afe_voltage_clampingmode();
+
+ vdec_init(vadc);
+
+ /*
+ * current control loop will move sinewave input off below
+ * the bottom of the signal range visible
+ * when the testbus is viewed as magnitude,
+ * so have to break before this point while capturing ENOB data:
+ */
+ afe_alwayson_clampingmode();
+}
+
+static inline struct vadc_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct vadc_state, sd);
+}
+
+static int vadc_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct vadc_state *state = to_state(sd);
+
+ *std = state->fmt->v4l2_std;
+ return 0;
+}
+
+/*!
+ * Return attributes of current video standard.
+ * Since this device autodetects the current standard, this function also
+ * sets the values that need to be changed if the standard changes.
+ * There is no set std equivalent function.
+ *
+ * @return None.
+ */
+static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct vadc_state *state = to_state(sd);
+ int tmp;
+ int idx;
+
+ /* Read auto mode detected result */
+ printk(KERN_INFO"wait vadc auto detect video mode....");
+ msleep(500);
+ do {
+ tmp = reg32_read(VDEC_VIDMOD);
+ } while (tmp == 0);
+
+ tmp &= (VDEC_VIDMOD_PAL_MASK | VDEC_VIDMOD_M625_MASK);
+
+ if (tmp)
+ idx = VADC_PAL;
+ else
+ idx = VADC_NTSC;
+
+ *std = video_fmts[idx].v4l2_std;
+ state->fmt = &video_fmts[idx];
+
+ pr_debug("std=%s\n", video_fmts[idx].name);
+ return 0;
+}
+
+static int vadc_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ /* support only one format */
+ if (index >= 1)
+ return -EINVAL;
+
+ *code = V4L2_MBUS_FMT_AYUV8_1X32;
+ return 0;
+}
+
+static int vadc_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct vadc_state *state = to_state(sd);
+
+ fmt->code = V4L2_MBUS_FMT_AYUV8_1X32;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->width = 720;
+ fmt->height = state->fmt->v4l2_std & V4L2_STD_NTSC ? 480 : 576;
+
+ return 0;
+}
+
+static int vadc_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct vadc_state *state = to_state(sd);
+ if (fsize->index >= 1)
+ return -EINVAL;
+
+ fsize->discrete.width = state->fmt->active_width;
+ fsize->discrete.height = state->fmt->active_height;
+
+ return 0;
+}
+static int vadc_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_frmivalenum *fival)
+{
+ struct vadc_state *state = to_state(sd);
+
+ if (fival->index < 0 || fival->index >= 1)
+ return -EINVAL;
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete.numerator = 1;
+
+ fival->discrete.denominator = state->fmt->framerates;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops vadc_video_ops = {
+ .querystd = vadc_querystd,
+ .enum_mbus_fmt = vadc_enum_mbus_fmt,
+ .try_mbus_fmt = vadc_mbus_fmt,
+ .g_mbus_fmt = vadc_mbus_fmt,
+ .enum_framesizes = vadc_enum_framesizes,
+ .enum_frameintervals = vadc_enum_frameintervals,
+};
+
+static const struct v4l2_subdev_core_ops vadc_core_ops = {
+ .g_std = vadc_g_std,
+};
+
+static const struct v4l2_subdev_ops vadc_ops = {
+ .core = &vadc_core_ops,
+ .video = &vadc_video_ops,
+};
+
+static const struct of_device_id fsl_vadc_dt_ids[] = {
+ { .compatible = "fsl,imx6sx-vadc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_vadc_dt_ids);
+
+static int vadc_of_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *gpc_np;
+ struct vadc_state *state = platform_get_drvdata(pdev);
+ int csi_id;
+ int ret;
+
+ /* Get csi_id to setting vadc to csi mux in gpr */
+ ret = of_property_read_u32(np, "csi_id", &csi_id);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read of property csi_id\n");
+ return ret;
+ }
+
+ state->csi_id = csi_id;
+
+ /* remap GPR register */
+ state->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "gpr");
+ if (IS_ERR(state->gpr)) {
+ dev_dbg(&pdev->dev, "can not get gpr\n");
+ return -ENOMEM;
+ }
+
+ /* Configuration vadc-to-csi 0 or 1 */
+ if (csi_id) {
+ regmap_update_bits(state->gpr, IOMUXC_GPR5,
+ IMX6SX_GPR5_CSI2_MUX_CTRL_MASK,
+ IMX6SX_GPR5_CSI2_MUX_CTRL_CVD);
+ } else {
+ regmap_update_bits(state->gpr, IOMUXC_GPR5,
+ IMX6SX_GPR5_CSI1_MUX_CTRL_MASK,
+ IMX6SX_GPR5_CSI1_MUX_CTRL_CVD);
+ }
+
+ /* Get default vadc_in number */
+ ret = of_property_read_u32(np, "vadc_in", &state->vadc_in);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read of property vadc_in\n");
+ return ret;
+ }
+
+ /* map GPC register */
+ gpc_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
+ state->gpc_reg = of_iomap(gpc_np, 0);
+ if (!state->gpc_reg) {
+ dev_err(&pdev->dev, "ioremap failed with gpc base\n");
+ goto error;
+ }
+
+ return ret;
+
+error:
+ iounmap(state->gpc_reg);
+ return ret;
+}
+
+static void vadc_v4l2_subdev_init(struct v4l2_subdev *sd,
+ struct platform_device *pdev,
+ const struct v4l2_subdev_ops *ops)
+{
+ struct vadc_state *state = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ v4l2_subdev_init(sd, ops);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->owner = pdev->dev.driver->owner;
+ sd->dev = &pdev->dev;
+
+ /* initialize name */
+ snprintf(sd->name, sizeof(sd->name), "%s",
+ pdev->dev.driver->name);
+
+ v4l2_set_subdevdata(sd, state);
+
+ ret = v4l2_async_register_subdev(sd);
+ if (ret < 0)
+ dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n", __func__, ret);
+}
+
+static int vadc_probe(struct platform_device *pdev)
+{
+ struct vadc_state *state;
+ struct v4l2_subdev *sd;
+ struct resource *res;
+ int ret = 0;
+
+ state = devm_kzalloc(&pdev->dev, sizeof(struct vadc_state), GFP_KERNEL);
+ if (!state) {
+ dev_err(&pdev->dev, "Cannot allocate device data\n");
+ return -ENOMEM;
+ }
+
+ /* Set initial values for the sensor struct. */
+ state->fmt = &video_fmts[VADC_NTSC];
+
+ sd = &state->sd;
+
+ /* map vafe address */
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, VAFE_REGS_ADDR_RES_NAME);
+ if (!res) {
+ dev_err(&pdev->dev, "No vafe base address found.\n");
+ return -ENOMEM;
+ }
+ vafe_regbase = devm_ioremap_resource(&pdev->dev, res);
+ if (!vafe_regbase) {
+ dev_err(&pdev->dev, "ioremap failed with vafe base\n");
+ return -ENOMEM;
+ }
+
+ /* map vdec address */
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, VDEC_REGS_ADDR_RES_NAME);
+ if (!res) {
+ dev_err(&pdev->dev, "No vdec base address found.\n");
+ return -ENODEV;
+ }
+ vdec_regbase = devm_ioremap_resource(&pdev->dev, res);
+ if (!vdec_regbase) {
+ dev_err(&pdev->dev, "ioremap failed with vdec base\n");
+ return -ENOMEM;
+ }
+
+ /* Get clock */
+ state->vadc_clk = devm_clk_get(&pdev->dev, "vadc");
+ if (IS_ERR(state->vadc_clk)) {
+ ret = PTR_ERR(state->vadc_clk);
+ return ret;
+ }
+
+ state->csi_clk = devm_clk_get(&pdev->dev, "csi");
+ if (IS_ERR(state->csi_clk)) {
+ ret = PTR_ERR(state->csi_clk);
+ return ret;
+ }
+
+ /* clock */
+ clk_prepare_enable(state->csi_clk);
+ clk_prepare_enable(state->vadc_clk);
+
+ platform_set_drvdata(pdev, state);
+
+ vadc_v4l2_subdev_init(sd, pdev, &vadc_ops);
+
+ /* Init VADC */
+ ret = vadc_of_init(pdev);
+ if (ret < 0)
+ goto err;
+ vadc_init(state);
+
+ pr_info("vadc driver loaded\n");
+
+ return 0;
+err:
+ clk_disable_unprepare(state->csi_clk);
+ clk_disable_unprepare(state->vadc_clk);
+ return ret;
+}
+
+static int vadc_remove(struct platform_device *pdev)
+{
+ struct vadc_state *state = platform_get_drvdata(pdev);
+
+ v4l2_async_unregister_subdev(&state->sd);
+ clk_disable_unprepare(state->csi_clk);
+ clk_disable_unprepare(state->vadc_clk);
+
+ vadc_power_down(state);
+ return true;
+}
+
+static struct platform_driver vadc_driver = {
+ .driver = {
+ .name = "fsl_vadc",
+ .of_match_table = of_match_ptr(fsl_vadc_dt_ids),
+ },
+ .probe = vadc_probe,
+ .remove = vadc_remove,
+};
+
+module_platform_driver(vadc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("fsl VADC/VDEC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/subdev/mxc_vadc.h b/drivers/media/platform/mxc/subdev/mxc_vadc.h
new file mode 100644
index 000000000000..6ed5eeb982d0
--- /dev/null
+++ b/drivers/media/platform/mxc/subdev/mxc_vadc.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef MXC_VDEC_H
+#define MXC_VDEC_H
+
+/*** define base address ***/
+#define VDEC_BASE vdec_regbase
+#define AFE_BASE vafe_regbase
+
+/* AFE - Register offsets */
+#define AFE_BLOCK_ID_OFFSET 0x00000000
+#define AFE_PDBUF_OFFSET 0x00000004
+#define AFE_SWRST_OFFSET 0x00000008
+#define AFE_TSTSEL_OFFSET 0x0000000c
+#define AFE_TSTMSC_OFFSET 0x00000010
+#define AFE_ENPADIO_OFFSET 0x00000014
+#define AFE_BGREG_OFFSET 0x00000018
+#define AFE_ACCESSAR_ID_OFFSET 0x00000400
+#define AFE_PDADC_OFFSET 0x00000404
+#define AFE_PDSARH_OFFSET 0x00000408
+#define AFE_PDSARL_OFFSET 0x0000040C
+#define AFE_PDADCRFH_OFFSET 0x00000410
+#define AFE_PDADCRFL_OFFSET 0x00000414
+#define AFE_ACCTST_OFFSET 0x00000418
+#define AFE_ADCGN_OFFSET 0x0000041C
+#define AFE_ICTRL_OFFSET 0x00000420
+#define AFE_ICTLSTG_OFFSET 0x00000424
+#define AFE_RCTRLSTG_OFFSET 0x00000428
+#define AFE_TCTRLSTG_OFFSET 0x0000042c
+#define AFE_REFMOD_OFFSET 0x00000430
+#define AFE_REFTRIML_OFFSET 0x00000434
+#define AFE_REFTRIMH_OFFSET 0x00000438
+#define AFE_ADCR_OFFSET 0x0000043c
+#define AFE_DUMMY0_OFFSET 0x00000440
+#define AFE_DUMMY1_OFFSET 0x00000444
+#define AFE_DUMMY2_OFFSET 0x00000448
+#define AFE_DACAMP_OFFSET 0x0000044c
+#define AFE_CLMPTST_OFFSET 0x00000450
+#define AFE_CLMPDAT_OFFSET 0x00000454
+#define AFE_CLMPAMP_OFFSET 0x00000458
+#define AFE_CLAMP_OFFSET 0x0000045c
+#define AFE_INPBUF_OFFSET 0x00000460
+#define AFE_INPFLT_OFFSET 0x00000464
+#define AFE_ADCDGN_OFFSET 0x00000468
+#define AFE_OFFDRV_OFFSET 0x0000046c
+#define AFE_INPCONFIG_OFFSET 0x00000470
+#define AFE_PROGDELAY_OFFSET 0x00000474
+#define AFE_ADCOMT_OFFSET 0x00000478
+#define AFE_ALGDELAY_OFFSET 0x0000047c
+#define AFE_ACC_ID_OFFSET 0x00000800
+#define AFE_ACCSTA_OFFSET 0x00000804
+#define AFE_ACCNOSLI_OFFSET 0x00000808
+#define AFE_ACCCALCON_OFFSET 0x0000080c
+#define AFE_BWEWRICTRL_OFFSET 0x00000810
+#define AFE_SELSLI_OFFSET 0x00000814
+#define AFE_SELBYT_OFFSET 0x00000818
+#define AFE_REDVAL_OFFSET 0x00000820
+#define AFE_WRIBYT_OFFSET 0x00000824
+
+/* AFE Register per module */
+#define AFE_BLOCK_ID (AFE_BASE + AFE_BLOCK_ID_OFFSET)
+#define AFE_PDBUF (AFE_BASE + AFE_PDBUF_OFFSET)
+#define AFE_SWRST (AFE_BASE + AFE_SWRST_OFFSET)
+#define AFE_TSTSEL (AFE_BASE + AFE_TSTSEL_OFFSET)
+#define AFE_TSTMSC (AFE_BASE + AFE_TSTMSC_OFFSET)
+#define AFE_ENPADIO (AFE_BASE + AFE_ENPADIO_OFFSET)
+#define AFE_BGREG (AFE_BASE + AFE_BGREG_OFFSET)
+#define AFE_ACCESSAR_ID (AFE_BASE + AFE_ACCESSAR_ID_OFFSET)
+#define AFE_PDADC (AFE_BASE + AFE_PDADC_OFFSET)
+#define AFE_PDSARH (AFE_BASE + AFE_PDSARH_OFFSET)
+#define AFE_PDSARL (AFE_BASE + AFE_PDSARL_OFFSET)
+#define AFE_PDADCRFH (AFE_BASE + AFE_PDADCRFH_OFFSET)
+#define AFE_PDADCRFL (AFE_BASE + AFE_PDADCRFL_OFFSET)
+#define AFE_ACCTST (AFE_BASE + AFE_ACCTST_OFFSET)
+#define AFE_ADCGN (AFE_BASE + AFE_ADCGN_OFFSET)
+#define AFE_ICTRL (AFE_BASE + AFE_ICTRL_OFFSET)
+#define AFE_ICTLSTG (AFE_BASE + AFE_ICTLSTG_OFFSET)
+#define AFE_RCTRLSTG (AFE_BASE + AFE_RCTRLSTG_OFFSET)
+#define AFE_TCTRLSTG (AFE_BASE + AFE_TCTRLSTG_OFFSET)
+#define AFE_REFMOD (AFE_BASE + AFE_REFMOD_OFFSET)
+#define AFE_REFTRIML (AFE_BASE + AFE_REFTRIML_OFFSET)
+#define AFE_REFTRIMH (AFE_BASE + AFE_REFTRIMH_OFFSET)
+#define AFE_ADCR (AFE_BASE + AFE_ADCR_OFFSET)
+#define AFE_DUMMY0 (AFE_BASE + AFE_DUMMY0_OFFSET)
+#define AFE_DUMMY1 (AFE_BASE + AFE_DUMMY1_OFFSET)
+#define AFE_DUMMY2 (AFE_BASE + AFE_DUMMY2_OFFSET)
+#define AFE_DACAMP (AFE_BASE + AFE_DACAMP_OFFSET)
+#define AFE_CLMPTST (AFE_BASE + AFE_CLMPTST_OFFSET)
+#define AFE_CLMPDAT (AFE_BASE + AFE_CLMPDAT_OFFSET)
+#define AFE_CLMPAMP (AFE_BASE + AFE_CLMPAMP_OFFSET)
+#define AFE_CLAMP (AFE_BASE + AFE_CLAMP_OFFSET)
+#define AFE_INPBUF (AFE_BASE + AFE_INPBUF_OFFSET)
+#define AFE_INPFLT (AFE_BASE + AFE_INPFLT_OFFSET)
+#define AFE_ADCDGN (AFE_BASE + AFE_ADCDGN_OFFSET)
+#define AFE_OFFDRV (AFE_BASE + AFE_OFFDRV_OFFSET)
+#define AFE_INPCONFIG (AFE_BASE + AFE_INPCONFIG_OFFSET)
+#define AFE_PROGDELAY (AFE_BASE + AFE_PROGDELAY_OFFSET)
+#define AFE_ADCOMT (AFE_BASE + AFE_ADCOMT_OFFSET)
+#define AFE_ALGDELAY (AFE_BASE + AFE_ALGDELAY_OFFSET)
+#define AFE_ACC_ID (AFE_BASE + AFE_ACC_ID_OFFSET)
+#define AFE_ACCSTA (AFE_BASE + AFE_ACCSTA_OFFSET)
+#define AFE_ACCNOSLI (AFE_BASE + AFE_ACCNOSLI_OFFSET)
+#define AFE_ACCCALCON (AFE_BASE + AFE_ACCCALCON_OFFSET)
+#define AFE_BWEWRICTRL (AFE_BASE + AFE_BWEWRICTRL_OFFSET)
+#define AFE_SELSLI (AFE_BASE + AFE_SELSLI_OFFSET)
+#define AFE_SELBYT (AFE_BASE + AFE_SELBYT_OFFSET)
+#define AFE_REDVAL (AFE_BASE + AFE_REDVAL_OFFSET)
+#define AFE_WRIBYT (AFE_BASE + AFE_WRIBYT_OFFSET)
+
+/* VDEC - Register offsets */
+#define VDEC_CFC1_OFFSET 0x00000000
+#define VDEC_CFC2_OFFSET 0x00000004
+#define VDEC_BRSTGT_OFFSET 0x00000024
+#define VDEC_HZPOS_OFFSET 0x00000040
+#define VDEC_VRTPOS_OFFSET 0x00000044
+#define VDEC_HVSHIFT_OFFSET 0x00000054
+#define VDEC_HSIGS_OFFSET 0x00000058
+#define VDEC_HSIGE_OFFSET 0x0000005C
+#define VDEC_VSCON1_OFFSET 0x00000060
+#define VDEC_VSCON2_OFFSET 0x00000064
+#define VDEC_YCDEL_OFFSET 0x0000006C
+#define VDEC_AFTCLP_OFFSET 0x00000070
+#define VDEC_DCOFF_OFFSET 0x00000078
+#define VDEC_CSID_OFFSET 0x00000084
+#define VDEC_CBGN_OFFSET 0x00000088
+#define VDEC_CRGN_OFFSET 0x0000008C
+#define VDEC_CNTR_OFFSET 0x00000090
+#define VDEC_BRT_OFFSET 0x00000094
+#define VDEC_HUE_OFFSET 0x00000098
+#define VDEC_CHBTH_OFFSET 0x0000009C
+#define VDEC_SHPIMP_OFFSET 0x000000A4
+#define VDEC_CHPLLIM_OFFSET 0x000000A8
+#define VDEC_VIDMOD_OFFSET 0x000000AC
+#define VDEC_VIDSTS_OFFSET 0x000000B0
+#define VDEC_NOISE_OFFSET 0x000000B4
+#define VDEC_STDDBG_OFFSET 0x000000B8
+#define VDEC_MANOVR_OFFSET 0x000000BC
+#define VDEC_VSSGTH_OFFSET 0x000000C8
+#define VDEC_DBGFBH_OFFSET 0x000000D0
+#define VDEC_DBGFBL_OFFSET 0x000000D4
+#define VDEC_HACTS_OFFSET 0x000000D8
+#define VDEC_HACTE_OFFSET 0x000000DC
+#define VDEC_VACTS_OFFSET 0x000000E0
+#define VDEC_VACTE_OFFSET 0x000000E4
+#define VDEC_HSTIP_OFFSET 0x000000EC
+#define VDEC_BLSCRY_OFFSET 0x000000F4
+#define VDEC_BLSCRCR_OFFSET 0x000000F8
+#define VDEC_BLSCRCB_OFFSET 0x000000FC
+#define VDEC_LMAGC1_OFFSET 0x00000100
+#define VDEC_LMAGC2_OFFSET 0x00000104
+#define VDEC_CHAGC1_OFFSET 0x00000108
+#define VDEC_CHAGC2_OFFSET 0x0000010C
+#define VDEC_MINTH_OFFSET 0x00000114
+#define VDEC_VFRQOH_OFFSET 0x0000011C
+#define VDEC_VFRQOL_OFFSET 0x00000120
+#define VDEC_THSH1_OFFSET 0x00000124
+#define VDEC_THSH2_OFFSET 0x00000128
+#define VDEC_NCHTH_OFFSET 0x0000012C
+#define VDEC_TH1F_OFFSET 0x00000130
+
+/* VDEC Register per module */
+#define VDEC_CFC1 (VDEC_BASE + VDEC_CFC1_OFFSET)
+#define VDEC_CFC2 (VDEC_BASE + VDEC_CFC2_OFFSET)
+#define VDEC_BRSTGT (VDEC_BASE + VDEC_BRSTGT_OFFSET)
+#define VDEC_HZPOS (VDEC_BASE + VDEC_HZPOS_OFFSET)
+#define VDEC_VRTPOS (VDEC_BASE + VDEC_VRTPOS_OFFSET)
+#define VDEC_HVSHIFT (VDEC_BASE + VDEC_HVSHIFT_OFFSET)
+#define VDEC_HSIGS (VDEC_BASE + VDEC_HSIGS_OFFSET)
+#define VDEC_HSIGE (VDEC_BASE + VDEC_HSIGE_OFFSET)
+#define VDEC_VSCON1 (VDEC_BASE + VDEC_VSCON1_OFFSET)
+#define VDEC_VSCON2 (VDEC_BASE + VDEC_VSCON2_OFFSET)
+#define VDEC_YCDEL (VDEC_BASE + VDEC_YCDEL_OFFSET)
+#define VDEC_AFTCLP (VDEC_BASE + VDEC_AFTCLP_OFFSET)
+#define VDEC_DCOFF (VDEC_BASE + VDEC_DCOFF_OFFSET)
+#define VDEC_CSID (VDEC_BASE + VDEC_CSID_OFFSET)
+#define VDEC_CBGN (VDEC_BASE + VDEC_CBGN_OFFSET)
+#define VDEC_CRGN (VDEC_BASE + VDEC_CRGN_OFFSET)
+#define VDEC_CNTR (VDEC_BASE + VDEC_CNTR_OFFSET)
+#define VDEC_BRT (VDEC_BASE + VDEC_BRT_OFFSET)
+#define VDEC_HUE (VDEC_BASE + VDEC_HUE_OFFSET)
+#define VDEC_CHBTH (VDEC_BASE + VDEC_CHBTH_OFFSET)
+#define VDEC_SHPIMP (VDEC_BASE + VDEC_SHPIMP_OFFSET)
+#define VDEC_CHPLLIM (VDEC_BASE + VDEC_CHPLLIM_OFFSET)
+#define VDEC_VIDMOD (VDEC_BASE + VDEC_VIDMOD_OFFSET)
+#define VDEC_VIDSTS (VDEC_BASE + VDEC_VIDSTS_OFFSET)
+#define VDEC_NOISE (VDEC_BASE + VDEC_NOISE_OFFSET)
+#define VDEC_STDDBG (VDEC_BASE + VDEC_STDDBG_OFFSET)
+#define VDEC_MANOVR (VDEC_BASE + VDEC_MANOVR_OFFSET)
+#define VDEC_VSSGTH (VDEC_BASE + VDEC_VSSGTH_OFFSET)
+#define VDEC_DBGFBH (VDEC_BASE + VDEC_DBGFBH_OFFSET)
+#define VDEC_DBGFBL (VDEC_BASE + VDEC_DBGFBL_OFFSET)
+#define VDEC_HACTS (VDEC_BASE + VDEC_HACTS_OFFSET)
+#define VDEC_HACTE (VDEC_BASE + VDEC_HACTE_OFFSET)
+#define VDEC_VACTS (VDEC_BASE + VDEC_VACTS_OFFSET)
+#define VDEC_VACTE (VDEC_BASE + VDEC_VACTE_OFFSET)
+#define VDEC_HSTIP (VDEC_BASE + VDEC_HSTIP_OFFSET)
+#define VDEC_BLSCRY (VDEC_BASE + VDEC_BLSCRY_OFFSET)
+#define VDEC_BLSCRCR (VDEC_BASE + VDEC_BLSCRCR_OFFSET)
+#define VDEC_BLSCRCB (VDEC_BASE + VDEC_BLSCRCB_OFFSET)
+#define VDEC_LMAGC1 (VDEC_BASE + VDEC_LMAGC1_OFFSET)
+#define VDEC_LMAGC2 (VDEC_BASE + VDEC_LMAGC2_OFFSET)
+#define VDEC_CHAGC1 (VDEC_BASE + VDEC_CHAGC1_OFFSET)
+#define VDEC_CHAGC2 (VDEC_BASE + VDEC_CHAGC2_OFFSET)
+#define VDEC_MINTH (VDEC_BASE + VDEC_MINTH_OFFSET)
+#define VDEC_VFRQOH (VDEC_BASE + VDEC_VFRQOH_OFFSET)
+#define VDEC_VFRQOL (VDEC_BASE + VDEC_VFRQOL_OFFSET)
+#define VDEC_THSH1 (VDEC_BASE + VDEC_THSH1_OFFSET)
+#define VDEC_THSH2 (VDEC_BASE + VDEC_THSH2_OFFSET)
+#define VDEC_NCHTH (VDEC_BASE + VDEC_NCHTH_OFFSET)
+#define VDEC_TH1F (VDEC_BASE + VDEC_TH1F_OFFSET)
+
+#define VDEC_VIDMOD_M625_SHIFT 4
+#define VDEC_VIDMOD_M625_MASK (1 << VDEC_VIDMOD_M625_SHIFT)
+
+#define VDEC_VIDMOD_PAL_SHIFT 7
+#define VDEC_VIDMOD_PAL_MASK (1 << VDEC_VIDMOD_PAL_SHIFT)
+/*** define base address ***/
+
+#endif