From 58c5f746d47fbcb849cd1b83973fe04dc72662d9 Mon Sep 17 00:00:00 2001
From: Damian <damian.eppel@teleca.com>
Date: Tue, 5 Jun 2012 23:14:58 +0200
Subject: [PATCH] cssp_camera driver

---
 arch/arm/mach-omap2/board-am335xevm.c         |  202 ++++-
 arch/arm/mach-omap2/devices.c                 |    2 +-
 arch/arm/plat-omap/include/plat/dma-33xx.h    |    1 +
 defconfig                                     |   21 +-
 drivers/media/video/Kconfig                   |   14 +
 drivers/media/video/Makefile                  |    2 +
 drivers/media/video/cssp_camera/Makefile      |    3 +
 drivers/media/video/cssp_camera/cssp_camera.c | 1123 +++++++++++++++++++++++++
 drivers/media/video/cssp_camera/cssp_camera.h |  235 ++++++
 9 files changed, 1592 insertions(+), 11 deletions(-)
 create mode 100755 drivers/media/video/cssp_camera/Makefile
 create mode 100755 drivers/media/video/cssp_camera/cssp_camera.c
 create mode 100644 drivers/media/video/cssp_camera/cssp_camera.h

diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
index a337bb3..db8253e 100644
--- a/arch/arm/mach-omap2/board-am335xevm.c
+++ b/arch/arm/mach-omap2/board-am335xevm.c
@@ -65,6 +65,10 @@
 #include <plat/mmc.h>
 #include <plat/emif.h>
 #include <plat/nand.h>
+#include <plat/dma-33xx.h>
+
+#include <media/soc_camera.h>
+#include <media/mt9t112.h>
 
 #include "board-flash.h"
 #include "cpuidle33xx.h"
@@ -803,6 +807,42 @@ static struct pinmux_config i2c1_pin_mux[] = {
 	{NULL, 0},
 };
 
+/* Pin mux for GPMC bus */
+static struct pinmux_config gpmc_pin_mux[] = {
+	{"gpmc_ad0.gpmc_ad0",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad1.gpmc_ad1",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad2.gpmc_ad2",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad3.gpmc_ad3",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad4.gpmc_ad4",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad5.gpmc_ad5",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad6.gpmc_ad6",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad7.gpmc_ad7",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad8.gpmc_ad8",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad9.gpmc_ad9",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad10.gpmc_ad10",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad11.gpmc_ad11",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad12.gpmc_ad12",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad13.gpmc_ad13",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad14.gpmc_ad14",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_ad15.gpmc_ad15",	  OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_wait0.gpmc_wait0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_wpn.gpmc_wpn",	  OMAP_MUX_MODE7 | AM33XX_PIN_INPUT_PULLUP},
+	{"gpmc_csn1.gpmc_csn1",	  OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
+	{"gpmc_advn_ale.gpmc_advn_ale",  OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
+	{"gpmc_oen_ren.gpmc_oen_ren",	 OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
+	{"gpmc_wen.gpmc_wen",     OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
+	{"gpmc_ben0_cle.gpmc_ben0_cle",	 OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
+	{"gpmc_clk.gpmc_clk",	 OMAP_MUX_MODE0 | AM33XX_PIN_INPUT},
+	{"ecap0_in_pwm0_out.xdma_event_intr2", OMAP_MUX_MODE6 | AM33XX_PIN_INPUT}, // DMAREQ
+	{NULL, 0},
+};
+
+static struct pinmux_config camera_cape_pin_mux[] = {
+	{"spi0_d1.gpio0_4",    OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT },		// QL CSSP and Camera Sensor Reset
+	{"spi0_cs0.gpio0_5",   OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT_PULLUP },	// 1V8 and 2V8 Power Enable
+	{NULL, 0},
+};
+
 static struct pinmux_config i2c2_pin_mux[] = {
 	{"uart1_ctsn.i2c2_sda",    OMAP_MUX_MODE3 | AM33XX_SLEWCTRL_SLOW |
 					AM33XX_PIN_INPUT_PULLUP},
@@ -1802,6 +1842,153 @@ static void dvileds_init(int evm_id, int profile )
 		pr_err("failed to register BeagleBone DVI cape LEDS\n");
 }
 
+static struct resource cssp_camera_resources[] = {
+	{
+		.name = "gpmc_phys_mem_slot",
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct mt9t112_camera_info mt9t111_cam_info = {
+	/* divider calculated for 32Mhz CAM_MCLK */
+	.divider = {
+		.m = 24, .n = 1,
+		.p1 = 0, .p2 = 7, .p3 = 0, .p4 = 11, .p5 = 15, .p6 = 7, .p7 = 0,
+	},
+};
+
+
+static struct soc_camera_link mt9t111_camera_link =  {
+	.priv = &mt9t111_cam_info,
+	.i2c_adapter_id = 3,
+};
+
+struct cssp_cam_platform_data_s
+{
+	struct soc_camera_link *scl;
+	const char* cam_clk_name;
+	int dma_ch;
+	int gpio_cssp_reset_pin;
+};
+
+struct cssp_cam_platform_data_s cssp_cam_platform_data = {
+	.scl = &mt9t111_camera_link,
+	.dma_ch = AM33XX_DMA_XDMA_EVENT_INTR2,
+	.cam_clk_name = "clkout2_ck",
+	.gpio_cssp_reset_pin = GPIO_TO_PIN(0, 4),
+};
+
+static struct platform_device cssp_camera = {
+	.name  = "cssp-camera",
+	.id    = -1,
+	.dev   = {
+		.platform_data = &cssp_cam_platform_data,
+	},
+	.num_resources = sizeof(cssp_camera_resources) / sizeof(cssp_camera_resources[0]),
+	.resource = cssp_camera_resources,
+};
+
+static struct gpmc_timings cssp_timings = {
+	/* Minimum clock period for synchronous mode (in picoseconds) */
+	.sync_clk = 10000,
+
+	.cs_on = 0,
+	.cs_rd_off = 23 * 10,		/* Read deassertion time */
+	.cs_wr_off = 23 * 10,		/* Write deassertion time */
+
+	/* ADV signal timings corresponding to GPMC_CONFIG3 */
+	.adv_on = 0,			/* Assertion time */
+	.adv_rd_off = 2 * 10,		/* Read deassertion time */
+	.adv_wr_off = 2 * 10,		/* Write deassertion time */
+
+	/* WE signals timings corresponding to GPMC_CONFIG4 */
+	.we_on = 3 * 10,		/* WE assertion time */
+	.we_off = 23 * 10,		/* WE deassertion time */
+
+	/* OE signals timings corresponding to GPMC_CONFIG4 */
+	.oe_on = 3 * 10,		/* OE assertion time */
+	.oe_off = 23 * 10,		/* OE deassertion time */
+
+	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
+	.page_burst_access = 1 * 10,	/* Multiple access word delay */
+	.access = 7 * 10,		/* Start-cycle to first data valid delay */
+	.rd_cycle = 23 * 10,		/* Total read cycle time */
+	.wr_cycle = 23 * 10,		/* Total write cycle time */
+
+	/* The following are only on OMAP3430 */
+	.wr_access = 7 * 10,		/* WRACCESSTIME */
+	.wr_data_mux_bus = 3 * 10,	/* WRDATAONADMUXBUS */
+};
+
+static int gpmc_cssp_init(void)
+{
+	int cs = 1; /* Chip Select on GPMC bus */
+	int val;
+	long unsigned int cssp_gpmc_mem_base_phys;
+
+	if (gpmc_cs_request(cs, SZ_16M, &cssp_gpmc_mem_base_phys) < 0) {
+			printk(KERN_ERR "[cssp_cam platform init]: gpmc_cs_request failed\n");
+			return -1;
+	}
+
+	cssp_camera_resources[0].start = cssp_gpmc_mem_base_phys;
+	cssp_camera_resources[0].end = cssp_gpmc_mem_base_phys + 0x1ffff;
+
+	if (gpmc_cs_configure(cs, GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NOR) < 0) {
+			printk(KERN_ERR "[cssp_cam platform init]: gpmc_cs_configure failed\n");
+			return -1;
+	}
+
+	val = GPMC_CONFIG1_READMULTIPLE_SUPP;
+	val |= GPMC_CONFIG1_READTYPE_SYNC;
+	val |= GPMC_CONFIG1_WRITETYPE_SYNC;
+	val |= GPMC_CONFIG1_CLKACTIVATIONTIME(1);
+	val |= GPMC_CONFIG1_PAGE_LEN(2);
+	val |= GPMC_CONFIG1_DEVICESIZE_16;
+	val |= GPMC_CONFIG1_DEVICETYPE_NOR;
+	val |= GPMC_CONFIG1_MUXADDDATA;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, val);
+
+	if (gpmc_cs_set_timings(cs, &cssp_timings) < 0) {
+		printk(KERN_ERR "Failed gpmc_cs_set_timings for QuickLogic CAMIF device\n");
+		goto free;
+	}
+
+	val = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG6);
+	val &= 0xe0f0f030;
+	val |= 0x07030481;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, val);
+
+	printk(KERN_INFO "gpmc_cssp_init for QuickLogic CAMIF device succeeded\n");
+
+	return 0;
+
+free:
+	gpmc_cs_free(cs);
+
+	printk(KERN_ERR "Could not initialize QuickLogic CAMIF device\n");
+
+	return -1;
+}
+
+static void cssp_gpmc_init(void)
+{
+	struct gpmc_devices_info gpmc_device[2] = {
+			{ NULL, GPMC_DEVICE_NOR },
+		};
+
+	setup_pin_mux(camera_cape_pin_mux);
+	setup_pin_mux(gpmc_pin_mux);
+
+	omap_init_gpmc(gpmc_device, sizeof(gpmc_device));
+	gpmc_cssp_init();
+
+	platform_device_register(&cssp_camera);
+
+	printk(KERN_INFO "[cssp_cam platform init]: cssp_gpmc_init: DONE\n");
+}
+
+
 static void lcd3leds_init(int evm_id, int profile )
 {
 	int err;
@@ -2820,6 +3007,7 @@ static void beaglebone_cape_setup(struct memory_accessor *mem_acc, void *context
 	if (!strncmp("BB-BONE-CAM-01", cape_config.partnumber, 14)) {
 		pr_info("BeagleBone cape: recognized Camera cape\n");
 		beaglebone_w1gpio_free = 0;
+		cssp_gpmc_init();
 	}
 
 	goto out2;
@@ -3731,15 +3919,13 @@ static struct pinmux_config clkout2_pin_mux[] = {
 
 static void __init clkout2_enable(void)
 {
-	struct clk *ck_32;
-
-	ck_32 = clk_get(NULL, "clkout2_ck");
-	if (IS_ERR(ck_32)) {
-		pr_err("Cannot clk_get ck_32\n");
-		return;
-	}
+	void __iomem *base;
+	unsigned int val;
 
-	clk_enable(ck_32);
+	base = ioremap(0x44E00700, SZ_4K);
+	val = (5 << 3) | (3 << 0); //32 MHz
+	writel(val, base);
+	iounmap(base);
 
 	setup_pin_mux(clkout2_pin_mux);
 }
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 41c9b0f..3ef045e 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -968,7 +968,7 @@ static struct event_to_channel_map am33xx_xbar_event_mapping[] = {
 	{27, -1},
 	{28, -1},
 	{29, -1},
-	{30, -1},
+	{30, 20},	/* XDMA_EVENT_INTR2 */
 	{31, -1},
 	{-1, -1}
 };
diff --git a/arch/arm/plat-omap/include/plat/dma-33xx.h b/arch/arm/plat-omap/include/plat/dma-33xx.h
index bebdaa7..ded00aa 100644
--- a/arch/arm/plat-omap/include/plat/dma-33xx.h
+++ b/arch/arm/plat-omap/include/plat/dma-33xx.h
@@ -83,5 +83,6 @@
 #define AM33XX_DMA_PWMSS2_EPW				63
 #define AM33XX_DMA_MMCHS2_W				64	/* xBar */
 #define AM33XX_DMA_MMCHS2_R				65	/* xBar */
+#define AM33XX_DMA_XDMA_EVENT_INTR2			93	/* xBar */
 
 #endif
diff --git a/defconfig b/defconfig
index 9354aa7..27090ce 100644
--- a/defconfig
+++ b/defconfig
@@ -2071,7 +2071,7 @@ CONFIG_VIDEO_CX2341X=m
 #
 # CONFIG_VIDEO_THS7303 is not set
 # CONFIG_VIDEO_M52790 is not set
-CONFIG_VIDEO_VIVI=m
+CONFIG_VIDEO_VIVI=y
 # CONFIG_VIDEO_VPFE_CAPTURE is not set
 # CONFIG_VIDEO_OMAP2_VOUT is not set
 # CONFIG_VIDEO_BWQCAM is not set
@@ -2079,7 +2079,24 @@ CONFIG_VIDEO_VIVI=m
 # CONFIG_VIDEO_W9966 is not set
 # CONFIG_VIDEO_CPIA2 is not set
 # CONFIG_VIDEO_AU0828 is not set
-# CONFIG_SOC_CAMERA is not set
+CONFIG_SOC_CAMERA=y
+# CONFIG_SOC_CAMERA_IMX074 is not set
+# CONFIG_SOC_CAMERA_MT9M001 is not set
+# CONFIG_SOC_CAMERA_MT9M111 is not set
+# CONFIG_SOC_CAMERA_MT9T031 is not set
+CONFIG_SOC_CAMERA_MT9T112=y
+# CONFIG_SOC_CAMERA_MT9V022 is not set
+# CONFIG_SOC_CAMERA_RJ54N1 is not set
+# CONFIG_SOC_CAMERA_TW9910 is not set
+# CONFIG_SOC_CAMERA_PLATFORM is not set
+# CONFIG_SOC_CAMERA_OV2640 is not set
+# CONFIG_SOC_CAMERA_OV5642 is not set
+# CONFIG_SOC_CAMERA_OV6650 is not set
+# CONFIG_SOC_CAMERA_OV772X is not set
+# CONFIG_SOC_CAMERA_OV9640 is not set
+# CONFIG_SOC_CAMERA_OV9740 is not set
+# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
 CONFIG_V4L_USB_DRIVERS=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index b303a3f..5d85f02 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1002,6 +1002,20 @@ config VIDEO_S5P_MIPI_CSIS
 
 source "drivers/media/video/s5p-tv/Kconfig"
 
+config VIDEO_QL_CAMIF
+	tristate "QuickLogic Camera Interface support (EXPERIMENTAL)"
+	depends on VIDEO_DEV && SOC_CAMERA && SOC_OMAPAM33XX && EXPERIMENTAL
+	select VIDEOBUF_DMA_CONTIG
+	select VIDEOBUF2_VMALLOC
+	---help---
+	  This is a v4l2 driver for the QuickLogic CAMIF controller.
+
+config VIDEO_QL_CAMIF_DEBUG
+	bool "QuickLogic Camera Interface debug messages"
+	depends on VIDEO_QL_CAMIF
+	---help---
+	  Enable debug messages on QuickLogic CAMIF driver.
+
 #
 # USB Multimedia device configuration
 #
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 117f9c4..af7af692 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -195,6 +195,8 @@ obj-y	+= davinci/
 
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
 
+obj-$(CONFIG_VIDEO_QL_CAMIF)	+= cssp_camera/
+
 ccflags-y += -Idrivers/media/dvb/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
 ccflags-y += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/cssp_camera/Makefile b/drivers/media/video/cssp_camera/Makefile
new file mode 100755
index 0000000..d85a84e
--- /dev/null
+++ b/drivers/media/video/cssp_camera/Makefile
@@ -0,0 +1,3 @@
+# cssp_camera
+
+obj-$(CONFIG_VIDEO_QL_CAMIF) += cssp_camera.o
diff --git a/drivers/media/video/cssp_camera/cssp_camera.c b/drivers/media/video/cssp_camera/cssp_camera.c
new file mode 100755
index 0000000..033469f
--- /dev/null
+++ b/drivers/media/video/cssp_camera/cssp_camera.c
@@ -0,0 +1,1123 @@
+/*
+ * cssp-camera driver
+ *
+ * Based on Vivi driver
+ *
+ * Copyright (C) 2012 QuickLogic Corp.
+ * Damian Eppel <damian.eppel@teleca.com>
+ * Przemek Szewczyk <przemek.szewczyk@teleca.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/mt9t112.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-mediabus.h>
+#include <plat/gpmc.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <mach/edma.h>
+#include <linux/clk.h>
+// V4L2 Interface *********************
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+//*************************************
+#include "cssp_camera.h"
+
+
+static cssp_cam_struct_t cssp_cam_struct = {
+
+		.camera_board_info = {
+
+				I2C_BOARD_INFO("mt9t112", 0x3c),
+		},
+
+		.dma_tr_params = {
+
+				.opt = TCINTEN,
+				.a_b_cnt = ACNT(32) | BCNT(19200),
+				.src_dst_bidx = SRCBIDX(0) | DSTBIDX(32),
+				.link_bcntrld = BCNTRLD(0) | LINK(0xffff),
+				.src_dst_cidx = SRCCIDX(0) | DSTCIDX(0),
+				.ccnt = CCNT(1),
+
+		},
+
+		.dst_buff_size = VGA_RES*BYTES_PER_PIXEL,
+
+		.frame_cnt = 0,
+
+};
+
+
+// V4L2 Interface *************************************************************************************************
+
+static const struct v4l2_file_operations cssp_cam_fops = {
+
+	.owner          = THIS_MODULE,
+	.open           = v4l2_fh_open, //drv_open,
+	.release        = video_close,
+	.read           = video_read,
+	.poll           = video_poll,
+	.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+	.mmap           = video_mmap,
+};
+
+static const struct v4l2_ioctl_ops  cssp_cam_ioctl_ops = {
+
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+	.vidioc_log_status    = vidioc_log_status,
+	.vidioc_subscribe_event = vidioc_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static struct video_device cssp_cam_template = {
+
+	.name  = "cssp_camera",
+	.fops  = &cssp_cam_fops,
+	.ioctl_ops = &cssp_cam_ioctl_ops,
+	.minor  = -1,
+	.release = video_device_release,
+	.tvnorms = V4L2_STD_525_60,
+	.current_norm = V4L2_STD_NTSC_M,
+};
+
+
+
+static struct cssp_cam_fmt formats[] = {
+	{
+		.name     = "RGB565 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+		.depth    = 16,
+	},
+	{
+		.name     = "RGB565 (BE)",
+		.fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+		.depth    = 16,
+	},
+};
+
+
+static struct vb2_ops cssp_cam_video_qops = {
+
+	.queue_setup		= queue_setup,
+	.buf_init		= buffer_init,
+	.buf_prepare		= buffer_prepare,
+	.buf_finish		= buffer_finish,
+	.buf_cleanup		= buffer_cleanup,
+	.buf_queue		= buffer_queue,
+	.start_streaming	= start_streaming,
+	.stop_streaming		= stop_streaming,
+	.wait_prepare		= cssp_cam_unlock,
+	.wait_finish		= cssp_cam_lock,
+};
+
+/***************************************************************************/
+
+
+static int bb_configure_gpio(int nr, int val, const char *name)
+{
+	unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+	int ret;
+	if (!gpio_is_valid(nr))
+		return 0;
+	ret = gpio_request_one(nr, flags, name);
+	if (!ret)
+		gpio_export(nr, 0);
+	return ret;
+}
+
+
+static int reset_cssp(struct platform_device * pdev)
+{
+	int err;
+
+	cssp_cam_struct.cssp_reset_pin = ((struct cssp_cam_platform_data_s*) pdev->dev.platform_data)->gpio_cssp_reset_pin;
+
+	err= bb_configure_gpio(cssp_cam_struct.cssp_reset_pin, 0, "cssp_reset");
+	if(err){
+		printk(KERN_ERR "[%s]: failed to configure cssp_reset pin", pdev->name);
+		return -1;
+	}
+
+	mdelay(1);
+
+	gpio_direction_output(cssp_cam_struct.cssp_reset_pin, 1);
+
+	return err;
+}
+
+static int video_post_frame(struct cssp_cam_dev *dev)
+{
+	struct cssp_cam_buffer *buf;
+	struct cssp_cam_dmaqueue *dma_q = &dev->vidq;
+	struct timeval ts;
+	unsigned long flags = 0;
+	void *vbuf = NULL;
+
+	spin_lock_irqsave(&dev->slock, flags);
+	if (list_empty(&dma_q->active)) {
+		dprintk(dev, 1, "No active queue to serve\n");
+		spin_unlock_irqrestore(&dev->slock, flags);
+
+		return -1;
+	}
+
+	buf = list_entry(dma_q->active.next, struct cssp_cam_buffer, list);
+	list_del(&buf->list);
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	vbuf = vb2_plane_vaddr(&buf->vb, 0);
+	if(!vbuf){
+		dprintk(dev, 1, "vbuf = NULL!\n");
+		return -1;
+	}
+
+	buf->fmt = dev->fmt;
+
+	memcpy(vbuf, cssp_cam_struct.dma_dest_buff_virt, cssp_cam_struct.dst_buff_size);
+
+
+	buf->vb.v4l2_buf.field = dev->field;
+	dev->field_count++;
+	buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
+	do_gettimeofday(&ts);
+	buf->vb.v4l2_buf.timestamp = ts;
+
+	dprintk(dev, 1, "filled buffer %p\n", buf);
+
+	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+	dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
+
+	dprintk(dev, 1, "returning from %s\n", __func__);
+	return 0;
+}
+
+
+static void dma_callback(unsigned lch, u16 ch_status, void *data)
+{
+	struct cssp_cam_dev* dev;
+
+	// Disable data capture
+	writew(0xe000, cssp_cam_struct.gpmc_mem_base_virt);
+	readw(cssp_cam_struct.gpmc_mem_base_virt);
+
+	if (cssp_cam_struct.vdev != NULL){
+
+		dev = video_get_drvdata(cssp_cam_struct.vdev);
+
+		if(ch_status == DMA_COMPLETE){
+			video_post_frame(dev);
+		}
+		else {
+
+			printk(KERN_ERR "[cssp_camera]: EDMA error (ch_status = %d)", ch_status);
+		}
+
+
+		cssp_cam_struct.frame_cnt++;
+	}
+	else
+		printk(KERN_ERR "[cssp_camera]: error (video_dev = NULL)");
+
+
+	edma_write_slot(cssp_cam_struct.dma_ch_out, &cssp_cam_struct.dma_tr_params);
+
+	// Enable data capture
+	writew(0xf000, cssp_cam_struct.gpmc_mem_base_virt);
+	readw(cssp_cam_struct.gpmc_mem_base_virt);
+
+
+}
+
+
+
+static int configure_edma_for_cssp_cam(struct platform_device* pdev)
+{
+	int ret = 0;
+	int dma_channel;
+
+	dma_channel = ((struct cssp_cam_platform_data_s*) pdev->dev.platform_data)->dma_ch;
+
+
+	pdev->dev.dma_mask = &cssp_cam_struct.dma_mask;
+
+	pdev->dev.coherent_dma_mask = (u32)~0;
+
+
+	if(dma_set_mask(&pdev->dev, (u32)~0)){
+
+		printk(KERN_ERR "[%s]: failed setting mask for DMA", pdev->name);
+		return -1;
+	}
+
+
+	cssp_cam_struct.dma_dest_buff_virt = dma_alloc_coherent(&pdev->dev, cssp_cam_struct.dst_buff_size, &cssp_cam_struct.dma_tr_params.dst, GFP_KERNEL);
+	if(cssp_cam_struct.dma_dest_buff_virt == NULL){
+
+		printk(KERN_ERR "[%s]: failed allocating coherent memory for DMA", pdev->name);
+		return -1;
+	}
+
+	printk(KERN_INFO "[%s]: allocating coherent memory for DMA succeeded", pdev->name);
+
+
+	cssp_cam_struct.dma_tr_params.src = cssp_cam_struct.gpmc_mem_base_phys + 0x10000;
+
+
+	cssp_cam_struct.dma_ch_out = edma_alloc_channel(dma_channel, dma_callback, NULL, EVENTQ_1);
+	if(cssp_cam_struct.dma_ch_out < 0){
+		printk(KERN_ERR "[%s]: allocating channel for DMA failed", pdev->name);
+		goto fail;
+	}
+	else
+		printk(KERN_ERR "[%s]: allocating channel for DMA succeeded, chan=%d", pdev->name, cssp_cam_struct.dma_ch_out);
+
+	cssp_cam_struct.dma_tr_params.opt |= TCC(cssp_cam_struct.dma_ch_out);
+
+
+	return ret;
+
+fail:
+
+	dma_free_coherent(&pdev->dev, cssp_cam_struct.dst_buff_size,
+			cssp_cam_struct.dma_dest_buff_virt, cssp_cam_struct.dma_tr_params.dst);
+	return -1;
+
+}
+
+
+static int configure_cssp(struct platform_device* pdev)
+{
+	int ret = 0;
+	unsigned int val;
+	struct resource *res;
+	resource_size_t gpmc_mem_slot_size;
+
+	ret = reset_cssp(pdev);
+	if(ret)
+		return ret;
+
+	res =  platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpmc_phys_mem_slot");
+	if(res == NULL){
+		printk(KERN_ERR "[%s]: failed to get gpmc_phys_mem_slot resource", pdev->name);
+		return -1;
+	}
+
+	cssp_cam_struct.gpmc_mem_base_phys = res->start;
+	gpmc_mem_slot_size =res->end - res->start;
+
+	cssp_cam_struct.gpmc_mem_base_virt = (unsigned int)ioremap(cssp_cam_struct.gpmc_mem_base_phys, gpmc_mem_slot_size);
+	if(cssp_cam_struct.gpmc_mem_base_virt == 0){
+		printk(KERN_ERR "[%s]: ioremap failed with gpmc_phys_mem_slot", pdev->name);
+		return -1;
+	}
+
+	printk(KERN_INFO "[%s]: gpmc_base_virt=0x%x\n", pdev->name, cssp_cam_struct.gpmc_mem_base_virt);
+
+
+	val = readw((cssp_cam_struct.gpmc_mem_base_virt + 0x0));
+	printk(KERN_INFO "[%s]: reading gpmc address=0x0 returns 0x%x", pdev->name, val);
+
+
+	return ret;
+}
+
+
+
+static int drive_mt9t111_camera(struct i2c_board_info* info)
+{
+	struct i2c_adapter* adapter = NULL;
+	struct v4l2_subdev *subdev = NULL;
+	struct v4l2_mbus_framefmt f_format = {
+
+			.width = VGA_WIDTH,
+			.height = VGA_HEIGHT,
+			.code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+			.colorspace = V4L2_COLORSPACE_SRGB,
+	};
+
+
+	clk_enable(cssp_cam_struct.camera_ck);
+	udelay(5);
+
+
+	/* If we already have camera_client just bypass initialization */
+	if(cssp_cam_struct.camera_client != NULL)
+		goto drive;
+
+	adapter	= i2c_get_adapter(((struct soc_camera_link*)(info->platform_data))->i2c_adapter_id);
+	if(!adapter){
+		printk(KERN_INFO "[%s]: failed to get adapter...", __func__);
+		return -1;
+	}
+
+	cssp_cam_struct.camera_client = i2c_new_device(adapter, info);
+	i2c_put_adapter(adapter);
+
+	if(cssp_cam_struct.camera_client == NULL){
+		return -1;
+	}
+
+
+	printk(KERN_INFO "[%s]: client's name is: %s\n", __func__, cssp_cam_struct.camera_client->name);
+
+drive:
+
+	subdev = (struct v4l2_subdev *)i2c_get_clientdata(cssp_cam_struct.camera_client);
+	subdev->ops->video->s_mbus_fmt(subdev, &f_format);
+	subdev->ops->video->s_stream(subdev,1);
+
+	return 0;
+
+}
+
+
+static void stop_mt9t111_camera(struct i2c_board_info* info)
+{
+	struct v4l2_subdev *subdev = NULL;
+
+	clk_disable(cssp_cam_struct.camera_ck);
+	udelay(5);
+
+
+	/* If we don't have camera_client yet - just return */
+	if(cssp_cam_struct.camera_client == NULL){
+			return;
+		}
+
+
+	subdev = (struct v4l2_subdev *)i2c_get_clientdata(cssp_cam_struct.camera_client);
+	subdev->ops->video->s_stream(subdev,0);
+
+	return;
+
+}
+
+
+/************************************************
+ * 				Video4Linux2
+ */
+
+
+
+static struct cssp_cam_fmt *get_format(struct v4l2_format *f)
+{
+	struct cssp_cam_fmt *fmt;
+	unsigned int k;
+
+	for (k = 0; k < ARRAY_SIZE(formats); k++) {
+		fmt = &formats[k];
+		if (fmt->fourcc == f->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (k == ARRAY_SIZE(formats))
+		return NULL;
+
+	return &formats[k];
+}
+
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
+	unsigned long size;
+
+	size = dev->width * dev->height * 2;
+
+	if (0 == *nbuffers)
+		*nbuffers = 32;
+
+	while (size * *nbuffers > vid_limit * 1024 * 1024)
+		(*nbuffers)--;
+
+	*nplanes = 1;
+
+	sizes[0] = size;
+
+	/*
+	 * videobuf2-vmalloc allocator is context-less so no need to set
+	 * alloc_ctxs array.
+	 */
+
+	dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__, *nbuffers, size);
+
+	return 0;
+}
+
+static int buffer_init(struct vb2_buffer *vb)
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+	BUG_ON(NULL == dev->fmt);
+
+	/*
+	 * This callback is called once per buffer, after its allocation.
+	 *
+	 * Vivi does not allow changing format during streaming, but it is
+	 * possible to do so when streaming is paused (i.e. in streamoff state).
+	 * Buffers however are not freed when going into streamoff and so
+	 * buffer size verification has to be done in buffer_prepare, on each
+	 * qbuf.
+	 * It would be best to move verification code here to buf_init and
+	 * s_fmt though.
+	 */
+
+	return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct cssp_cam_buffer *buf = container_of(vb, struct cssp_cam_buffer, vb);
+	unsigned long size;
+
+	dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
+
+	BUG_ON(NULL == dev->fmt);
+
+	/*
+	 * Theses properties only change when queue is idle, see s_fmt.
+	 * The below checks should not be performed here, on each
+	 * buffer_prepare (i.e. on each qbuf). Most of the code in this function
+	 * should thus be moved to buffer_init and s_fmt.
+	 */
+	if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
+	    dev->height < 32 || dev->height > MAX_HEIGHT)
+		return -EINVAL;
+
+	size = dev->width * dev->height * 2;
+	if (vb2_plane_size(vb, 0) < size) {
+		dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
+				__func__, vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(&buf->vb, 0, size);
+
+	buf->fmt = dev->fmt;
+
+	return 0;
+}
+
+static int buffer_finish(struct vb2_buffer *vb)
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	dprintk(dev, 1, "%s\n", __func__);
+	return 0;
+}
+
+static void buffer_cleanup(struct vb2_buffer *vb)
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	dprintk(dev, 1, "%s\n", __func__);
+
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct cssp_cam_buffer *buf = container_of(vb, struct cssp_cam_buffer, vb);
+	struct cssp_cam_dmaqueue *vidq = &dev->vidq;
+	unsigned long flags = 0;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	spin_lock_irqsave(&dev->slock, flags);
+	list_add_tail(&buf->list, &vidq->active);
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
+
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
+	int ret;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	ret = drive_mt9t111_camera(&cssp_cam_struct.camera_board_info);
+	if (ret != 0)
+		return ret;
+
+	// Enable DMA
+	edma_write_slot(cssp_cam_struct.dma_ch_out, &cssp_cam_struct.dma_tr_params);
+	edma_start(cssp_cam_struct.dma_ch_out);
+
+	// Enable data capture
+	writew(0xf000, cssp_cam_struct.gpmc_mem_base_virt);
+	readw(cssp_cam_struct.gpmc_mem_base_virt);
+
+	return 0;
+}
+
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	// Disable DMA
+	edma_stop(cssp_cam_struct.dma_ch_out);
+
+	// Disable data capture
+	writew(0xe000, cssp_cam_struct.gpmc_mem_base_virt);
+	readw(cssp_cam_struct.gpmc_mem_base_virt);
+
+	stop_mt9t111_camera(&cssp_cam_struct.camera_board_info);
+
+
+	return 0;
+}
+
+static void cssp_cam_lock(struct vb2_queue *vq)
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
+	mutex_lock(&dev->mutex);
+}
+
+static void cssp_cam_unlock(struct vb2_queue *vq)
+{
+	struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
+	mutex_unlock(&dev->mutex);
+}
+
+/* ------------------------------------------------------------------
+	IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+
+	strcpy(cap->driver, "cssp_camera");
+	strcpy(cap->card, "cssp_camera");
+	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
+			    V4L2_CAP_READWRITE;
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	struct cssp_cam_fmt *fmt;
+
+	if (f->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	fmt = &formats[f->index];
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+
+	f->fmt.pix.width        = dev->width;
+	f->fmt.pix.height       = dev->height;
+	f->fmt.pix.field        = dev->field;
+	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * dev->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	if (dev->fmt->fourcc == V4L2_PIX_FMT_YUYV ||
+	    dev->fmt->fourcc == V4L2_PIX_FMT_UYVY)
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	else
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	struct cssp_cam_fmt *fmt;
+	enum v4l2_field field;
+
+	fmt = get_format(f);
+	if (!fmt) {
+		dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
+			f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	field = f->fmt.pix.field;
+
+	if (field == V4L2_FIELD_ANY) {
+		field = V4L2_FIELD_INTERLACED;
+	} else if (V4L2_FIELD_INTERLACED != field) {
+		dprintk(dev, 1, "Field type invalid.\n");
+		return -EINVAL;
+	}
+
+	f->fmt.pix.field = field;
+	v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
+			      &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	if (fmt->fourcc == V4L2_PIX_FMT_YUYV ||
+	    fmt->fourcc == V4L2_PIX_FMT_UYVY)
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	else
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	struct vb2_queue *q = &dev->vb_vidq;
+
+	int ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret < 0)
+		return ret;
+
+	if (vb2_is_streaming(q)) {
+		dprintk(dev, 1, "%s device busy\n", __func__);
+		return -EBUSY;
+	}
+
+	dev->fmt = get_format(f);
+	dev->width = f->fmt.pix.width;
+	dev->height = f->fmt.pix.height;
+	dev->field = f->fmt.pix.field;
+
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *p)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	return vb2_reqbufs(&dev->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	return vb2_querybuf(&dev->vb_vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	return vb2_qbuf(&dev->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	return vb2_streamon(&dev->vb_vidq, i);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	return vb2_streamoff(&dev->vb_vidq, i);
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+
+	v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name);
+	return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+	return 0;
+}
+
+/* only one input in this sample driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *inp)
+{
+	return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std = V4L2_STD_525_60;
+	sprintf(inp->name, "Camera %u", inp->index);
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+
+	*i = dev->input;
+
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+
+	return -EINVAL;
+
+	if (i == dev->input)
+		return 0;
+
+	dev->input = i;
+
+	return 0;
+}
+
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_CTRL:
+		return v4l2_event_subscribe(fh, sub, 0);
+	default:
+		return -EINVAL;
+	}
+}
+
+////---------------------------------------------------------
+
+
+
+static unsigned int video_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	struct v4l2_fh *fh = file->private_data;
+	struct vb2_queue *q = &dev->vb_vidq;
+	unsigned int res;
+
+	dprintk(dev, 1, "%s\n", __func__);
+	res = vb2_poll(q, file, wait);
+	if (v4l2_event_pending(fh))
+		res |= POLLPRI;
+	else
+		poll_wait(file, &fh->wait, wait);
+	return res;
+}
+
+static int video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct cssp_cam_dev *dev = video_drvdata(file);
+	int ret;
+
+	dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+	ret = vb2_mmap(&dev->vb_vidq, vma);
+	dprintk(dev, 1, "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;
+}
+
+
+
+//[PS] drv_read Test -->
+static ssize_t video_read(struct file* file, char __user* buf, size_t size, loff_t* offset)
+{
+	struct cssp_cam_dev *cam_dev = video_drvdata(file);
+
+	dprintk(cam_dev, 1, "read called\n");
+	return vb2_read(&cam_dev->vb_vidq, buf, size, offset, file->f_flags & O_NONBLOCK);
+}
+
+static int video_close(struct file *file)
+{
+	struct video_device  *vdev = video_devdata(file);
+	struct cssp_cam_dev *cam_dev = video_drvdata(file);
+
+	dprintk(cam_dev, 1, "close called (dev=%s), file %p\n",
+		video_device_node_name(vdev), file);
+
+	if (v4l2_fh_is_singular_file(file))
+		vb2_queue_release(&cam_dev->vb_vidq);
+	return v4l2_fh_release(file);
+}
+
+
+static int __init  video_probe(struct video_device ** v_dev)
+{
+
+	struct cssp_cam_dev *cam_dev;
+	struct video_device *vfd;
+	struct v4l2_ctrl_handler *hdl;
+	struct vb2_queue *q;
+	int ret = 0;
+
+
+	cam_dev = kzalloc(sizeof(*cam_dev), GFP_KERNEL);
+	if (!cam_dev)
+		return -ENOMEM;
+
+	snprintf(cam_dev->v4l2_dev.name, sizeof(cam_dev->v4l2_dev.name),
+			"%s-%03d", "cssp_camera", 0);
+	ret = v4l2_device_register(NULL, &cam_dev->v4l2_dev);
+	if (ret)
+		goto free_dev;
+
+	cam_dev->fmt = &formats[0];
+	cam_dev->width = 640;
+	cam_dev->height = 480;
+	hdl = &cam_dev->ctrl_handler;
+	v4l2_ctrl_handler_init(hdl, 0);
+
+	if (hdl->error) {
+		ret = hdl->error;
+		goto unreg_dev;
+	}
+	cam_dev->v4l2_dev.ctrl_handler = hdl;
+
+	/* initialize locks */
+	spin_lock_init(&cam_dev->slock);
+
+	/* initialize queue */
+	q = &cam_dev->vb_vidq;
+	memset(q, 0, sizeof(cam_dev->vb_vidq));
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+	q->drv_priv = cam_dev;
+	q->buf_struct_size = sizeof(struct cssp_cam_buffer);
+	q->ops = &cssp_cam_video_qops;
+	q->mem_ops = &vb2_vmalloc_memops;
+
+	//[TODO] videobuf_queue_dma_contig_init
+
+	vb2_queue_init(q);
+
+	mutex_init(&cam_dev->mutex);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&cam_dev->vidq.active);
+	init_waitqueue_head(&cam_dev->vidq.wq);
+
+	ret = -ENOMEM;
+	vfd = video_device_alloc();
+	if (!vfd)
+		goto unreg_dev;
+
+	*vfd = cssp_cam_template;
+	vfd->debug = debug;
+	vfd->v4l2_dev = &cam_dev->v4l2_dev;
+	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+
+	/*
+	 * Provide a mutex to v4l2 core. It will be used to protect
+	 * all fops and v4l2 ioctls.
+	 */
+	vfd->lock = &cam_dev->mutex;
+
+	*v_dev=vfd;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+	if (ret < 0)
+		goto rel_vdev;
+
+	video_set_drvdata(vfd, cam_dev);
+
+	/* Now that everything is fine, let's add it to device list */
+	list_add_tail(&cam_dev->cssp_cam_devlist, &cssp_cam_devlist);
+
+	if (video_nr != -1)
+		video_nr++;
+
+	cam_dev->vfd = vfd;
+	v4l2_info(&cam_dev->v4l2_dev, "V4L2 device registered as %s\n",
+	video_device_node_name(vfd));
+
+	return 0;
+
+
+rel_vdev:
+		video_device_release(vfd);
+unreg_dev:
+		v4l2_ctrl_handler_free(hdl);
+		v4l2_device_unregister(&cam_dev->v4l2_dev);
+free_dev:
+		kfree(cam_dev);
+		return ret;
+
+}
+
+
+static int __init  cssp_cam_probe(struct platform_device* pdev)
+{
+	int ret = 0;
+	struct cssp_cam_platform_data_s* cssp_cam_platform_data = NULL;
+
+	cssp_cam_platform_data = (struct cssp_cam_platform_data_s*) pdev->dev.platform_data;
+	if(cssp_cam_platform_data == NULL){
+
+		printk(KERN_ERR "[%s]: missing platform data", pdev->name);
+		return -1;
+	}
+
+	cssp_cam_struct.camera_board_info.platform_data = cssp_cam_platform_data->scl;
+	if(cssp_cam_platform_data->scl == NULL){
+
+		printk(KERN_ERR "[%s]: missing mt9t112 platform data", pdev->name);
+		return -1;
+	}
+
+	cssp_cam_struct.camera_ck = clk_get(NULL, cssp_cam_platform_data->cam_clk_name);
+	if (IS_ERR(cssp_cam_struct.camera_ck)) {
+		printk(KERN_ERR "[%s]: cannot clk_get clkout2_ck", pdev->name);
+		return -1;
+	}
+
+	ret = configure_cssp(pdev);
+	if(ret)
+		return ret;
+
+	ret = configure_edma_for_cssp_cam(pdev);
+	if(ret)
+		goto fail1;
+
+	ret = video_probe(&cssp_cam_struct.vdev);
+	if(ret)
+		goto fail2;
+
+
+	return ret;
+
+fail2:
+	edma_free_channel(cssp_cam_struct.dma_ch_out);
+	dma_free_coherent(&pdev->dev, cssp_cam_struct.dst_buff_size,
+			cssp_cam_struct.dma_dest_buff_virt, cssp_cam_struct.dma_tr_params.dst);
+
+fail1:
+	gpio_free(cssp_cam_struct.cssp_reset_pin);
+	iounmap((void*)cssp_cam_struct.gpmc_mem_base_virt);
+
+	return ret;
+
+}
+
+static int video_release(void)
+{
+	struct cssp_cam_dev *cam_dev;
+	struct list_head *list;
+
+	while (!list_empty(&cssp_cam_devlist)) {
+		list = cssp_cam_devlist.next;
+		list_del(list);
+		cam_dev = list_entry(list, struct cssp_cam_dev, cssp_cam_devlist);
+
+		v4l2_info(&cam_dev->v4l2_dev, "unregistering %s\n",
+			video_device_node_name(cam_dev->vfd));
+		video_unregister_device(cam_dev->vfd);
+		v4l2_device_unregister(&cam_dev->v4l2_dev);
+		v4l2_ctrl_handler_free(&cam_dev->ctrl_handler);
+		kfree(cam_dev);
+	}
+
+	return 0;
+}
+
+
+/*
+ * Function will exetute by rmmod command
+ */
+static int cssp_cam_remove(struct platform_device* pdev)
+{
+
+	iounmap((void*)cssp_cam_struct.gpmc_mem_base_virt);
+
+	gpio_free(cssp_cam_struct.cssp_reset_pin);
+
+	edma_free_channel(cssp_cam_struct.dma_ch_out);
+
+	dma_free_coherent(&pdev->dev, cssp_cam_struct.dst_buff_size,
+			cssp_cam_struct.dma_dest_buff_virt, cssp_cam_struct.dma_tr_params.dst);
+
+
+	if(cssp_cam_struct.camera_client != NULL)
+		i2c_unregister_device(cssp_cam_struct.camera_client);
+
+
+
+	printk(KERN_INFO "[%s]: removed\n",pdev->name);
+
+	return 0;
+}
+
+
+static struct platform_driver cssp_cam_driver = {
+	.probe		= cssp_cam_probe,
+	.remove		= __devexit_p(cssp_cam_remove),
+	.driver		= {
+		.name	= "cssp-camera",
+		.owner	= THIS_MODULE,
+	},
+};
+
+
+static int __init cssp_cam_init(void)
+{
+	return platform_driver_register(&cssp_cam_driver);
+}
+
+static void __exit cssp_cam_exit(void)
+{
+	platform_driver_unregister(&cssp_cam_driver);
+	video_release();
+}
+
+
+module_init(cssp_cam_init);
+module_exit(cssp_cam_exit);
+
+/*
+ * Macros sets license, author and description
+ */
+MODULE_LICENSE("GPLv2");
+MODULE_AUTHOR("Damian Eppel <damian.eppel@teleca.com>, Przemek Szewczyk <przemek.szewczyk@teleca.com>");
+
diff --git a/drivers/media/video/cssp_camera/cssp_camera.h b/drivers/media/video/cssp_camera/cssp_camera.h
new file mode 100644
index 0000000..e97f1e5
--- /dev/null
+++ b/drivers/media/video/cssp_camera/cssp_camera.h
@@ -0,0 +1,235 @@
+/*
+ * cssp-camera driver
+ *
+ * Based on Vivi driver
+ *
+ * Copyright (C) 2012 QuickLogic Corp.
+ * Damian Eppel <damian.eppel@teleca.com>
+ * Przemek Szewczyk <przemek.szewczyk@teleca.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#ifndef CSSP_CAMERA_H
+#define  CSSP_CAMERA_H
+
+
+static unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
+
+static unsigned debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+static unsigned int vid_limit = 1;
+module_param(vid_limit, uint, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
+#define dprintk(dev, level, fmt, arg...) \
+	v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
+
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
+
+#define MAX_WIDTH VGA_WIDTH
+#define MAX_HEIGHT VGA_HEIGHT
+
+#define VGA_RES (VGA_WIDTH*VGA_HEIGHT)
+#define BYTES_PER_PIXEL (2)
+
+/* PaRAM.opt: */
+#define TCC(v) ((v & 0x3f) << 12)
+/* PaRAM.a_b_cnt: */
+#define ACNT(v) ((v & 0xffff) << 0)
+#define BCNT(v) ((v & 0xffff) << 16)
+/* PaRAM.src_dst_bidx: */
+#define SRCBIDX(v) ((v & 0xffff) << 0)
+#define DSTBIDX(v) ((v & 0xffff) << 16)
+/* PaRAM.link_bcntrld: */
+#define LINK(v) ((v & 0xffff) << 0)
+#define BCNTRLD(v) ((v & 0xffff) << 16)
+/* PaRAM.src_dst_cidx: */
+#define SRCCIDX(v) ((v & 0xffff) << 0)
+#define DSTCIDX(v) ((v & 0xffff) << 16)
+/* PaRAM.ccnt: */
+#define CCNT(v) ((v & 0xffff))
+
+
+typedef struct
+{
+	struct i2c_client* camera_client;
+	struct i2c_board_info camera_board_info;
+	unsigned int gpmc_mem_base_virt;
+	unsigned int gpmc_mem_base_phys;
+
+	struct edmacc_param dma_tr_params;
+	void * dma_dest_buff_virt;
+	int dma_ch_out;
+	u64 dma_mask;
+	int frame_cnt;
+	int dst_buff_size;
+	int  cssp_reset_pin;
+	struct clk* camera_ck;
+
+	struct video_device * vdev;
+
+} cssp_cam_struct_t;
+
+struct cssp_cam_platform_data_s
+{
+	struct soc_camera_link* scl;
+	const char* cam_clk_name;
+	int dma_ch;
+	int gpio_cssp_reset_pin;
+
+};
+
+
+/* ------------------------------------------------------------------
+	video Basic structures
+   ------------------------------------------------------------------*/
+
+struct cssp_cam_fmt {
+	char  *name;
+	u32   fourcc;          /* v4l2 format id */
+	int   depth;
+};
+
+
+/* buffer for one video frame */
+struct cssp_cam_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct vb2_buffer	vb;
+	struct list_head	list;
+	struct cssp_cam_fmt *fmt;
+};
+
+struct cssp_cam_dmaqueue {
+	struct list_head       active;
+
+	/* thread for generating video stream*/
+	struct task_struct         *kthread;
+	wait_queue_head_t          wq;
+	/* Counters to control fps rate */
+	int                        frame;
+	int                        ini_jiffies;
+};
+
+static LIST_HEAD(cssp_cam_devlist);
+
+struct cssp_cam_dev {
+	struct list_head       cssp_cam_devlist;
+	struct v4l2_device 	   v4l2_dev;
+	struct v4l2_ctrl_handler   ctrl_handler;
+
+	spinlock_t             slock;
+	struct mutex		   mutex;
+
+	/* various device info */
+	struct video_device        *vfd;
+
+	struct cssp_cam_dmaqueue       vidq;
+
+	/* Input Number */
+	int			   input;
+
+	/* video capture */
+	struct cssp_cam_fmt            *fmt;
+	unsigned int               width, height;
+	struct vb2_queue	   vb_vidq;
+	enum v4l2_field		   field;
+	unsigned int		   field_count;
+
+};
+
+/**************************************************************************/
+
+static int video_close(struct file *file);
+static ssize_t video_read(struct file* file, char __user* buf, size_t size, loff_t* offset);
+static unsigned int video_poll(struct file *file, struct poll_table_struct *wait);
+static int video_mmap(struct file *file, struct vm_area_struct *vma);
+static int video_release(void);
+
+
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[]);
+
+static int buffer_init(struct vb2_buffer *vb);
+
+static int buffer_prepare(struct vb2_buffer *vb);
+
+static int buffer_finish(struct vb2_buffer *vb);
+
+static void buffer_cleanup(struct vb2_buffer *vb);
+
+static void buffer_queue(struct vb2_buffer *vb);
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count);
+
+static int stop_streaming(struct vb2_queue *vq);
+
+static void cssp_cam_lock(struct vb2_queue *vq);
+
+static void cssp_cam_unlock(struct vb2_queue *vq);
+
+
+
+
+/* ------------------------------------------------------------------
+	IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap);
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f);
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f);
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+			struct v4l2_format *f);
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f);
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *p);
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p);
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p);
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p);
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i);
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i);
+
+static int vidioc_log_status(struct file *file, void *priv);
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i);
+
+/* only one input in this sample driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *inp);
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i);
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i);
+
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub);
+
+
+#endif //CSSP_CAMERA_H
-- 
1.7.10

