linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/14] Media Controller capture driver for DM365
@ 2012-09-14 12:46 Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 01/14] davinci: vpfe: add dm3xx IPIPEIF hardware support module Prabhakar Lad
                   ` (14 more replies)
  0 siblings, 15 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Lad, Prabhakar

From: Lad, Prabhakar <prabhakar.lad@ti.com>

This patch set adds media controller based capture driver for
DM365.

This driver bases its design on Laurent Pinchart's Media Controller Design
whose patches for Media Controller and subdev enhancements form the base.
The driver also takes copious elements taken from Laurent Pinchart and
others' OMAP ISP driver based on Media Controller. So thank you all the
people who are responsible for the Media Controller and the OMAP ISP driver.

Also, the core functionality of the driver comes from the arago vpfe capture
driver of which the CCDC capture was based on V4L2, with other drivers like
Previwer, and Resizer.

The current driver caters to dm6446,dm355 and dm365 of which the current
implementation works for dm365. The three VPFE IPs have some common elements
in terms of some high level functionality but there are differences in terms
of register definitions and some core blocks.

The individual specifications for each of these can be found here:
dm365  vpfe: http://www.ti.com/litv/pdf/sprufg8c
dm6446 vpfe: http://www.ti.com/litv/pdf/sprue38h
dm355  vpfe: http://www.ti.com/litv/pdf/spruf71a

This patch set has undergone reviewed several revisions.
(http://davinci-linux-open-source.1494791.n2.nabble.com/
RESEND-RFC-PATCH-v4-00-15-RFC-for-Media-Controller-capture-
driver-for-DM365-td7003648.html). This patches might be appearing
new due to the new folder structure changes to video drivers.

Manjunath Hadli (14):
  davinci: vpfe: add dm3xx IPIPEIF hardware support module
  davinci: vpfe: add IPIPE hardware layer support
  davinci: vpfe: add IPIPE support for media controller driver
  davinci: vpfe: add support for CCDC hardware for dm365
  davinci: vpfe: add ccdc driver with media controller interface
  davinci: vpfe: add v4l2 video driver support
  davinci: vpfe: v4l2 capture driver with media interface
  davinci: vpfe: previewer driver based on v4l2 media controller
    framework
  davinci: vpfe: resizer driver based on media framework
  dm365: vpss: setup ISP registers
  dm365: vpss: set vpss clk ctrl
  dm365: vpss: add vpss helper functions to be used in the main driver
    for setting hardware parameters
  davinci: vpfe: build infrastructure for dm365
  [media] davinci: vpfe: Add documentation

 Documentation/video4linux/davinci-vpfe-mc.txt    |   95 +
 drivers/media/platform/davinci/Kconfig           |   40 +-
 drivers/media/platform/davinci/Makefile          |    9 +
 drivers/media/platform/davinci/ccdc_hw_device.h  |   11 +-
 drivers/media/platform/davinci/dm355_ccdc.c      |    2 +-
 drivers/media/platform/davinci/dm365_ccdc.c      | 1424 +++++++++
 drivers/media/platform/davinci/dm365_ccdc.h      |  137 +
 drivers/media/platform/davinci/dm365_ccdc_regs.h |  314 ++
 drivers/media/platform/davinci/dm365_def_para.c  |  294 ++
 drivers/media/platform/davinci/dm365_def_para.h  |   49 +
 drivers/media/platform/davinci/dm365_ipipe.c     | 3673 ++++++++++++++++++++++
 drivers/media/platform/davinci/dm365_ipipe.h     |  430 +++
 drivers/media/platform/davinci/dm365_ipipe_hw.c  |  936 ++++++
 drivers/media/platform/davinci/dm365_ipipe_hw.h  |  538 ++++
 drivers/media/platform/davinci/dm3xx_ipipeif.c   |  318 ++
 drivers/media/platform/davinci/dm3xx_ipipeif.h   |  262 ++
 drivers/media/platform/davinci/dm644x_ccdc.c     |    2 +-
 drivers/media/platform/davinci/imp_hw_if.h       |  180 ++
 drivers/media/platform/davinci/isif.c            |    2 +-
 drivers/media/platform/davinci/vpfe_capture.c    |    2 +-
 drivers/media/platform/davinci/vpfe_ccdc.c       |  903 ++++++
 drivers/media/platform/davinci/vpfe_ccdc.h       |   87 +
 drivers/media/platform/davinci/vpfe_imp_common.h |   84 +
 drivers/media/platform/davinci/vpfe_mc_capture.c |  764 +++++
 drivers/media/platform/davinci/vpfe_mc_capture.h |  104 +
 drivers/media/platform/davinci/vpfe_previewer.c  | 1041 ++++++
 drivers/media/platform/davinci/vpfe_previewer.h  |   71 +
 drivers/media/platform/davinci/vpfe_resizer.c    | 1080 +++++++
 drivers/media/platform/davinci/vpfe_resizer.h    |   66 +
 drivers/media/platform/davinci/vpfe_video.c      | 1725 ++++++++++
 drivers/media/platform/davinci/vpfe_video.h      |  150 +
 drivers/media/platform/davinci/vpss.c            |   56 +
 include/linux/davinci_vpfe.h                     |  929 ++++++
 include/linux/dm365_ccdc.h                       |  592 ++++
 include/linux/dm3xx_ipipeif.h                    |   62 +
 include/media/davinci/vpfe.h                     |   84 +
 include/media/davinci/vpss.h                     |   16 +
 37 files changed, 16518 insertions(+), 14 deletions(-)
 create mode 100644 Documentation/video4linux/davinci-vpfe-mc.txt
 create mode 100644 drivers/media/platform/davinci/dm365_ccdc.c
 create mode 100644 drivers/media/platform/davinci/dm365_ccdc.h
 create mode 100644 drivers/media/platform/davinci/dm365_ccdc_regs.h
 create mode 100644 drivers/media/platform/davinci/dm365_def_para.c
 create mode 100644 drivers/media/platform/davinci/dm365_def_para.h
 create mode 100644 drivers/media/platform/davinci/dm365_ipipe.c
 create mode 100644 drivers/media/platform/davinci/dm365_ipipe.h
 create mode 100644 drivers/media/platform/davinci/dm365_ipipe_hw.c
 create mode 100644 drivers/media/platform/davinci/dm365_ipipe_hw.h
 create mode 100644 drivers/media/platform/davinci/dm3xx_ipipeif.c
 create mode 100644 drivers/media/platform/davinci/dm3xx_ipipeif.h
 create mode 100644 drivers/media/platform/davinci/imp_hw_if.h
 create mode 100644 drivers/media/platform/davinci/vpfe_ccdc.c
 create mode 100644 drivers/media/platform/davinci/vpfe_ccdc.h
 create mode 100644 drivers/media/platform/davinci/vpfe_imp_common.h
 create mode 100644 drivers/media/platform/davinci/vpfe_mc_capture.c
 create mode 100644 drivers/media/platform/davinci/vpfe_mc_capture.h
 create mode 100644 drivers/media/platform/davinci/vpfe_previewer.c
 create mode 100644 drivers/media/platform/davinci/vpfe_previewer.h
 create mode 100644 drivers/media/platform/davinci/vpfe_resizer.c
 create mode 100644 drivers/media/platform/davinci/vpfe_resizer.h
 create mode 100644 drivers/media/platform/davinci/vpfe_video.c
 create mode 100644 drivers/media/platform/davinci/vpfe_video.h
 create mode 100644 include/linux/davinci_vpfe.h
 create mode 100644 include/linux/dm365_ccdc.h
 create mode 100644 include/linux/dm3xx_ipipeif.h
 create mode 100644 include/media/davinci/vpfe.h

-- 
1.7.4.1


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 01/14] davinci: vpfe: add dm3xx IPIPEIF hardware support module
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-19 22:01   ` Laurent Pinchart
  2012-09-14 12:46 ` [PATCH 02/14] davinci: vpfe: add IPIPE hardware layer support Prabhakar Lad
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

add support for dm3xx IPIPEIF hardware setup. This is the
lowest software layer for the dm3x vpfe driver which directly
accesses hardware. Add support for features like default
pixel correction, dark frame substraction and hardware setup.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/dm3xx_ipipeif.c |  318 ++++++++++++++++++++++++
 drivers/media/platform/davinci/dm3xx_ipipeif.h |  262 +++++++++++++++++++
 include/linux/dm3xx_ipipeif.h                  |   62 +++++
 3 files changed, 642 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/platform/davinci/dm3xx_ipipeif.c
 create mode 100644 drivers/media/platform/davinci/dm3xx_ipipeif.h
 create mode 100644 include/linux/dm3xx_ipipeif.h

diff --git a/drivers/media/platform/davinci/dm3xx_ipipeif.c b/drivers/media/platform/davinci/dm3xx_ipipeif.c
new file mode 100644
index 0000000..7961a74
--- /dev/null
+++ b/drivers/media/platform/davinci/dm3xx_ipipeif.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/platform_device.h>
+
+#include "dm3xx_ipipeif.h"
+
+static void *__iomem ipipeif_base_addr;
+
+static inline u32 regr_if(u32 offset)
+{
+	return readl(ipipeif_base_addr + offset);
+}
+
+static inline void regw_if(u32 val, u32 offset)
+{
+	writel(val, ipipeif_base_addr + offset);
+}
+
+void ipipeif_set_enable()
+{
+	regw_if(1, IPIPEIF_ENABLE);
+}
+
+u32 ipipeif_get_enable(void)
+{
+	return regr_if(IPIPEIF_ENABLE);
+}
+
+int ipipeif_set_address(struct ipipeif *params, unsigned int address)
+{
+	u32 val;
+
+	if (params->source == 0)
+		return -EINVAL;
+
+	val = (params->adofs >> 5) & IPIPEIF_ADOFS_LSB_MASK;
+	regw_if(val, IPIPEIF_ADOFS);
+
+	/* lower sixteen bit */
+	val = (address >> IPIPEIF_ADDRL_SHIFT) & IPIPEIF_ADDRL_MASK;
+	regw_if(val, IPIPEIF_ADDRL);
+
+	/* upper next seven bit */
+	val = (address >> IPIPEIF_ADDRU_SHIFT) & IPIPEIF_ADDRU_MASK;
+	regw_if(val, IPIPEIF_ADDRU);
+
+	return 0;
+}
+
+static void ipipeif_config_dpc(struct ipipeif_dpc *dpc)
+{
+	u32 val = 0;
+
+	if (dpc->en) {
+		val = (dpc->en & 1) << IPIPEIF_DPC2_EN_SHIFT;
+		val |= dpc->thr & IPIPEIF_DPC2_THR_MASK;
+	}
+
+	regw_if(val, IPIPEIF_DPC2);
+}
+
+#define RD_DATA_15_2	0x7
+
+/*
+ * ipipeif_hw_setup() - This function sets up IPIPEIF
+ */
+int ipipeif_hw_setup(struct ipipeif *params, int device_type)
+{
+	enum v4l2_mbus_pixelcode isif_port_if;
+	unsigned int val;
+
+	if (params == NULL)
+		return -EINVAL;
+
+	/* Enable clock to IPIPEIF and IPIPE */
+	if (device_type == DM365)
+		vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
+
+	/* Combine all the fields to make CFG1 register of IPIPEIF */
+	val = params->mode << ONESHOT_SHIFT;
+	val |= params->source << INPSRC_SHIFT;
+	val |= params->clock_select << CLKSEL_SHIFT;
+	val |= params->avg_filter << AVGFILT_SHIFT;
+	val |= params->decimation << DECIM_SHIFT;
+
+	if (device_type == DM355) {
+		val |= params->var.if_base.ialaw << IALAW_SHIFT;
+		val |= params->var.if_base.pack_mode << PACK8IN_SHIFT;
+		val |= params->var.if_base.clk_div << CLKDIV_SHIFT;
+		val |= params->var.if_base.data_shift << DATASFT_SHIFT;
+	} else {
+		/* DM365 IPIPE 5.1 */
+		val |= params->var.if_5_1.pack_mode << PACK8IN_SHIFT;
+		val |= params->var.if_5_1.source1 << INPSRC1_SHIFT;
+		if (params->source != IPIPEIF_SDRAM_YUV)
+			val |= params->var.if_5_1.data_shift << DATASFT_SHIFT;
+		else
+			val &= ~(RD_DATA_15_2 << DATASFT_SHIFT);
+	}
+	regw_if(val, IPIPEIF_CFG1);
+
+	switch (params->source) {
+	case IPIPEIF_CCDC:
+		regw_if(params->gain, IPIPEIF_GAIN);
+		break;
+	case IPIPEIF_SDRAM_RAW:
+	case IPIPEIF_CCDC_DARKFM:
+		regw_if(params->gain, IPIPEIF_GAIN);
+		/* fall through */
+	case IPIPEIF_SDRAM_YUV:
+		val |= params->var.if_5_1.data_shift << DATASFT_SHIFT;
+		regw_if(params->glob_hor_size, IPIPEIF_PPLN);
+		regw_if(params->glob_ver_size, IPIPEIF_LPFR);
+		regw_if(params->hnum, IPIPEIF_HNUM);
+		regw_if(params->vnum, IPIPEIF_VNUM);
+		break;
+	default:
+		/* Do nothing */
+		return -EINVAL;
+	}
+
+	/*check if decimation is enable or not */
+	if (params->decimation)
+		regw_if(params->rsz, IPIPEIF_RSZ);
+
+	if (device_type != DM365)
+		return 0;
+
+	/* Setup sync alignment and initial rsz position */
+	val = params->var.if_5_1.align_sync & 1;
+	val <<= IPIPEIF_INIRSZ_ALNSYNC_SHIFT;
+	val |= params->var.if_5_1.rsz_start & IPIPEIF_INIRSZ_MASK;
+	regw_if(val, IPIPEIF_INIRSZ);
+
+	/* Enable DPCM decompression */
+	switch (params->source) {
+	case IPIPEIF_SDRAM_RAW:
+		val = 0;
+		if (params->var.if_5_1.dpcm.en) {
+			val = params->var.if_5_1.dpcm.en & 1;
+			val |= (params->var.if_5_1.dpcm.type & 1) <<
+				IPIPEIF_DPCM_BITS_SHIFT;
+			val |= (params->var.if_5_1.dpcm.pred & 1) <<
+				IPIPEIF_DPCM_PRED_SHIFT;
+		}
+		regw_if(val, IPIPEIF_DPCM);
+
+		/* set DPC */
+		ipipeif_config_dpc(&params->var.if_5_1.dpc);
+
+		regw_if(params->var.if_5_1.clip, IPIPEIF_OCLIP);
+		/* fall through for SDRAM YUV mode */
+		isif_port_if = params->var.if_5_1.isif_port.if_type;
+		/* configure CFG2 */
+		val = regr_if(IPIPEIF_CFG2);
+		switch (isif_port_if) {
+		case V4L2_MBUS_FMT_YUYV8_1X16:
+			RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
+			SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
+			regw_if(val, IPIPEIF_CFG2);
+			break;
+		default:
+			RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
+			RESETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
+			regw_if(val, IPIPEIF_CFG2);
+			break;
+		}
+		break;
+	case IPIPEIF_SDRAM_YUV:
+		/* Set clock divider */
+		if (params->clock_select == IPIPEIF_SDRAM_CLK) {
+			val = regr_if(IPIPEIF_CLKDIV);
+			val |= (params->var.if_5_1.clk_div.m - 1) <<
+				IPIPEIF_CLKDIV_M_SHIFT;
+			val |= (params->var.if_5_1.clk_div.n - 1);
+			regw_if(val, IPIPEIF_CLKDIV);
+		}
+		break;
+	case IPIPEIF_CCDC:
+	case IPIPEIF_CCDC_DARKFM:
+		/* set DPC */
+		ipipeif_config_dpc(&params->var.if_5_1.dpc);
+
+		/* Set DF gain & threshold control */
+		val = 0;
+		if (params->var.if_5_1.df_gain_en) {
+			val = params->var.if_5_1.df_gain_thr &
+				IPIPEIF_DF_GAIN_THR_MASK;
+			regw_if(val, IPIPEIF_DFSGTH);
+			val = (params->var.if_5_1.df_gain_en & 1) <<
+				IPIPEIF_DF_GAIN_EN_SHIFT;
+			val |= params->var.if_5_1.df_gain &
+				IPIPEIF_DF_GAIN_MASK;
+		}
+		regw_if(val, IPIPEIF_DFSGVL);
+		isif_port_if = params->var.if_5_1.isif_port.if_type;
+
+		/* configure CFG2 */
+		val = params->var.if_5_1.isif_port.hdpol <<
+			IPIPEIF_CFG2_HDPOL_SHIFT;
+		val |= params->var.if_5_1.isif_port.vdpol <<
+			IPIPEIF_CFG2_VDPOL_SHIFT;
+
+		switch (isif_port_if) {
+		case V4L2_MBUS_FMT_YUYV8_1X16:
+		case V4L2_MBUS_FMT_YUYV10_1X20:
+			RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
+			SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
+			break;
+		case V4L2_MBUS_FMT_YUYV8_2X8:
+		case V4L2_MBUS_FMT_Y8_1X8:
+		case V4L2_MBUS_FMT_YUYV10_2X10:
+			SETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
+			SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
+			val |= params->var.if_5_1.chroma_phase <<
+				IPIPEIF_CFG2_YUV8P_SHIFT;
+			break;
+		default:
+			/* Bayer */
+			regw_if(params->var.if_5_1.clip,
+				IPIPEIF_OCLIP);
+		}
+		regw_if(val, IPIPEIF_CFG2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __devinit dm3xx_ipipeif_probe(struct platform_device *pdev)
+{
+	static resource_size_t  res_len;
+	struct resource *res;
+	int status;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOENT;
+
+	res_len = resource_size(res);
+
+	res = request_mem_region(res->start, res_len, res->name);
+	if (!res)
+		return -EBUSY;
+
+	ipipeif_base_addr = ioremap_nocache(res->start, res_len);
+	if (!ipipeif_base_addr) {
+		status = -EBUSY;
+		goto fail;
+	}
+	return 0;
+
+fail:
+	release_mem_region(res->start, res_len);
+
+	return status;
+}
+
+static int dm3xx_ipipeif_remove(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	iounmap(ipipeif_base_addr);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res)
+		release_mem_region(res->start, resource_size(res));
+	return 0;
+}
+
+static struct platform_driver dm3xx_ipipeif_driver = {
+	.driver = {
+		.name   = "dm3xx_ipipeif",
+		.owner = THIS_MODULE,
+	},
+	.remove = __devexit_p(dm3xx_ipipeif_remove),
+	.probe = dm3xx_ipipeif_probe,
+};
+
+static int dm3xx_ipipeif_init(void)
+{
+	return platform_driver_register(&dm3xx_ipipeif_driver);
+}
+
+static void dm3xx_ipipeif_exit(void)
+{
+	platform_driver_unregister(&dm3xx_ipipeif_driver);
+}
+
+module_init(dm3xx_ipipeif_init);
+module_exit(dm3xx_ipipeif_exit);
+
+MODULE_LICENSE("GPL2");
diff --git a/drivers/media/platform/davinci/dm3xx_ipipeif.h b/drivers/media/platform/davinci/dm3xx_ipipeif.h
new file mode 100644
index 0000000..ac8fcc7
--- /dev/null
+++ b/drivers/media/platform/davinci/dm3xx_ipipeif.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _DM3XX_IPIPEIF_H
+#define _DM3XX_IPIPEIF_H
+
+#include <linux/kernel.h>
+#include <linux/dm3xx_ipipeif.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#include <media/davinci/vpfe_types.h>
+#include <media/davinci/vpss.h>
+
+/* Used to shift input image data based on the data lines connected
+ * to parallel port
+ */
+/* IPIPE base specific types */
+enum ipipeif_data_shift {
+	IPIPEIF_BITS15_2,
+	IPIPEIF_BITS14_1,
+	IPIPEIF_BITS13_0,
+	IPIPEIF_BITS12_0,
+	IPIPEIF_BITS11_0,
+	IPIPEIF_BITS10_0,
+	IPIPEIF_BITS9_0
+};
+
+enum ipipeif_clkdiv {
+	IPIPEIF_DIVIDE_HALF,
+	IPIPEIF_DIVIDE_THIRD,
+	IPIPEIF_DIVIDE_FOURTH,
+	IPIPEIF_DIVIDE_FIFTH,
+	IPIPEIF_DIVIDE_SIXTH,
+	IPIPEIF_DIVIDE_EIGHTH,
+	IPIPEIF_DIVIDE_SIXTEENTH,
+	IPIPEIF_DIVIDE_THIRTY
+};
+
+enum ipipeif_clock {
+	IPIPEIF_PIXCEL_CLK,
+	IPIPEIF_SDRAM_CLK
+};
+
+enum ipipeif_pack_mode  {
+	IPIPEIF_PACK_16_BIT,
+	IPIPEIF_PACK_8_BIT
+};
+
+enum ipipe_oper_mode {
+	IPIPEIF_CONTINUOUS,
+	IPIPEIF_ONE_SHOT
+};
+
+enum ipipeif_5_1_pack_mode  {
+	IPIPEIF_5_1_PACK_16_BIT,
+	IPIPEIF_5_1_PACK_8_BIT,
+	IPIPEIF_5_1_PACK_8_BIT_A_LAW,
+	IPIPEIF_5_1_PACK_12_BIT
+};
+
+enum  ipipeif_avg_filter {
+	IPIPEIF_AVG_OFF,
+	IPIPEIF_AVG_ON
+};
+
+enum  ipipeif_input_source {
+	IPIPEIF_CCDC,
+	IPIPEIF_SDRAM_RAW,
+	IPIPEIF_CCDC_DARKFM,
+	IPIPEIF_SDRAM_YUV
+};
+
+enum ipipeif_ialaw {
+	IPIPEIF_ALAW_OFF,
+	IPIPEIF_ALAW_ON
+};
+
+struct ipipeif_base {
+	enum ipipeif_ialaw ialaw;
+	enum ipipeif_pack_mode pack_mode;
+	enum ipipeif_data_shift data_shift;
+	enum ipipeif_clkdiv clk_div;
+};
+
+enum  ipipeif_input_src1 {
+	IPIPEIF_SRC1_PARALLEL_PORT,
+	IPIPEIF_SRC1_SDRAM_RAW,
+	IPIPEIF_SRC1_ISIF_DARKFM,
+	IPIPEIF_SRC1_SDRAM_YUV
+};
+
+enum ipipeif_dpcm_type {
+	IPIPEIF_DPCM_8BIT_10BIT,
+	IPIPEIF_DPCM_8BIT_12BIT
+};
+
+struct ipipeif_dpcm_decomp {
+	unsigned char en;
+	enum ipipeif_dpcm_type type;
+	enum v4l2_dpcm_predictor pred;
+};
+
+enum ipipeif_dfs_dir {
+	IPIPEIF_PORT_MINUS_SDRAM,
+	IPIPEIF_SDRAM_MINUS_PORT
+};
+
+struct ipipeif_5_1 {
+	enum ipipeif_5_1_pack_mode pack_mode;
+	enum ipipeif_5_1_data_shift data_shift;
+	enum ipipeif_input_src1 source1;
+	struct ipipeif_5_1_clkdiv clk_div;
+	/* Defect pixel correction */
+	struct ipipeif_dpc dpc;
+	/* DPCM decompression */
+	struct ipipeif_dpcm_decomp dpcm;
+	/* ISIF port pixel order */
+	enum ipipeif_chroma_phase chroma_phase;
+	/* interface parameters from isif */
+	struct vpfe_hw_if_param isif_port;
+	/* clipped to this value */
+	unsigned short clip;
+	/* Align HSync and VSync to rsz_start */
+	unsigned char align_sync;
+	/* resizer start position */
+	unsigned int rsz_start;
+	/* DF gain enable */
+	unsigned char df_gain_en;
+	/* DF gain value */
+	unsigned short df_gain;
+	/* DF gain threshold value */
+	unsigned short df_gain_thr;
+};
+
+/* ipipeif structures common to DM350 and DM365 used by ipipeif API */
+struct ipipeif {
+	enum ipipe_oper_mode mode;
+	enum ipipeif_input_source source;
+	enum ipipeif_clock clock_select;
+	unsigned int glob_hor_size;
+	unsigned int glob_ver_size;
+	unsigned int hnum;
+	unsigned int vnum;
+	unsigned int adofs;
+	unsigned char rsz;
+	enum ipipeif_decimation decimation;
+	enum ipipeif_avg_filter avg_filter;
+	unsigned short gain;
+	/* IPIPE 5.1 */
+	union var_part {
+		struct ipipeif_base if_base;
+		struct ipipeif_5_1  if_5_1;
+	} var;
+};
+
+/* IPIPEIF Register Offsets from the base address */
+#define IPIPEIF_ENABLE			0x00
+#define IPIPEIF_CFG1			0x04
+#define IPIPEIF_PPLN			0x08
+#define IPIPEIF_LPFR			0x0c
+#define IPIPEIF_HNUM			0x10
+#define IPIPEIF_VNUM			0x14
+#define IPIPEIF_ADDRU			0x18
+#define IPIPEIF_ADDRL			0x1c
+#define IPIPEIF_ADOFS			0x20
+#define IPIPEIF_RSZ			0x24
+#define IPIPEIF_GAIN			0x28
+
+/* Below registers are available only on IPIPE 5.1 */
+#define IPIPEIF_DPCM			0x2c
+#define IPIPEIF_CFG2			0x30
+#define IPIPEIF_INIRSZ			0x34
+#define IPIPEIF_OCLIP			0x38
+#define IPIPEIF_DTUDF			0x3c
+#define IPIPEIF_CLKDIV			0x40
+#define IPIPEIF_DPC1			0x44
+#define IPIPEIF_DPC2			0x48
+#define IPIPEIF_DFSGVL			0x4c
+#define IPIPEIF_DFSGTH			0x50
+#define IPIPEIF_RSZ3A			0x54
+#define IPIPEIF_INIRSZ3A		0x58
+#define IPIPEIF_RSZ_MIN			16
+#define IPIPEIF_RSZ_MAX			112
+#define IPIPEIF_RSZ_CONST		16
+#define SETBIT(reg, bit)   (reg = ((reg) | ((0x00000001)<<(bit))))
+#define RESETBIT(reg, bit) (reg = ((reg) & (~(0x00000001<<(bit)))))
+
+#define IPIPEIF_ADOFS_LSB_MASK		0x1ff
+#define IPIPEIF_ADOFS_LSB_SHIFT		5
+#define IPIPEIF_ADOFS_MSB_MASK		0x200
+#define IPIPEIF_ADDRU_MASK		0x7ff
+#define IPIPEIF_ADDRL_SHIFT		5
+#define IPIPEIF_ADDRL_MASK		0xffff
+#define IPIPEIF_ADDRU_SHIFT		21
+#define IPIPEIF_ADDRMSB_SHIFT		31
+#define IPIPEIF_ADDRMSB_LEFT_SHIFT	10
+
+/* CFG1 Masks and shifts */
+#define ONESHOT_SHIFT			0
+#define DECIM_SHIFT			1
+#define INPSRC_SHIFT			2
+#define CLKDIV_SHIFT			4
+#define AVGFILT_SHIFT			7
+#define PACK8IN_SHIFT			8
+#define IALAW_SHIFT			9
+#define CLKSEL_SHIFT			10
+#define DATASFT_SHIFT			11
+#define INPSRC1_SHIFT			14
+
+/* DPC2 */
+#define IPIPEIF_DPC2_EN_SHIFT		12
+#define IPIPEIF_DPC2_THR_MASK		0xfff
+/* Applicable for IPIPE 5.1 */
+#define IPIPEIF_DF_GAIN_EN_SHIFT	10
+#define IPIPEIF_DF_GAIN_MASK		0x3ff
+#define IPIPEIF_DF_GAIN_THR_MASK	0xfff
+/* DPCM */
+#define IPIPEIF_DPCM_BITS_SHIFT		2
+#define IPIPEIF_DPCM_PRED_SHIFT		1
+/* CFG2 */
+#define IPIPEIF_CFG2_HDPOL_SHIFT	1
+#define IPIPEIF_CFG2_VDPOL_SHIFT	2
+#define IPIPEIF_CFG2_YUV8_SHIFT		6
+#define IPIPEIF_CFG2_YUV16_SHIFT	3
+#define IPIPEIF_CFG2_YUV8P_SHIFT	7
+
+/* INIRSZ */
+#define IPIPEIF_INIRSZ_ALNSYNC_SHIFT	13
+#define IPIPEIF_INIRSZ_MASK		0x1fff
+
+/* CLKDIV */
+#define IPIPEIF_CLKDIV_M_SHIFT		8
+
+void ipipeif_set_enable(void);
+u32 ipipeif_get_enable(void);
+int ipipeif_hw_setup(struct ipipeif *if_params, int device_type);
+int ipipeif_set_address(struct ipipeif *if_params, unsigned int address);
+
+#define DM355	0
+#define DM365	1
+
+#endif
diff --git a/include/linux/dm3xx_ipipeif.h b/include/linux/dm3xx_ipipeif.h
new file mode 100644
index 0000000..1c1a830
--- /dev/null
+++ b/include/linux/dm3xx_ipipeif.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _DM3XX_IPIPEIF_INCLUDE_H
+#define _DM3XX_IPIPEIF_INCLUDE_H
+
+#include <media/davinci/vpfe_types.h>
+#include <media/davinci/vpfe.h>
+
+/* clockdiv for IPIPE 5.1 */
+struct ipipeif_5_1_clkdiv {
+	unsigned char m;
+	unsigned char n;
+};
+
+/* data shift for IPIPE 5.1 */
+enum ipipeif_5_1_data_shift {
+	IPIPEIF_5_1_BITS11_0,
+	IPIPEIF_5_1_BITS10_0,
+	IPIPEIF_5_1_BITS9_0,
+	IPIPEIF_5_1_BITS8_0,
+	IPIPEIF_5_1_BITS7_0,
+	IPIPEIF_5_1_BITS15_4,
+};
+
+enum ipipeif_decimation {
+	IPIPEIF_DECIMATION_OFF,
+	IPIPEIF_DECIMATION_ON
+};
+
+/* DPC at the if for IPIPE 5.1 */
+struct ipipeif_dpc {
+	/* 0 - disable, 1 - enable */
+	unsigned char en;
+	/* threshold */
+	unsigned short thr;
+};
+
+enum ipipeif_chroma_phase {
+	IPIPEIF_CBCR_Y = 0,
+	IPIPEIF_Y_CBCR = 1,
+};
+
+#endif
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 02/14] davinci: vpfe: add IPIPE hardware layer support
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 01/14] davinci: vpfe: add dm3xx IPIPEIF hardware support module Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-23 14:36   ` Sakari Ailus
  2012-09-14 12:46 ` [PATCH 03/14] davinci: vpfe: add IPIPE support for media controller driver Prabhakar Lad
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

add dm365 IPIPE hardware support. IPIPE is the hardware IP which
implements the functionality required for resizer, previewer and
the associated feature support. This is built along with the vpfe
driver, and implements hardware setup including coeffcient
programming for various hardware filters, gamma, cfa and clock
enable.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/dm365_ipipe_hw.c |  936 +++++++++++++++++++++++
 drivers/media/platform/davinci/dm365_ipipe_hw.h |  538 +++++++++++++
 2 files changed, 1474 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/platform/davinci/dm365_ipipe_hw.c
 create mode 100644 drivers/media/platform/davinci/dm365_ipipe_hw.h

diff --git a/drivers/media/platform/davinci/dm365_ipipe_hw.c b/drivers/media/platform/davinci/dm365_ipipe_hw.c
new file mode 100644
index 0000000..4ce6d95
--- /dev/null
+++ b/drivers/media/platform/davinci/dm365_ipipe_hw.c
@@ -0,0 +1,936 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/v4l2-mediabus.h>
+
+#include "dm365_ipipe.h"
+#include "dm3xx_ipipeif.h"
+#include "dm365_ipipe_hw.h"
+
+static void ipipe_clock_enable(void)
+{
+	/* enable IPIPE MMR for register write access */
+	regw_ip(IPIPE_GCK_MMR_DEFAULT, IPIPE_GCK_MMR);
+	/* enable the clock wb,cfa,dfc,d2f,pre modules */
+	regw_ip(IPIPE_GCK_PIX_DEFAULT, IPIPE_GCK_PIX);
+	/* enable RSZ MMR for register write access */
+}
+
+/* Set input channel format to either 420 Y or C format */
+void rsz_set_in_pix_format(unsigned char y_c)
+{
+	u32 val;
+
+	val = regr_rsz(RSZ_SRC_FMT1);
+	val |= y_c & 1;
+	regw_rsz(val, RSZ_SRC_FMT1);
+}
+
+static void rsz_set_common_params(struct ipipe_params *params)
+{
+	struct rsz_common_params *rsz_common = &params->rsz_common;
+	u32 val;
+
+	/* Set mode */
+	regw_rsz(params->ipipe_mode, RSZ_SRC_MODE);
+
+	/* data source selection  and bypass */
+	val = (rsz_common->passthrough << RSZ_BYPASS_SHIFT) |
+		rsz_common->source;
+
+	regw_rsz(val, RSZ_SRC_FMT0);
+	val = regr_rsz(RSZ_SRC_MODE);
+	/* src image selection */
+	val = (rsz_common->raw_flip & 1) |
+		(rsz_common->src_img_fmt << RSZ_SRC_IMG_FMT_SHIFT) |
+		((rsz_common->y_c & 1) << RSZ_SRC_Y_C_SEL_SHIFT);
+
+	regw_rsz(val, RSZ_SRC_FMT1);
+	regw_rsz(rsz_common->vps & IPIPE_RSZ_VPS_MASK, RSZ_SRC_VPS);
+	regw_rsz(rsz_common->hps & IPIPE_RSZ_HPS_MASK, RSZ_SRC_HPS);
+	regw_rsz(rsz_common->vsz & IPIPE_RSZ_VSZ_MASK, RSZ_SRC_VSZ);
+	regw_rsz(rsz_common->hsz & IPIPE_RSZ_HSZ_MASK, RSZ_SRC_HSZ);
+	regw_rsz(rsz_common->yuv_y_min, RSZ_YUV_Y_MIN);
+	regw_rsz(rsz_common->yuv_y_max, RSZ_YUV_Y_MAX);
+	regw_rsz(rsz_common->yuv_c_min, RSZ_YUV_C_MIN);
+	regw_rsz(rsz_common->yuv_c_max, RSZ_YUV_C_MAX);
+	/* chromatic position */
+	regw_rsz(rsz_common->out_chr_pos, RSZ_YUV_PHS);
+	val = regr_rsz(RSZ_SRC_MODE);
+}
+
+static void rsz_set_rsz_regs(unsigned int rsz_id, struct ipipe_params *params)
+{
+	struct ipipe_rsz_rescale_param *rsc_params;
+	struct ipipe_ext_mem_param *ext_mem;
+	struct ipipe_rsz_resize2rgb *rgb;
+	u32 reg_base;
+	u32 val;
+
+	val = regr_rsz(RSZ_SEQ);
+	rsc_params = &params->rsz_rsc_param[rsz_id];
+	rgb = &params->rsz2rgb[rsz_id];
+	ext_mem = &params->ext_mem_param[rsz_id];
+
+	if (rsz_id == RSZ_A) {
+		val = rsc_params->h_flip << RSZA_H_FLIP_SHIFT;
+		val |= rsc_params->v_flip << RSZA_V_FLIP_SHIFT;
+		reg_base = RSZ_EN_A;
+	} else {
+		val = rsc_params->h_flip << RSZB_H_FLIP_SHIFT;
+		val |= rsc_params->v_flip << RSZB_V_FLIP_SHIFT;
+		reg_base = RSZ_EN_B;
+	}
+	/* update flip settings */
+	regw_rsz(val, RSZ_SEQ);
+
+	regw_rsz(rsc_params->mode, reg_base + RSZ_MODE);
+	val = (rsc_params->cen << RSZ_CEN_SHIFT) | rsc_params->yen;
+	regw_rsz(val, reg_base + RSZ_420);
+	regw_rsz(rsc_params->i_vps & RSZ_VPS_MASK, reg_base + RSZ_I_VPS);
+	regw_rsz(rsc_params->i_hps & RSZ_HPS_MASK, reg_base + RSZ_I_HPS);
+	regw_rsz(rsc_params->o_vsz & RSZ_O_VSZ_MASK, reg_base + RSZ_O_VSZ);
+	regw_rsz(rsc_params->o_hsz & RSZ_O_HSZ_MASK, reg_base + RSZ_O_HSZ);
+	regw_rsz(rsc_params->v_phs_y & RSZ_V_PHS_MASK, reg_base + RSZ_V_PHS_Y);
+	regw_rsz(rsc_params->v_phs_c & RSZ_V_PHS_MASK, reg_base + RSZ_V_PHS_C);
+	/* keep this additional adjustment to zero for now */
+	regw_rsz(rsc_params->v_dif & RSZ_V_DIF_MASK, reg_base + RSZ_V_DIF);
+
+	val = (rsc_params->v_typ_y & 1) | ((rsc_params->v_typ_c & 1) <<
+							RSZ_TYP_C_SHIFT);
+	regw_rsz(val, reg_base + RSZ_V_TYP);
+
+	val = (rsc_params->v_lpf_int_y & RSZ_LPF_INT_MASK) |
+			((rsc_params->v_lpf_int_c & RSZ_LPF_INT_MASK) <<
+				RSZ_LPF_INT_C_SHIFT);
+	regw_rsz(val, reg_base + RSZ_V_LPF);
+
+	regw_rsz(rsc_params->h_phs & RSZ_H_PHS_MASK, reg_base + RSZ_H_PHS);
+	regw_rsz(0, reg_base + RSZ_H_PHS_ADJ);
+	regw_rsz(rsc_params->h_dif & RSZ_H_DIF_MASK, reg_base + RSZ_H_DIF);
+	val = (rsc_params->h_typ_y & 1) | ((rsc_params->h_typ_c & 1) <<
+							RSZ_TYP_C_SHIFT);
+	regw_rsz(val, reg_base + RSZ_H_TYP);
+	val = (rsc_params->h_lpf_int_y & RSZ_LPF_INT_MASK) |
+		 ((rsc_params->h_lpf_int_c & RSZ_LPF_INT_MASK) <<
+		 RSZ_LPF_INT_C_SHIFT);
+	regw_rsz(val, reg_base + RSZ_H_LPF);
+
+	regw_rsz(rsc_params->dscale_en & 1, reg_base + RSZ_DWN_EN);
+	val = rsc_params->h_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK;
+	val |= (rsc_params->v_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK) <<
+				  RSZ_DWN_SCALE_AV_SZ_V_SHIFT;
+	regw_rsz(val, reg_base + RSZ_DWN_AV);
+
+	/* setting rgb conversion parameters */
+	regw_rsz(rgb->rgb_en, reg_base + RSZ_RGB_EN);
+	val = (rgb->rgb_typ << RSZ_RGB_TYP_SHIFT) |
+		 (rgb->rgb_msk0 << RSZ_RGB_MSK0_SHIFT) |
+		 (rgb->rgb_msk1 << RSZ_RGB_MSK1_SHIFT);
+	regw_rsz(val, reg_base + RSZ_RGB_TYP);
+	regw_rsz(rgb->rgb_alpha_val & RSZ_RGB_ALPHA_MASK,
+		reg_base + RSZ_RGB_BLD);
+
+	/* setting external memory parameters */
+	regw_rsz(ext_mem->rsz_sdr_oft_y, reg_base + RSZ_SDR_Y_OFT);
+	regw_rsz(ext_mem->rsz_sdr_ptr_s_y, reg_base + RSZ_SDR_Y_PTR_S);
+	regw_rsz(ext_mem->rsz_sdr_ptr_e_y, reg_base + RSZ_SDR_Y_PTR_E);
+	regw_rsz(ext_mem->rsz_sdr_oft_c, reg_base + RSZ_SDR_C_OFT);
+	regw_rsz(ext_mem->rsz_sdr_ptr_s_c, reg_base + RSZ_SDR_C_PTR_S);
+	regw_rsz((ext_mem->rsz_sdr_ptr_e_c >> 1), reg_base + RSZ_SDR_C_PTR_E);
+}
+
+/*set the registers of either RSZ0 or RSZ1 */
+static void ipipe_setup_resizer(struct ipipe_params *params)
+{
+	/* enable MMR gate to write to Resizer */
+	regw_rsz(1, RSZ_GCK_MMR);
+
+	/* Enable resizer if it is not in bypass mode */
+	if (params->rsz_common.passthrough)
+		regw_rsz(0, RSZ_GCK_SDR);
+	else
+		regw_rsz(1, RSZ_GCK_SDR);
+
+	rsz_set_common_params(params);
+
+	regw_rsz(params->rsz_en[RSZ_A], RSZ_EN_A);
+	if (params->rsz_en[RSZ_A])
+		/*setting rescale parameters */
+		rsz_set_rsz_regs(RSZ_A, params);
+
+	regw_rsz(params->rsz_en[RSZ_B], RSZ_EN_B);
+	if (params->rsz_en[RSZ_B])
+		rsz_set_rsz_regs(RSZ_B, params);
+
+	regr_rsz(RSZ_SRC_MODE);
+}
+
+/*
+ * ipipe_hw_setup() - Performs hardware setup of ipipe.
+ */
+int ipipe_hw_setup(struct ipipe_params *config)
+{
+	u32 data_format;
+	u32 val;
+
+	if (!config) {
+		pr_err("ipipe_hw_setup- Invalid config\n");
+		return -EINVAL;
+	}
+
+	if (ipipeif_hw_setup(&config->ipipeif_param, DM365) < 0) {
+		pr_err("ipipe_hw_setup- Failed to configure IPIPEIF");
+		return -EINVAL;
+	}
+
+	/* enable clock to IPIPE */
+	vpss_enable_clock(VPSS_IPIPE_CLOCK, 1);
+	/* enable clock to MMR and modules before writting
+	 * to ipipe registers
+	 */
+	ipipe_clock_enable();
+
+	if (config->rsz_common.source == IPIPEIF_DATA) {
+		/* we need to skip configuring IPIPE */
+		regw_ip(0, IPIPE_SRC_EN);
+	} else {
+		/* enable ipipe mode to either one shot or continuous */
+		val = config->ipipe_mode;
+		regw_ip(val, IPIPE_SRC_MODE);
+		data_format = config->ipipe_dpaths_fmt;
+		regw_ip(data_format, IPIPE_SRC_FMT);
+		/* set size */
+		regw_ip(config->ipipe_vps & IPIPE_RSZ_VPS_MASK, IPIPE_SRC_VPS);
+		regw_ip(config->ipipe_hps & IPIPE_RSZ_HPS_MASK, IPIPE_SRC_HPS);
+		regw_ip(config->ipipe_vsz & IPIPE_RSZ_VSZ_MASK, IPIPE_SRC_VSZ);
+		regw_ip(config->ipipe_hsz & IPIPE_RSZ_HSZ_MASK, IPIPE_SRC_HSZ);
+
+		if (data_format == IPIPE_RAW2YUV ||
+					data_format == IPIPE_RAW2RAW)
+			regw_ip(config->ipipe_colpat, IPIPE_SRC_COL);
+	}
+
+	ipipe_setup_resizer(config);
+
+	return 0;
+}
+
+static void rsz_set_y_address(unsigned int address, unsigned int offset)
+{
+	u32 val;
+
+	val = address & SET_LOW_ADD;
+	regw_rsz(val, offset + RSZ_SDR_Y_BAD_L);
+	regw_rsz(val, offset + RSZ_SDR_Y_SAD_L);
+	val = (address & SET_HIGH_ADD) >> 16;
+	regw_rsz(val, offset + RSZ_SDR_Y_BAD_H);
+	regw_rsz(val, offset + RSZ_SDR_Y_SAD_H);
+}
+
+static void rsz_set_c_address(unsigned int address, unsigned int offset)
+{
+	u32 val;
+
+	val = address & SET_LOW_ADD;
+
+	regw_rsz(val, offset + RSZ_SDR_C_BAD_L);
+	regw_rsz(val, offset + RSZ_SDR_C_SAD_L);
+	val = (address & SET_HIGH_ADD) >> 16;
+	regw_rsz(val, offset + RSZ_SDR_C_BAD_H);
+	regw_rsz(val, offset + RSZ_SDR_C_SAD_H);
+}
+
+/* Assume we get a valid params ptr and resize_no set to RSZ_A
+ * or RSZ_B. This could be called in the interrupt context and
+ * must be efficient
+ */
+void rsz_set_output_address(struct ipipe_params *params,
+			   int resize_no, unsigned int address)
+{
+	unsigned int rsz_start_add;
+	unsigned int val;
+
+	struct ipipe_ext_mem_param *mem_param =
+		&params->ext_mem_param[resize_no];
+	struct rsz_common_params *rsz_common =
+		&params->rsz_common;
+	struct ipipe_rsz_rescale_param *rsc_param =
+		&params->rsz_rsc_param[resize_no];
+
+	if (resize_no == RSZ_A)
+		rsz_start_add = RSZ_EN_A;
+	else
+		rsz_start_add = RSZ_EN_B;
+	/* y_c = 0 for y, = 1 for c */
+	if (rsz_common->src_img_fmt == RSZ_IMG_420) {
+		if (rsz_common->y_c) {
+			/* C channel */
+			val = address + mem_param->flip_ofst_c;
+			rsz_set_c_address(val, rsz_start_add);
+		} else {
+			val = address + mem_param->flip_ofst_y;
+			rsz_set_y_address(val, rsz_start_add);
+		}
+	} else {
+		if (rsc_param->cen && rsc_param->yen) {
+			/* 420 */
+			val = address + mem_param->c_offset;
+			val = address + mem_param->c_offset +
+				mem_param->flip_ofst_c;
+			val += mem_param->user_y_ofst +
+				mem_param->user_c_ofst;
+			if (resize_no == RSZ_B)
+				val +=
+				params->ext_mem_param[RSZ_A].user_y_ofst +
+				params->ext_mem_param[RSZ_A].user_c_ofst;
+			/* set C address */
+			rsz_set_c_address(val, rsz_start_add);
+		}
+		val = address + mem_param->flip_ofst_y;
+		val += mem_param->user_y_ofst;
+		if (resize_no == RSZ_B)
+			val += params->ext_mem_param[RSZ_A].user_y_ofst +
+				params->ext_mem_param[RSZ_A].user_c_ofst;
+		/* set Y address */
+		rsz_set_y_address(val, rsz_start_add);
+	}
+	/* resizer must be enabled */
+	regw_rsz(params->rsz_en[resize_no], rsz_start_add);
+
+}
+
+void ipipe_set_lutdpc_regs(struct prev_lutdpc *dpc)
+{
+	u32 max_tbl_size = LUT_DPC_MAX_SIZE >> 1;
+	u32 lut_start_addr = DPC_TB0_START_ADDR;
+	u32 val;
+	u32 count;
+
+	ipipe_clock_enable();
+	regw_ip(dpc->en, DPC_LUT_EN);
+	if (dpc->en != 1)
+		return;
+
+	/* if dpc is enabled */
+	val = LUTDPC_TBL_256_EN;
+	val |= dpc->repl_white & 1;
+	regw_ip(val, DPC_LUT_SEL);
+	regw_ip(LUT_DPC_START_ADDR, DPC_LUT_ADR);
+	regw_ip(dpc->dpc_size, DPC_LUT_SIZ & LUT_DPC_SIZE_MASK);
+
+	if (dpc->table == NULL)
+		return;
+
+	for (count = 0; count < dpc->dpc_size; count++) {
+		if (count >= max_tbl_size)
+			lut_start_addr = DPC_TB1_START_ADDR;
+		val = dpc->table[count].horz_pos & LUT_DPC_H_POS_MASK;
+		val |= (dpc->table[count].vert_pos & LUT_DPC_V_POS_MASK) <<
+			LUT_DPC_V_POS_SHIFT;
+		val |= dpc->table[count].method << LUT_DPC_CORR_METH_SHIFT;
+		w_ip_table(val, (lut_start_addr +
+						((count % max_tbl_size) << 2)));
+	}
+}
+
+static void set_dpc_thresholds(struct prev_otfdpc_2_0 *dpc_thr)
+{
+	regw_ip((dpc_thr->corr_thr.r & OTFDPC_DPC2_THR_MASK),
+		DPC_OTF_2C_THR_R);
+	regw_ip((dpc_thr->corr_thr.gr & OTFDPC_DPC2_THR_MASK),
+		DPC_OTF_2C_THR_GR);
+	regw_ip((dpc_thr->corr_thr.gb & OTFDPC_DPC2_THR_MASK),
+		DPC_OTF_2C_THR_GB);
+	regw_ip((dpc_thr->corr_thr.b & OTFDPC_DPC2_THR_MASK),
+		DPC_OTF_2C_THR_B);
+	regw_ip((dpc_thr->det_thr.r & OTFDPC_DPC2_THR_MASK),
+		DPC_OTF_2D_THR_R);
+	regw_ip((dpc_thr->det_thr.gr & OTFDPC_DPC2_THR_MASK),
+		DPC_OTF_2D_THR_GR);
+	regw_ip((dpc_thr->det_thr.gb & OTFDPC_DPC2_THR_MASK),
+		DPC_OTF_2D_THR_GB);
+	regw_ip((dpc_thr->det_thr.b & OTFDPC_DPC2_THR_MASK),
+		DPC_OTF_2D_THR_B);
+}
+
+void ipipe_set_otfdpc_regs(struct prev_otfdpc *otfdpc)
+{
+	struct prev_otfdpc_2_0 *dpc_2_0 = &otfdpc->alg_cfg.dpc_2_0;
+	struct prev_otfdpc_3_0 *dpc_3_0 = &otfdpc->alg_cfg.dpc_3_0;
+	u32 val;
+
+	ipipe_clock_enable();
+
+	regw_ip((otfdpc->en & 1), DPC_OTF_EN);
+	if (otfdpc->en != 1)
+		return;
+
+	/* dpc enabled */
+	val = otfdpc->det_method << OTF_DET_METHOD_SHIFT;
+	val |= otfdpc->alg;
+	regw_ip(val, DPC_OTF_TYP);
+	if (otfdpc->det_method == IPIPE_DPC_OTF_MIN_MAX) {
+		/* ALG= 0, TYP = 0, DPC_OTF_2D_THR_[x]=0
+		 * DPC_OTF_2C_THR_[x] = Maximum thresohld
+		 * MinMax method
+		 */
+		dpc_2_0->det_thr.r = dpc_2_0->det_thr.gb =
+		dpc_2_0->det_thr.gr = dpc_2_0->det_thr.b = 0;
+		set_dpc_thresholds(dpc_2_0);
+		return;
+	}
+	/* MinMax2 */
+	if (otfdpc->alg == IPIPE_OTFDPC_2_0) {
+		set_dpc_thresholds(dpc_2_0);
+		return;
+	}
+	regw_ip((dpc_3_0->act_adj_shf & OTF_DPC3_0_SHF_MASK), DPC_OTF_3_SHF);
+	/* Detection thresholds */
+	regw_ip(((dpc_3_0->det_thr & OTF_DPC3_0_THR_MASK) <<
+		OTF_DPC3_0_THR_SHIFT), DPC_OTF_3D_THR);
+	regw_ip((dpc_3_0->det_slp & OTF_DPC3_0_SLP_MASK), DPC_OTF_3D_SLP);
+	regw_ip((dpc_3_0->det_thr_min & OTF_DPC3_0_DET_MASK), DPC_OTF_3D_MIN);
+	regw_ip((dpc_3_0->det_thr_max & OTF_DPC3_0_DET_MASK), DPC_OTF_3D_MAX);
+	/* Correction thresholds */
+	regw_ip(((dpc_3_0->corr_thr & OTF_DPC3_0_THR_MASK) <<
+		OTF_DPC3_0_THR_SHIFT), DPC_OTF_3C_THR);
+	regw_ip((dpc_3_0->corr_slp & OTF_DPC3_0_SLP_MASK), DPC_OTF_3C_SLP);
+	regw_ip((dpc_3_0->corr_thr_min & OTF_DPC3_0_CORR_MASK), DPC_OTF_3C_MIN);
+	regw_ip((dpc_3_0->corr_thr_max & OTF_DPC3_0_CORR_MASK), DPC_OTF_3C_MAX);
+}
+
+/* 2D Noise filter */
+void ipipe_set_d2f_regs(unsigned int id, struct prev_nf *noise_filter)
+{
+
+	u32 offset = D2F_1ST;
+	int count;
+	u32 val;
+
+	/* id = 0 , NF1 & id = 1, NF 2 */
+	if (id)
+		offset = D2F_2ND;
+	ipipe_clock_enable();
+	regw_ip(noise_filter->en & 1, offset + D2F_EN);
+	if (noise_filter->en != 1)
+		return;
+
+	/*noise filter enabled */
+	/* Combine all the fields to make D2F_CFG register of IPIPE */
+	val = ((noise_filter->spread_val & D2F_SPR_VAL_MASK) <<
+		 D2F_SPR_VAL_SHIFT) |
+		 ((noise_filter->shft_val & D2F_SHFT_VAL_MASK) <<
+		 D2F_SHFT_VAL_SHIFT) |
+		 (noise_filter->gr_sample_meth <<
+		 D2F_SAMPLE_METH_SHIFT) |
+		 ((noise_filter->apply_lsc_gain & 1) <<
+		 D2F_APPLY_LSC_GAIN_SHIFT) | D2F_USE_SPR_REG_VAL;
+
+	regw_ip(val, offset + D2F_TYP);
+	/* edge detection minimum */
+	regw_ip(noise_filter->edge_det_min_thr & D2F_EDGE_DET_THR_MASK,
+		offset + D2F_EDG_MIN);
+	/* edge detection maximum */
+	regw_ip(noise_filter->edge_det_max_thr & D2F_EDGE_DET_THR_MASK,
+		offset + D2F_EDG_MAX);
+	for (count = 0; count < IPIPE_NF_STR_TABLE_SIZE; count++) {
+		regw_ip((noise_filter->str[count] & D2F_STR_VAL_MASK),
+			offset + D2F_STR + count * 4);
+
+	}
+	for (count = 0; count < IPIPE_NF_THR_TABLE_SIZE; count++) {
+		regw_ip(noise_filter->thr[count] & D2F_THR_VAL_MASK,
+			offset + D2F_THR + count * 4);
+	}
+}
+
+#define IPIPE_U8Q5(decimal, integer) \
+	(((decimal & 0x1f) | ((integer & 0x7) << 5)))
+
+/* Green Imbalance Correction */
+void ipipe_set_gic_regs(struct prev_gic *gic)
+{
+	u32 val;
+
+	ipipe_clock_enable();
+	regw_ip(gic->en & 1, GIC_EN);
+
+	if (!gic->en)
+		return;
+
+	/*gic enabled */
+	val = gic->wt_fn_type << GIC_TYP_SHIFT;
+	val |= gic->thr_sel << GIC_THR_SEL_SHIFT;
+	val |= (gic->apply_lsc_gain & 1) << GIC_APPLY_LSC_GAIN_SHIFT;
+	regw_ip(val, GIC_TYP);
+	regw_ip(gic->gain & GIC_GAIN_MASK, GIC_GAN);
+
+	if (gic->gic_alg != IPIPE_GIC_ALG_ADAPT_GAIN) {
+		/* Constant Gain. Set threshold to maximum */
+		regw_ip(GIC_THR_MASK, GIC_THR);
+		return;
+	}
+
+	if (gic->thr_sel == IPIPE_GIC_THR_REG) {
+		regw_ip(gic->thr & GIC_THR_MASK, GIC_THR);
+		regw_ip(gic->slope & GIC_SLOPE_MASK, GIC_SLP);
+	} else {
+		/* Use NF thresholds */
+		val = IPIPE_U8Q5(gic->nf2_thr_gain.decimal,
+				gic->nf2_thr_gain.integer);
+		regw_ip(val, GIC_NFGAN);
+	}
+}
+
+#define IPIPE_U13Q9(decimal, integer) \
+	(((decimal & 0x1ff) | ((integer & 0xf) << 9)))
+/* White balance */
+void ipipe_set_wb_regs(struct prev_wb *wb)
+{
+	u32 val;
+
+	ipipe_clock_enable();
+	/* Ofsets. S12 */
+	regw_ip(wb->ofst_r & WB_OFFSET_MASK, WB2_OFT_R);
+	regw_ip(wb->ofst_gr & WB_OFFSET_MASK, WB2_OFT_GR);
+	regw_ip(wb->ofst_gb & WB_OFFSET_MASK, WB2_OFT_GB);
+	regw_ip(wb->ofst_b & WB_OFFSET_MASK, WB2_OFT_B);
+
+	/* Gains. U13Q9 */
+	val = IPIPE_U13Q9(wb->gain_r.decimal, wb->gain_r.integer);
+	regw_ip(val, WB2_WGN_R);
+	val = IPIPE_U13Q9(wb->gain_gr.decimal, wb->gain_gr.integer);
+	regw_ip(val, WB2_WGN_GR);
+	val = IPIPE_U13Q9(wb->gain_gb.decimal, wb->gain_gb.integer);
+	regw_ip(val, WB2_WGN_GB);
+	val = IPIPE_U13Q9(wb->gain_b.decimal, wb->gain_b.integer);
+	regw_ip(val, WB2_WGN_B);
+}
+
+/* CFA */
+void ipipe_set_cfa_regs(struct prev_cfa *cfa)
+{
+	ipipe_clock_enable();
+	regw_ip(cfa->alg, CFA_MODE);
+	regw_ip(cfa->hpf_thr_2dir & CFA_HPF_THR_2DIR_MASK, CFA_2DIR_HPF_THR);
+	regw_ip(cfa->hpf_slp_2dir & CFA_HPF_SLOPE_2DIR_MASK, CFA_2DIR_HPF_SLP);
+	regw_ip(cfa->hp_mix_thr_2dir & CFA_HPF_MIX_THR_2DIR_MASK,
+			CFA_2DIR_MIX_THR);
+	regw_ip(cfa->hp_mix_slope_2dir & CFA_HPF_MIX_SLP_2DIR_MASK,
+			CFA_2DIR_MIX_SLP);
+	regw_ip(cfa->dir_thr_2dir & CFA_DIR_THR_2DIR_MASK, CFA_2DIR_DIR_THR);
+	regw_ip(cfa->dir_slope_2dir & CFA_DIR_SLP_2DIR_MASK, CFA_2DIR_DIR_SLP);
+	regw_ip(cfa->nd_wt_2dir & CFA_ND_WT_2DIR_MASK, CFA_2DIR_NDWT);
+	regw_ip(cfa->hue_fract_daa & CFA_DAA_HUE_FRA_MASK, CFA_MONO_HUE_FRA);
+	regw_ip(cfa->edge_thr_daa & CFA_DAA_EDG_THR_MASK, CFA_MONO_EDG_THR);
+	regw_ip(cfa->thr_min_daa & CFA_DAA_THR_MIN_MASK, CFA_MONO_THR_MIN);
+	regw_ip(cfa->thr_slope_daa & CFA_DAA_THR_SLP_MASK, CFA_MONO_THR_SLP);
+	regw_ip(cfa->slope_min_daa & CFA_DAA_SLP_MIN_MASK, CFA_MONO_SLP_MIN);
+	regw_ip(cfa->slope_slope_daa & CFA_DAA_SLP_SLP_MASK, CFA_MONO_SLP_SLP);
+	regw_ip(cfa->lp_wt_daa & CFA_DAA_LP_WT_MASK, CFA_MONO_LPWT);
+}
+
+void ipipe_set_rgb2rgb_regs(unsigned int id, struct prev_rgb2rgb *rgb)
+{
+	u32 offset_mask = RGB2RGB_1_OFST_MASK;
+	u32 offset = RGB1_MUL_BASE;
+	u32 integ_mask = 0xf;
+	u32 val;
+
+	ipipe_clock_enable();
+
+	if (id) {
+		/* For second RGB module, gain integer is 3 bits instead
+		of 4, offset has 11 bits insread of 13 */
+		offset = RGB2_MUL_BASE;
+		integ_mask = 0x7;
+		offset_mask = RGB2RGB_2_OFST_MASK;
+	}
+	/* Gains */
+	val = (rgb->coef_rr.decimal & 0xff) |
+		((rgb->coef_rr.integer & integ_mask) << 8);
+	regw_ip(val, offset + RGB_MUL_RR);
+	val = (rgb->coef_gr.decimal & 0xff) |
+		((rgb->coef_gr.integer & integ_mask) << 8);
+	regw_ip(val, offset + RGB_MUL_GR);
+	val = (rgb->coef_br.decimal & 0xff) |
+		((rgb->coef_br.integer & integ_mask) << 8);
+	regw_ip(val, offset + RGB_MUL_BR);
+	val = (rgb->coef_rg.decimal & 0xff) |
+		((rgb->coef_rg.integer & integ_mask) << 8);
+	regw_ip(val, offset + RGB_MUL_RG);
+	val = (rgb->coef_gg.decimal & 0xff) |
+		((rgb->coef_gg.integer & integ_mask) << 8);
+	regw_ip(val, offset + RGB_MUL_GG);
+	val = (rgb->coef_bg.decimal & 0xff) |
+		((rgb->coef_bg.integer & integ_mask) << 8);
+	regw_ip(val, offset + RGB_MUL_BG);
+	val = (rgb->coef_rb.decimal & 0xff) |
+		((rgb->coef_rb.integer & integ_mask) << 8);
+	regw_ip(val, offset + RGB_MUL_RB);
+	val = (rgb->coef_gb.decimal & 0xff) |
+		((rgb->coef_gb.integer & integ_mask) << 8);
+	regw_ip(val, offset + RGB_MUL_GB);
+	val = (rgb->coef_bb.decimal & 0xff) |
+		((rgb->coef_bb.integer & integ_mask) << 8);
+	regw_ip(val, offset + RGB_MUL_BB);
+
+	/* Offsets */
+	regw_ip(rgb->out_ofst_r & offset_mask, offset + RGB_OFT_OR);
+	regw_ip(rgb->out_ofst_g & offset_mask, offset + RGB_OFT_OG);
+	regw_ip(rgb->out_ofst_b & offset_mask, offset + RGB_OFT_OB);
+}
+
+static void ipipe_update_gamma_tbl(struct ipipe_gamma_entry *table,
+				   int size, u32 addr)
+{
+	int count;
+	u32 val;
+
+	for (count = 0; count < size; count++) {
+		val = table[count].slope & GAMMA_MASK;
+		val |= (table[count].offset & GAMMA_MASK) << GAMMA_SHIFT;
+		w_ip_table(val, (addr + (count * 4)));
+	}
+}
+
+/* Gamma correction */
+void ipipe_set_gamma_regs(struct prev_gamma *gamma)
+{
+	int table_size;
+	u32 val;
+
+	ipipe_clock_enable();
+	val = (gamma->bypass_r << GAMMA_BYPR_SHIFT) |
+		(gamma->bypass_b << GAMMA_BYPG_SHIFT) |
+		(gamma->bypass_g << GAMMA_BYPB_SHIFT) |
+		(gamma->tbl_sel << GAMMA_TBL_SEL_SHIFT) |
+		(gamma->tbl_size << GAMMA_TBL_SIZE_SHIFT);
+
+	regw_ip(val, GMM_CFG);
+
+	if (gamma->tbl_sel != IPIPE_GAMMA_TBL_RAM)
+		return;
+
+	table_size = gamma->tbl_size;
+
+	if (!gamma->bypass_r && gamma->table_r != NULL) {
+		ipipe_update_gamma_tbl(gamma->table_r, table_size,
+					GAMMA_R_START_ADDR);
+	}
+	if (!gamma->bypass_b && gamma->table_b != NULL) {
+		ipipe_update_gamma_tbl(gamma->table_b, table_size,
+					GAMMA_B_START_ADDR);
+	}
+	if (!gamma->bypass_g && gamma->table_g != NULL) {
+		ipipe_update_gamma_tbl(gamma->table_g, table_size,
+					GAMMA_G_START_ADDR);
+	}
+}
+
+/* 3D LUT */
+void ipipe_set_3d_lut_regs(struct prev_3d_lut *lut_3d)
+{
+	struct ipipe_3d_lut_entry *tbl;
+	u32 bnk_index;
+	u32 tbl_index;
+	u32 val;
+	u32 i;
+
+	ipipe_clock_enable();
+	regw_ip(lut_3d->en, D3LUT_EN);
+
+	if (!lut_3d->en)
+		return;
+
+	/* lut_3d enabled */
+	if (!lut_3d->table)
+		return;
+
+	/* valied table */
+	tbl = lut_3d->table;
+	for (i = 0 ; i < MAX_SIZE_3D_LUT; i++) {
+		/* Each entry has 0-9 (B), 10-19 (G) and
+		20-29 R values */
+		val = tbl[i].b & D3_LUT_ENTRY_MASK;
+		val |= (tbl[i].g & D3_LUT_ENTRY_MASK) <<
+			 D3_LUT_ENTRY_G_SHIFT;
+		val |= (tbl[i].r & D3_LUT_ENTRY_MASK) <<
+			 D3_LUT_ENTRY_R_SHIFT;
+		bnk_index = i % 4;
+		tbl_index = i >> 2;
+		tbl_index <<= 2;
+		if (bnk_index == 0)
+			w_ip_table(val, tbl_index + D3L_TB0_START_ADDR);
+		else if (bnk_index == 1)
+			w_ip_table(val, tbl_index + D3L_TB1_START_ADDR);
+		else if (bnk_index == 2)
+			w_ip_table(val, tbl_index + D3L_TB2_START_ADDR);
+		else
+			w_ip_table(val, tbl_index + D3L_TB3_START_ADDR);
+	}
+}
+
+/* Lumina adjustments */
+void ipipe_set_lum_adj_regs(struct prev_lum_adj *lum_adj)
+{
+	u32 val;
+
+	ipipe_clock_enable();
+	/* combine fields of YUV_ADJ to set brightness and contrast */
+	val = lum_adj->contrast << LUM_ADJ_CONTR_SHIFT |
+			lum_adj->brightness << LUM_ADJ_BRIGHT_SHIFT;
+	regw_ip(val, YUV_ADJ);
+}
+
+#define IPIPE_S12Q8(decimal, integer) \
+	(((decimal & 0xff) | ((integer & 0xf) << 8)))
+/* RGB2YUV */
+void ipipe_set_rgb2ycbcr_regs(struct prev_rgb2yuv *yuv)
+{
+	u32 val;
+
+	/* S10Q8 */
+	ipipe_clock_enable();
+	val = IPIPE_S12Q8(yuv->coef_ry.decimal, yuv->coef_ry.integer);
+	regw_ip(val, YUV_MUL_RY);
+	val = IPIPE_S12Q8(yuv->coef_gy.decimal, yuv->coef_gy.integer);
+	regw_ip(val, YUV_MUL_GY);
+	val = IPIPE_S12Q8(yuv->coef_by.decimal, yuv->coef_by.integer);
+	regw_ip(val, YUV_MUL_BY);
+	val = IPIPE_S12Q8(yuv->coef_rcb.decimal, yuv->coef_rcb.integer);
+	regw_ip(val, YUV_MUL_RCB);
+	val = IPIPE_S12Q8(yuv->coef_gcb.decimal, yuv->coef_gcb.integer);
+	regw_ip(val, YUV_MUL_GCB);
+	val = IPIPE_S12Q8(yuv->coef_bcb.decimal, yuv->coef_bcb.integer);
+	regw_ip(val, YUV_MUL_BCB);
+	val = IPIPE_S12Q8(yuv->coef_rcr.decimal, yuv->coef_rcr.integer);
+	regw_ip(val, YUV_MUL_RCR);
+	val = IPIPE_S12Q8(yuv->coef_gcr.decimal, yuv->coef_gcr.integer);
+	regw_ip(val, YUV_MUL_GCR);
+	val = IPIPE_S12Q8(yuv->coef_bcr.decimal, yuv->coef_bcr.integer);
+	regw_ip(val, YUV_MUL_BCR);
+	regw_ip(yuv->out_ofst_y & RGB2YCBCR_OFST_MASK, YUV_OFT_Y);
+	regw_ip(yuv->out_ofst_cb & RGB2YCBCR_OFST_MASK, YUV_OFT_CB);
+	regw_ip(yuv->out_ofst_cr & RGB2YCBCR_OFST_MASK, YUV_OFT_CR);
+}
+
+/* YUV 422 conversion */
+void ipipe_set_yuv422_conv_regs(struct prev_yuv422_conv *conv)
+{
+	u32 val;
+
+	ipipe_clock_enable();
+	/* Combine all the fields to make YUV_PHS register of IPIPE */
+	val = (conv->chrom_pos << 0) | (conv->en_chrom_lpf << 1);
+	regw_ip(val, YUV_PHS);
+}
+
+/* GBCE */
+void ipipe_set_gbce_regs(struct prev_gbce *gbce)
+{
+	unsigned int tbl_index;
+	unsigned int count;
+	u32 mask = GBCE_Y_VAL_MASK;
+	u32 val;
+
+	if (gbce->type == IPIPE_GBCE_GAIN_TBL)
+		mask = GBCE_GAIN_VAL_MASK;
+
+	ipipe_clock_enable();
+	regw_ip(gbce->en & 1, GBCE_EN);
+
+	if (!gbce->en)
+		return;
+
+	regw_ip(gbce->type, GBCE_TYP);
+
+	if (!gbce->table)
+		return;
+
+	/* set to 0 */
+	val = 0;
+
+	for (count = 0; count < MAX_SIZE_GBCE_LUT; count++) {
+		tbl_index = count >> 1;
+		tbl_index <<= 2;
+		/* Each table has 2 LUT entries, first in LS
+		  * and second in MS positions
+		  */
+		if (count % 2) {
+			val |=
+				(gbce->table[count] & mask) <<
+				GBCE_ENTRY_SHIFT;
+			w_ip_table(val, tbl_index + GBCE_TB_START_ADDR);
+		} else {
+			val = gbce->table[count] & mask;
+		}
+	}
+}
+
+/* Edge Enhancement */
+void ipipe_set_ee_regs(struct prev_yee *ee)
+{
+	unsigned int tbl_index;
+	unsigned int count;
+	u32 val;
+
+	ipipe_clock_enable();
+	regw_ip(ee->en, YEE_EN);
+
+	if (!ee->en)
+		return;
+
+	val = ee->en_halo_red & 1;
+	val |= ee->merge_meth << YEE_HALO_RED_EN_SHIFT;
+	regw_ip(val, YEE_TYP);
+	regw_ip(ee->hpf_shft, YEE_SHF);
+	regw_ip(ee->hpf_coef_00 & YEE_COEF_MASK, YEE_MUL_00);
+	regw_ip(ee->hpf_coef_01 & YEE_COEF_MASK, YEE_MUL_01);
+	regw_ip(ee->hpf_coef_02 & YEE_COEF_MASK, YEE_MUL_02);
+	regw_ip(ee->hpf_coef_10 & YEE_COEF_MASK, YEE_MUL_10);
+	regw_ip(ee->hpf_coef_11 & YEE_COEF_MASK, YEE_MUL_11);
+	regw_ip(ee->hpf_coef_12 & YEE_COEF_MASK, YEE_MUL_12);
+	regw_ip(ee->hpf_coef_20 & YEE_COEF_MASK, YEE_MUL_20);
+	regw_ip(ee->hpf_coef_21 & YEE_COEF_MASK, YEE_MUL_21);
+	regw_ip(ee->hpf_coef_22 & YEE_COEF_MASK, YEE_MUL_22);
+	regw_ip(ee->yee_thr & YEE_THR_MASK, YEE_THR);
+	regw_ip(ee->es_gain & YEE_ES_GAIN_MASK, YEE_E_GAN);
+	regw_ip(ee->es_thr1 & YEE_ES_THR1_MASK, YEE_E_THR1);
+	regw_ip(ee->es_thr2 & YEE_THR_MASK, YEE_E_THR2);
+	regw_ip(ee->es_gain_grad & YEE_THR_MASK, YEE_G_GAN);
+	regw_ip(ee->es_ofst_grad & YEE_THR_MASK, YEE_G_OFT);
+
+	if (ee->table == NULL)
+		return;
+
+	for (count = 0; count < MAX_SIZE_YEE_LUT; count++) {
+		tbl_index = count >> 1;
+		tbl_index <<= 2;
+		/* Each table has 2 LUT entries, first in LS
+		  * and second in MS positions
+		  */
+		if (count % 2) {
+			val |= (ee->table[count] & YEE_ENTRY_MASK) <<
+				YEE_ENTRY_SHIFT;
+			w_ip_table(val, tbl_index + YEE_TB_START_ADDR);
+		} else {
+			val = ee->table[count] & YEE_ENTRY_MASK;
+		}
+	}
+}
+
+/* Chromatic Artifact Correction. CAR */
+static void ipipe_set_mf(void)
+{
+	/* typ to dynamic switch */
+	regw_ip(IPIPE_CAR_DYN_SWITCH, CAR_TYP);
+	/* Set SW0 to maximum */
+	regw_ip(CAR_MF_THR, CAR_SW);
+}
+
+static void ipipe_set_gain_ctrl(struct prev_car *car)
+{
+	regw_ip(IPIPE_CAR_CHR_GAIN_CTRL, CAR_TYP);
+	regw_ip(car->hpf, CAR_HPF_TYP);
+	regw_ip(car->hpf_shft & CAR_HPF_SHIFT_MASK, CAR_HPF_SHF);
+	regw_ip(car->hpf_thr, CAR_HPF_THR);
+	regw_ip(car->gain1.gain, CAR_GN1_GAN);
+	regw_ip(car->gain1.shft & CAR_GAIN1_SHFT_MASK, CAR_GN1_SHF);
+	regw_ip(car->gain1.gain_min & CAR_GAIN_MIN_MASK, CAR_GN1_MIN);
+	regw_ip(car->gain2.gain, CAR_GN2_GAN);
+	regw_ip(car->gain2.shft & CAR_GAIN2_SHFT_MASK, CAR_GN2_SHF);
+	regw_ip(car->gain2.gain_min & CAR_GAIN_MIN_MASK, CAR_GN2_MIN);
+}
+
+void ipipe_set_car_regs(struct prev_car *car)
+{
+	u32 val;
+
+	ipipe_clock_enable();
+	regw_ip(car->en, CAR_EN);
+
+	if (!car->en)
+		return;
+
+	switch (car->meth) {
+	case IPIPE_CAR_MED_FLTR:
+		ipipe_set_mf();
+		break;
+	case IPIPE_CAR_CHR_GAIN_CTRL:
+		ipipe_set_gain_ctrl(car);
+		break;
+	default:
+		/* Dynamic switch between MF and Gain Ctrl. */
+		ipipe_set_mf();
+		ipipe_set_gain_ctrl(car);
+		/* Set the threshold for switching between
+		  * the two Here we overwrite the MF SW0 value
+		  */
+		regw_ip(IPIPE_CAR_DYN_SWITCH, CAR_TYP);
+		val = car->sw1;
+		val <<= CAR_SW1_SHIFT;
+		val |= car->sw0;
+		regw_ip(val, CAR_SW);
+	}
+}
+
+/* Chromatic Gain Suppression */
+void ipipe_set_cgs_regs(struct prev_cgs *cgs)
+{
+	ipipe_clock_enable();
+	regw_ip(cgs->en, CGS_EN);
+
+	if (!cgs->en)
+		return;
+
+	/* Set the bright side parameters */
+	regw_ip(cgs->h_thr, CGS_GN1_H_THR);
+	regw_ip(cgs->h_slope, CGS_GN1_H_GAN);
+	regw_ip(cgs->h_shft & CAR_SHIFT_MASK, CGS_GN1_H_SHF);
+	regw_ip(cgs->h_min, CGS_GN1_H_MIN);
+}
+
+void rsz_src_enable(int enable)
+{
+	regw_rsz(enable, RSZ_SRC_EN);
+}
+
+int rsz_enable(int rsz_id, int enable)
+{
+	if (rsz_id == RSZ_A) {
+		regw_rsz(enable, RSZ_EN_A);
+		/* We always enable RSZ_A. RSZ_B is enable upon request from
+		 * application. So enable RSZ_SRC_EN along with RSZ_A
+		 */
+		regw_rsz(enable, RSZ_SRC_EN);
+	} else if (rsz_id == RSZ_B) {
+		regw_rsz(enable, RSZ_EN_B);
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/platform/davinci/dm365_ipipe_hw.h b/drivers/media/platform/davinci/dm365_ipipe_hw.h
new file mode 100644
index 0000000..7e92633
--- /dev/null
+++ b/drivers/media/platform/davinci/dm365_ipipe_hw.h
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _DM365_IPIPE_HW_H
+#define _DM365_IPIPE_HW_H
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#define IPIPE_IOBASE_VADDR		IO_ADDRESS(0x01c70800)
+#define RSZ_IOBASE_VADDR		IO_ADDRESS(0x01c70400)
+#define IPIPE_INT_TABLE_IOBASE_VADDR	IO_ADDRESS(0x01c70000)
+
+#define SET_LOW_ADD     0x0000ffff
+#define SET_HIGH_ADD    0xffff0000
+
+/* Below are the internal tables */
+#define DPC_TB0_START_ADDR	0x8000
+#define DPC_TB1_START_ADDR	0x8400
+
+#define GAMMA_R_START_ADDR	0xa800
+#define GAMMA_G_START_ADDR	0xb000
+#define GAMMA_B_START_ADDR	0xb800
+
+/* RAM table addresses for edge enhancement correction*/
+#define YEE_TB_START_ADDR	0x8800
+
+/* RAM table address for GBC LUT */
+#define GBCE_TB_START_ADDR	0x9000
+
+/* RAM table for 3D NF LUT */
+#define D3L_TB0_START_ADDR	0x9800
+#define D3L_TB1_START_ADDR	0x9c00
+#define D3L_TB2_START_ADDR	0xa000
+#define D3L_TB3_START_ADDR	0xa400
+
+/* IPIPE Register Offsets from the base address */
+#define IPIPE_SRC_EN		0x0000
+#define IPIPE_SRC_MODE		0x0004
+#define IPIPE_SRC_FMT		0x0008
+#define IPIPE_SRC_COL		0x000c
+#define IPIPE_SRC_VPS		0x0010
+#define IPIPE_SRC_VSZ		0x0014
+#define IPIPE_SRC_HPS		0x0018
+#define IPIPE_SRC_HSZ		0x001c
+
+#define IPIPE_SEL_SBU		0x0020
+
+#define IPIPE_DMA_STA		0x0024
+#define IPIPE_GCK_MMR		0x0028
+#define IPIPE_GCK_PIX		0x002c
+#define IPIPE_RESERVED0		0x0030
+
+/* Defect Correction */
+#define DPC_LUT_EN		0x0034
+#define DPC_LUT_SEL		0x0038
+#define DPC_LUT_ADR		0x003c
+#define DPC_LUT_SIZ		0x0040
+#define DPC_OTF_EN		0x0044
+#define DPC_OTF_TYP		0x0048
+#define DPC_OTF_2D_THR_R	0x004c
+#define DPC_OTF_2D_THR_GR	0x0050
+#define DPC_OTF_2D_THR_GB	0x0054
+#define DPC_OTF_2D_THR_B	0x0058
+#define DPC_OTF_2C_THR_R	0x005c
+#define DPC_OTF_2C_THR_GR	0x0060
+#define DPC_OTF_2C_THR_GB	0x0064
+#define DPC_OTF_2C_THR_B	0x0068
+#define DPC_OTF_3_SHF		0x006c
+#define DPC_OTF_3D_THR		0x0070
+#define DPC_OTF_3D_SLP		0x0074
+#define DPC_OTF_3D_MIN		0x0078
+#define DPC_OTF_3D_MAX		0x007c
+#define DPC_OTF_3C_THR		0x0080
+#define DPC_OTF_3C_SLP		0x0084
+#define DPC_OTF_3C_MIN		0x0088
+#define DPC_OTF_3C_MAX		0x008c
+
+/* Lense Shading Correction */
+#define LSC_VOFT		0x90
+#define LSC_VA2			0x94
+#define LSC_VA1			0x98
+#define LSC_VS			0x9c
+#define LSC_HOFT		0xa0
+#define LSC_HA2			0xa4
+#define LSC_HA1			0xa8
+#define LSC_HS			0xac
+#define LSC_GAIN_R		0xb0
+#define LSC_GAIN_GR		0xb4
+#define LSC_GAIN_GB		0xb8
+#define LSC_GAIN_B		0xbc
+#define LSC_OFT_R		0xc0
+#define LSC_OFT_GR		0xc4
+#define LSC_OFT_GB		0xc8
+#define LSC_OFT_B		0xcc
+#define LSC_SHF			0xd0
+#define LSC_MAX			0xd4
+
+/* Noise Filter 1. Ofsets from start address given */
+#define D2F_1ST			0xd8
+#define D2F_EN			0x0
+#define D2F_TYP			0x4
+#define D2F_THR			0x8
+#define D2F_STR			0x28
+#define D2F_SPR			0x48
+#define D2F_EDG_MIN		0x68
+#define D2F_EDG_MAX		0x6c
+
+/* Noise Filter 2 */
+#define D2F_2ND			0x148
+
+/* GIC */
+#define GIC_EN			0x1b8
+#define GIC_TYP			0x1bc
+#define GIC_GAN			0x1c0
+#define GIC_NFGAN		0x1c4
+#define GIC_THR			0x1c8
+#define GIC_SLP			0x1cc
+
+/* White Balance */
+#define WB2_OFT_R		0x1d0
+#define WB2_OFT_GR		0x1d4
+#define WB2_OFT_GB		0x1d8
+#define WB2_OFT_B		0x1dc
+#define WB2_WGN_R		0x1e0
+#define WB2_WGN_GR		0x1e4
+#define WB2_WGN_GB		0x1e8
+#define WB2_WGN_B		0x1ec
+
+/* CFA interpolation */
+#define CFA_MODE		0x1f0
+#define CFA_2DIR_HPF_THR	0x1f4
+#define CFA_2DIR_HPF_SLP	0x1f8
+#define CFA_2DIR_MIX_THR	0x1fc
+#define CFA_2DIR_MIX_SLP	0x200
+#define CFA_2DIR_DIR_THR	0x204
+#define CFA_2DIR_DIR_SLP	0x208
+#define CFA_2DIR_NDWT		0x20c
+#define CFA_MONO_HUE_FRA	0x210
+#define CFA_MONO_EDG_THR	0x214
+#define CFA_MONO_THR_MIN	0x218
+#define CFA_MONO_THR_SLP	0x21c
+#define CFA_MONO_SLP_MIN	0x220
+#define CFA_MONO_SLP_SLP	0x224
+#define CFA_MONO_LPWT		0x228
+
+/* RGB to RGB conversiona - 1st */
+#define RGB1_MUL_BASE		0x22c
+/* Offsets from base */
+#define RGB_MUL_RR		0x0
+#define RGB_MUL_GR		0x4
+#define RGB_MUL_BR		0x8
+#define RGB_MUL_RG		0xc
+#define RGB_MUL_GG		0x10
+#define RGB_MUL_BG		0x14
+#define RGB_MUL_RB		0x18
+#define RGB_MUL_GB		0x1c
+#define RGB_MUL_BB		0x20
+#define RGB_OFT_OR		0x24
+#define RGB_OFT_OG		0x28
+#define RGB_OFT_OB		0x2c
+
+/* Gamma */
+#define GMM_CFG			0x25c
+
+/* RGB to RGB conversiona - 2nd */
+#define RGB2_MUL_BASE		0x260
+
+/* 3D LUT */
+#define D3LUT_EN		0x290
+
+/* RGB to YUV(YCbCr) conversion */
+#define YUV_ADJ			0x294
+#define YUV_MUL_RY		0x298
+#define YUV_MUL_GY		0x29c
+#define YUV_MUL_BY		0x2a0
+#define YUV_MUL_RCB		0x2a4
+#define YUV_MUL_GCB		0x2a8
+#define YUV_MUL_BCB		0x2ac
+#define YUV_MUL_RCR		0x2b0
+#define YUV_MUL_GCR		0x2b4
+#define YUV_MUL_BCR		0x2b8
+#define YUV_OFT_Y		0x2bc
+#define YUV_OFT_CB		0x2c0
+#define YUV_OFT_CR		0x2c4
+#define YUV_PHS			0x2c8
+
+/* Global Brightness and Contrast */
+#define GBCE_EN			0x2cc
+#define GBCE_TYP		0x2d0
+
+/* Edge Enhancer */
+#define YEE_EN			0x2d4
+#define YEE_TYP			0x2d8
+#define YEE_SHF			0x2dc
+#define YEE_MUL_00		0x2e0
+#define YEE_MUL_01		0x2e4
+#define YEE_MUL_02		0x2e8
+#define YEE_MUL_10		0x2ec
+#define YEE_MUL_11		0x2f0
+#define YEE_MUL_12		0x2f4
+#define YEE_MUL_20		0x2f8
+#define YEE_MUL_21		0x2fc
+#define YEE_MUL_22		0x300
+#define YEE_THR			0x304
+#define YEE_E_GAN		0x308
+#define YEE_E_THR1		0x30c
+#define YEE_E_THR2		0x310
+#define YEE_G_GAN		0x314
+#define YEE_G_OFT		0x318
+
+/* Chroma Artifact Reduction */
+#define CAR_EN			0x31c
+#define CAR_TYP			0x320
+#define CAR_SW			0x324
+#define CAR_HPF_TYP		0x328
+#define CAR_HPF_SHF		0x32c
+#define	CAR_HPF_THR		0x330
+#define CAR_GN1_GAN		0x334
+#define CAR_GN1_SHF		0x338
+#define CAR_GN1_MIN		0x33c
+#define CAR_GN2_GAN		0x340
+#define CAR_GN2_SHF		0x344
+#define CAR_GN2_MIN		0x348
+
+/* Chroma Gain Suppression */
+#define CGS_EN			0x34c
+#define CGS_GN1_L_THR		0x350
+#define CGS_GN1_L_GAN		0x354
+#define CGS_GN1_L_SHF		0x358
+#define CGS_GN1_L_MIN		0x35c
+#define CGS_GN1_H_THR		0x360
+#define CGS_GN1_H_GAN		0x364
+#define CGS_GN1_H_SHF		0x368
+#define CGS_GN1_H_MIN		0x36c
+#define CGS_GN2_L_THR		0x370
+#define CGS_GN2_L_GAN		0x374
+#define CGS_GN2_L_SHF		0x378
+#define CGS_GN2_L_MIN		0x37c
+
+/* Resizer */
+#define RSZ_SRC_EN		0x0
+#define RSZ_SRC_MODE		0x4
+#define RSZ_SRC_FMT0		0x8
+#define RSZ_SRC_FMT1		0xc
+#define RSZ_SRC_VPS		0x10
+#define RSZ_SRC_VSZ		0x14
+#define RSZ_SRC_HPS		0x18
+#define RSZ_SRC_HSZ		0x1c
+#define RSZ_DMA_RZA		0x20
+#define RSZ_DMA_RZB		0x24
+#define RSZ_DMA_STA		0x28
+#define RSZ_GCK_MMR		0x2c
+#define RSZ_RESERVED0		0x30
+#define RSZ_GCK_SDR		0x34
+#define RSZ_IRQ_RZA		0x38
+#define RSZ_IRQ_RZB		0x3c
+#define RSZ_YUV_Y_MIN		0x40
+#define RSZ_YUV_Y_MAX		0x44
+#define RSZ_YUV_C_MIN		0x48
+#define RSZ_YUV_C_MAX		0x4c
+#define RSZ_YUV_PHS		0x50
+#define RSZ_SEQ			0x54
+
+/* Resizer Rescale Parameters */
+#define RSZ_EN_A		0x58
+#define RSZ_EN_B		0xe8
+/* offset of the registers to be added with base register of
+   either RSZ0 or RSZ1
+*/
+#define RSZ_MODE		0x4
+#define RSZ_420			0x8
+#define RSZ_I_VPS		0xc
+#define RSZ_I_HPS		0x10
+#define RSZ_O_VSZ		0x14
+#define RSZ_O_HSZ		0x18
+#define RSZ_V_PHS_Y		0x1c
+#define RSZ_V_PHS_C		0x20
+#define RSZ_V_DIF		0x24
+#define RSZ_V_TYP		0x28
+#define RSZ_V_LPF		0x2c
+#define RSZ_H_PHS		0x30
+#define RSZ_H_PHS_ADJ		0x34
+#define RSZ_H_DIF		0x38
+#define RSZ_H_TYP		0x3c
+#define RSZ_H_LPF		0x40
+#define RSZ_DWN_EN		0x44
+#define RSZ_DWN_AV		0x48
+
+/* Resizer RGB Conversion Parameters */
+#define RSZ_RGB_EN		0x4c
+#define RSZ_RGB_TYP		0x50
+#define RSZ_RGB_BLD		0x54
+
+/* Resizer External Memory Parameters */
+#define RSZ_SDR_Y_BAD_H		0x58
+#define RSZ_SDR_Y_BAD_L		0x5c
+#define RSZ_SDR_Y_SAD_H		0x60
+#define RSZ_SDR_Y_SAD_L		0x64
+#define RSZ_SDR_Y_OFT		0x68
+#define RSZ_SDR_Y_PTR_S		0x6c
+#define RSZ_SDR_Y_PTR_E		0x70
+#define RSZ_SDR_C_BAD_H		0x74
+#define RSZ_SDR_C_BAD_L		0x78
+#define RSZ_SDR_C_SAD_H		0x7c
+#define RSZ_SDR_C_SAD_L		0x80
+#define RSZ_SDR_C_OFT		0x84
+#define RSZ_SDR_C_PTR_S		0x88
+#define RSZ_SDR_C_PTR_E		0x8c
+
+/* Macro for resizer */
+#define IPIPE_RESIZER_A(i)	(RSZ_IOBASE_VADDR + RSZ_EN_A + i)
+#define IPIPE_RESIZER_B(i)	(RSZ_IOBASE_VADDR + RSZ_EN_B + i)
+
+#define RSZ_YUV_Y_MIN		0x40
+#define RSZ_YUV_Y_MAX		0x44
+#define RSZ_YUV_C_MIN		0x48
+#define RSZ_YUV_C_MAX		0x4c
+
+#define IPIPE_GCK_MMR_DEFAULT	1
+#define IPIPE_GCK_PIX_DEFAULT	0xe
+#define RSZ_GCK_MMR_DEFAULT	1
+#define RSZ_GCK_SDR_DEFAULT	1
+
+/* LUTDPC */
+#define LUTDPC_TBL_256_EN	0
+#define LUTDPC_INF_TBL_EN	1
+#define LUT_DPC_START_ADDR	0
+#define LUT_DPC_H_POS_MASK	0x1fff
+#define LUT_DPC_V_POS_MASK	0x1fff
+#define LUT_DPC_V_POS_SHIFT	13
+#define LUT_DPC_CORR_METH_SHIFT	26
+#define LUT_DPC_MAX_SIZE	256
+#define LUT_DPC_SIZE_MASK	0x3ff
+
+/* OTFDPC */
+#define OTFDPC_DPC2_THR_MASK	0xfff
+#define OTF_DET_METHOD_SHIFT	1
+#define OTF_DPC3_0_SHF_MASK	3
+#define OTF_DPC3_0_THR_SHIFT	6
+#define OTF_DPC3_0_THR_MASK	0x3f
+#define OTF_DPC3_0_SLP_MASK	0x3f
+#define OTF_DPC3_0_DET_MASK	0xfff
+#define OTF_DPC3_0_CORR_MASK	0xfff
+
+/* NF (D2F) */
+#define D2F_SPR_VAL_MASK		0x1f
+#define D2F_SPR_VAL_SHIFT		0
+#define D2F_SHFT_VAL_MASK		3
+#define D2F_SHFT_VAL_SHIFT		5
+#define D2F_SAMPLE_METH_SHIFT		7
+#define D2F_APPLY_LSC_GAIN_SHIFT	8
+#define D2F_USE_SPR_REG_VAL		0
+#define D2F_STR_VAL_MASK		0x1f
+#define D2F_THR_VAL_MASK		0x3ff
+#define D2F_EDGE_DET_THR_MASK		0x7ff
+
+/* Green Imbalance Correction */
+#define GIC_TYP_SHIFT			0
+#define GIC_THR_SEL_SHIFT		1
+#define	GIC_APPLY_LSC_GAIN_SHIFT	2
+#define GIC_GAIN_MASK			0xff
+#define GIC_THR_MASK			0xfff
+#define GIC_SLOPE_MASK			0xfff
+#define GIC_NFGAN_INT_MASK		7
+#define GIC_NFGAN_DECI_MASK		0x1f
+
+/* WB */
+#define WB_OFFSET_MASK			0xfff
+#define WB_GAIN_INT_MASK		0xf
+#define WB_GAIN_DECI_MASK		0x1ff
+
+/* CFA */
+#define CFA_HPF_THR_2DIR_MASK		0x1fff
+#define CFA_HPF_SLOPE_2DIR_MASK		0x3ff
+#define CFA_HPF_MIX_THR_2DIR_MASK	0x1fff
+#define CFA_HPF_MIX_SLP_2DIR_MASK	0x3ff
+#define CFA_DIR_THR_2DIR_MASK		0x3ff
+#define CFA_DIR_SLP_2DIR_MASK		0x7f
+#define CFA_ND_WT_2DIR_MASK		0x3f
+#define CFA_DAA_HUE_FRA_MASK		0x3f
+#define CFA_DAA_EDG_THR_MASK		0xff
+#define CFA_DAA_THR_MIN_MASK		0x3ff
+#define CFA_DAA_THR_SLP_MASK		0x3ff
+#define CFA_DAA_SLP_MIN_MASK		0x3ff
+#define CFA_DAA_SLP_SLP_MASK		0x3ff
+#define CFA_DAA_LP_WT_MASK		0x3f
+
+/* RGB2RGB */
+#define RGB2RGB_1_OFST_MASK		0x1fff
+#define RGB2RGB_1_GAIN_INT_MASK		0xf
+#define RGB2RGB_GAIN_DECI_MASK		0xff
+#define RGB2RGB_2_OFST_MASK		0x7ff
+#define RGB2RGB_2_GAIN_INT_MASK		0x7
+
+/* Gamma */
+#define GAMMA_BYPR_SHIFT		0
+#define GAMMA_BYPG_SHIFT		1
+#define GAMMA_BYPB_SHIFT		2
+#define GAMMA_TBL_SEL_SHIFT		4
+#define GAMMA_TBL_SIZE_SHIFT		5
+#define GAMMA_MASK			0x3ff
+#define GAMMA_SHIFT			10
+
+/* 3D LUT */
+#define D3_LUT_ENTRY_MASK		0x3ff
+#define D3_LUT_ENTRY_R_SHIFT		20
+#define D3_LUT_ENTRY_G_SHIFT		10
+#define D3_LUT_ENTRY_B_SHIFT		0
+
+/* Lumina adj */
+#define	LUM_ADJ_CONTR_SHIFT		0
+#define	LUM_ADJ_BRIGHT_SHIFT		8
+
+/* RGB2YCbCr */
+#define RGB2YCBCR_OFST_MASK		0x7ff
+#define RGB2YCBCR_COEF_INT_MASK		0xf
+#define RGB2YCBCR_COEF_DECI_MASK	0xff
+
+/* GBCE */
+#define GBCE_Y_VAL_MASK			0xff
+#define GBCE_GAIN_VAL_MASK		0x3ff
+#define GBCE_ENTRY_SHIFT		10
+
+/* Edge Enhancements */
+#define YEE_HALO_RED_EN_SHIFT		1
+#define YEE_HPF_SHIFT_MASK		0xf
+#define YEE_COEF_MASK			0x3ff
+#define YEE_THR_MASK			0x3f
+#define YEE_ES_GAIN_MASK		0xfff
+#define YEE_ES_THR1_MASK		0xfff
+#define YEE_ENTRY_SHIFT			9
+#define YEE_ENTRY_MASK			0x1ff
+
+/* CAR */
+#define CAR_MF_THR			0xff
+#define CAR_SW1_SHIFT			8
+#define CAR_GAIN1_SHFT_MASK		7
+#define CAR_GAIN_MIN_MASK		0x1ff
+#define CAR_GAIN2_SHFT_MASK		0xf
+#define CAR_HPF_SHIFT_MASK		3
+
+/* CGS */
+#define CAR_SHIFT_MASK			3
+
+/* Resizer */
+#define RSZ_BYPASS_SHIFT		1
+#define RSZ_SRC_IMG_FMT_SHIFT		1
+#define RSZ_SRC_Y_C_SEL_SHIFT		2
+#define IPIPE_RSZ_VPS_MASK		0xffff
+#define IPIPE_RSZ_HPS_MASK		0xffff
+#define IPIPE_RSZ_VSZ_MASK		0x1fff
+#define IPIPE_RSZ_HSZ_MASK		0x1fff
+#define RSZ_HPS_MASK			0x1fff
+#define RSZ_VPS_MASK			0x1fff
+#define RSZ_O_HSZ_MASK			0x1fff
+#define RSZ_O_VSZ_MASK			0x1fff
+#define RSZ_V_PHS_MASK			0x3fff
+#define RSZ_V_DIF_MASK			0x3fff
+
+#define RSZA_H_FLIP_SHIFT		0
+#define RSZA_V_FLIP_SHIFT		1
+#define RSZB_H_FLIP_SHIFT		2
+#define RSZB_V_FLIP_SHIFT		3
+#define RSZ_A				0
+#define RSZ_B				1
+#define RSZ_CEN_SHIFT			1
+#define RSZ_YEN_SHIFT			0
+#define RSZ_TYP_Y_SHIFT			0
+#define RSZ_TYP_C_SHIFT			1
+#define RSZ_LPF_INT_MASK		0x3f
+#define RSZ_LPF_INT_MASK		0x3f
+#define RSZ_LPF_INT_C_SHIFT		6
+#define RSZ_H_PHS_MASK			0x3fff
+#define RSZ_H_DIF_MASK			0x3fff
+#define RSZ_DIFF_DOWN_THR		256
+#define RSZ_DWN_SCALE_AV_SZ_V_SHIFT	3
+#define RSZ_DWN_SCALE_AV_SZ_MASK	7
+#define RSZ_RGB_MSK1_SHIFT		2
+#define RSZ_RGB_MSK0_SHIFT		1
+#define RSZ_RGB_TYP_SHIFT		0
+#define RSZ_RGB_ALPHA_MASK		0xff
+
+static inline u32 regr_ip(u32 offset)
+{
+	return readl(IPIPE_IOBASE_VADDR + offset);
+}
+
+static inline u32 regw_ip(u32 val, u32 offset)
+{
+	writel(val, IPIPE_IOBASE_VADDR + offset);
+
+	return val;
+}
+
+static inline u32 r_ip_table(u32 offset)
+{
+	return readl(IPIPE_INT_TABLE_IOBASE_VADDR + offset);
+}
+
+static inline u32 w_ip_table(u32 val, u32 offset)
+{
+	writel(val, IPIPE_INT_TABLE_IOBASE_VADDR + offset);
+
+	return val;
+}
+
+static inline u32 regr_rsz(u32 offset)
+{
+	return readl(RSZ_IOBASE_VADDR + offset);
+}
+
+static inline u32 regw_rsz(u32 val, u32 offset)
+{
+	writel(val, RSZ_IOBASE_VADDR + offset);
+
+	return val;
+}
+
+#endif  /* End of #ifdef _DM365_IPIPE_HW_H */
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 03/14] davinci: vpfe: add IPIPE support for media controller driver
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 01/14] davinci: vpfe: add dm3xx IPIPEIF hardware support module Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 02/14] davinci: vpfe: add IPIPE hardware layer support Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 04/14] davinci: vpfe: add support for CCDC hardware for dm365 Prabhakar Lad
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

Add the IPIPE interfacing layer to the vpfe driver. This patch adds dm365
specific implementation of the genric imp_hw_interface interface for
programming the IPIPE block, mainly setting the resizer and previewer
configuration parameters. This is built as an independent module.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/dm365_def_para.c  |  294 ++
 drivers/media/platform/davinci/dm365_def_para.h  |   49 +
 drivers/media/platform/davinci/dm365_ipipe.c     | 3673 ++++++++++++++++++++++
 drivers/media/platform/davinci/dm365_ipipe.h     |  430 +++
 drivers/media/platform/davinci/imp_hw_if.h       |  180 ++
 drivers/media/platform/davinci/vpfe_imp_common.h |   84 +
 include/linux/davinci_vpfe.h                     |  929 ++++++
 7 files changed, 5639 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/platform/davinci/dm365_def_para.c
 create mode 100644 drivers/media/platform/davinci/dm365_def_para.h
 create mode 100644 drivers/media/platform/davinci/dm365_ipipe.c
 create mode 100644 drivers/media/platform/davinci/dm365_ipipe.h
 create mode 100644 drivers/media/platform/davinci/imp_hw_if.h
 create mode 100644 drivers/media/platform/davinci/vpfe_imp_common.h
 create mode 100644 include/linux/davinci_vpfe.h

diff --git a/drivers/media/platform/davinci/dm365_def_para.c b/drivers/media/platform/davinci/dm365_def_para.c
new file mode 100644
index 0000000..fe82298
--- /dev/null
+++ b/drivers/media/platform/davinci/dm365_def_para.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#include <linux/v4l2-mediabus.h>
+
+#include "dm365_ipipe.h"
+
+/* Defaults for lutdpc */
+struct prev_lutdpc dm365_lutdpc_defaults;
+
+/* Defaults for otfdpc */
+struct prev_otfdpc dm365_otfdpc_defaults;
+
+/* Defaults for 2D - nf */
+struct prev_nf dm365_nf_defaults;
+
+/* defaults for GIC */
+struct prev_gic dm365_gic_defaults;
+
+/* Defaults for white balance */
+struct prev_wb dm365_wb_defaults = {
+	.gain_r  = {2, 0x0},
+	.gain_gr = {2, 0x0},
+	.gain_gb = {2, 0x0},
+	.gain_b  = {2, 0x0}
+};
+
+/* Defaults for CFA */
+struct prev_cfa dm365_cfa_defaults = {
+	.alg = IPIPE_CFA_ALG_2DIRAC,
+};
+
+/* Defaults for rgb2rgb */
+struct prev_rgb2rgb dm365_rgb2rgb_defaults = {
+	.coef_rr = {1, 0},	/* 256 */
+	.coef_gr = {0, 0},
+	.coef_br = {0, 0},
+	.coef_rg = {0, 0},
+	.coef_gg = {1, 0},	/* 256 */
+	.coef_bg = {0, 0},
+	.coef_rb = {0, 0},
+	.coef_gb = {0, 0},
+	.coef_bb = {1, 0},	/* 256 */
+};
+
+/* Defaults for gamma correction */
+struct prev_gamma dm365_gamma_defaults = {
+	.tbl_sel = IPIPE_GAMMA_TBL_ROM
+};
+
+/* Defaults for 3d lut */
+struct prev_3d_lut dm365_3d_lut_defaults;
+
+/* Defaults for rgb2yuv conversion */
+struct prev_rgb2yuv dm365_rgb2yuv_defaults = {
+	.coef_ry  = {0, 0x4d},
+	.coef_gy  = {0, 0x96},
+	.coef_by  = {0, 0x1d},
+	.coef_rcb = {0xf, 0xd5},
+	.coef_gcb = {0xf, 0xab},
+	.coef_bcb = {0, 0x80},
+	.coef_rcr = {0, 0x80},
+	.coef_gcr = {0xf, 0x95},
+	.coef_bcr = {0xf, 0xeb},
+	.out_ofst_cb = 0x80,
+	.out_ofst_cr = 0x80,
+};
+
+/* Defaults for GBCE */
+struct prev_gbce dm365_gbce_defaults;
+
+/* Defaults for yuv 422 conversion */
+struct prev_yuv422_conv dm365_yuv422_conv_defaults = {
+	.chrom_pos = IPIPE_YUV422_CHR_POS_COSITE
+};
+
+/* Defaults for Edge Ehnancements  */
+struct prev_yee dm365_yee_defaults;
+
+/* Defaults for CAR conversion */
+struct prev_car dm365_car_defaults;
+
+/* Defaults for CGS */
+struct prev_cgs dm365_cgs_defaults;
+
+#define  WIDTH_I 640
+#define  HEIGHT_I 480
+#define  WIDTH_O 640
+#define  HEIGHT_O 480
+
+/* default ipipeif settings */
+struct ipipeif_5_1 ipipeif_5_1_defaults = {
+	.pack_mode = IPIPEIF_5_1_PACK_16_BIT,
+	.data_shift = IPIPEIF_BITS11_0,
+	.source1 = IPIPEIF_SRC1_PARALLEL_PORT,
+	.clk_div = {
+		.m = 1,	/* clock = sdram clock * (m/n) */
+		.n = 6
+	},
+	.dpcm = {
+		.type = IPIPEIF_DPCM_8BIT_12BIT,
+		.pred = V4L2_DPCM_PREDICTOR_SIMPLE
+	},
+	.chroma_phase = IPIPEIF_CBCR_Y,
+	.isif_port = {
+		.if_type = V4L2_MBUS_FMT_SGRBG12_1X12,
+		.hdpol = VPFE_PINPOL_POSITIVE,
+		.vdpol = VPFE_PINPOL_POSITIVE
+	},
+	.clip = 4095,
+};
+
+struct ipipe_params dm365_ipipe_defs = {
+	.ipipeif_param = {
+		.mode = IPIPEIF_ONE_SHOT,
+		.source = IPIPEIF_SDRAM_RAW,
+		.clock_select = IPIPEIF_SDRAM_CLK,
+		.glob_hor_size = WIDTH_I + 8,
+		.glob_ver_size = HEIGHT_I + 10,
+		.hnum = WIDTH_I,
+		.vnum = HEIGHT_I,
+		.adofs = WIDTH_I * 2,
+		.rsz = 16,	/* resize ratio 16/rsz */
+		.decimation = IPIPEIF_DECIMATION_OFF,
+		.avg_filter = IPIPEIF_AVG_OFF,
+		.gain = 0x200,	/* U10Q9 */
+	},
+	.ipipe_mode = IPIPEIF_ONE_SHOT,
+	.ipipe_dpaths_fmt = IPIPE_RAW2YUV,
+	.ipipe_vsz = HEIGHT_I - 1,
+	.ipipe_hsz = WIDTH_I - 1,
+	.ipipe_colpat = ipipe_sgrbg_pattern,
+	.rsz_common = {
+		.vsz = HEIGHT_I - 1,
+		.hsz = WIDTH_I - 1,
+		.src_img_fmt = RSZ_IMG_422,
+		.raw_flip = 1,	/* flip preserve Raw format */
+		.source = IPIPE_DATA,
+		.passthrough = IPIPE_BYPASS_OFF,
+		.yuv_y_max = 255,
+		.yuv_c_max = 255,
+		.rsz_seq_crv = DISABLE,
+		.out_chr_pos = IPIPE_YUV422_CHR_POS_COSITE
+	},
+	.rsz_rsc_param = {
+		{
+			.mode = IPIPEIF_ONE_SHOT,
+			.h_flip = DISABLE,
+			.v_flip = DISABLE,
+			.cen = DISABLE,
+			.yen = DISABLE,
+			.o_vsz = HEIGHT_O - 1,
+			.o_hsz = WIDTH_O - 1,
+			.v_dif = 256,
+			.v_typ_y = RSZ_INTP_CUBIC,
+			.h_typ_c = RSZ_INTP_CUBIC,
+			.h_dif = 256,
+			.h_typ_y = RSZ_INTP_CUBIC,
+			.h_typ_c = RSZ_INTP_CUBIC,
+			.h_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+			.v_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+		},
+		{
+			.mode = IPIPEIF_ONE_SHOT,
+			.h_flip = DISABLE,
+			.v_flip = DISABLE,
+			.cen = DISABLE,
+			.yen = DISABLE,
+			.o_vsz = HEIGHT_O - 1,
+			.o_hsz = WIDTH_O - 1,
+			.v_dif = 256,
+			.v_typ_y = RSZ_INTP_CUBIC,
+			.h_typ_c = RSZ_INTP_CUBIC,
+			.h_dif = 256,
+			.h_typ_y = RSZ_INTP_CUBIC,
+			.h_typ_c = RSZ_INTP_CUBIC,
+			.h_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+			.v_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+		},
+	},
+	.rsz2rgb = {
+		{
+			.rgb_en = DISABLE
+		},
+		{
+			.rgb_en = DISABLE
+		}
+	},
+	.ext_mem_param = {
+		{
+			.rsz_sdr_oft_y = WIDTH_O << 1,
+			.rsz_sdr_ptr_e_y = HEIGHT_O,
+			.rsz_sdr_oft_c = WIDTH_O,
+			.rsz_sdr_ptr_e_c = HEIGHT_O >> 1,
+		},
+		{
+			.rsz_sdr_oft_y = WIDTH_O << 1,
+			.rsz_sdr_ptr_e_y = HEIGHT_O,
+			.rsz_sdr_oft_c = WIDTH_O,
+			.rsz_sdr_ptr_e_c = HEIGHT_O,
+		},
+	},
+	.rsz_en[0] = ENABLE,
+	.rsz_en[1] = DISABLE
+};
+
+struct prev_ipipeif_config dm365_prev_ss_config_defs = {
+	.bypass = IPIPE_BYPASS_OFF,
+	.input_spec = {
+		.ppln = WIDTH_I + 8,
+		.lpfr = HEIGHT_I + 10,
+		.clk_div = {1, 6},
+	},
+	.rsz = 16,	/* resize ratio 16/rsz */
+	.avg_filter_en = IPIPEIF_AVG_OFF,
+	.dpc = {0, 0},
+	.clip = 4095,
+};
+
+struct prev_ipipeif_config dm365_prev_cont_config_defs = {
+	.bypass = IPIPE_BYPASS_OFF,
+	.rsz = 16,
+	.avg_filter_en = IPIPEIF_AVG_OFF,
+	.clip = 4095,
+};
+
+struct rsz_config dm365_rsz_ss_config_defs = {
+	.input = {
+		.ppln = WIDTH_I + 8,
+		.lpfr = HEIGHT_I + 10,
+		.clk_div = {1, 6},
+		.rsz = 16,	/* resize ratio 16/rsz */
+		.avg_filter_en = IPIPEIF_AVG_OFF,
+	},
+	.output1 = {
+		.v_typ_y = RSZ_INTP_CUBIC,
+		.v_typ_c = RSZ_INTP_CUBIC,
+		.h_typ_y = RSZ_INTP_CUBIC,
+		.h_typ_c = RSZ_INTP_CUBIC,
+		.h_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+		.v_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+	},
+	.output2 = {
+		.v_typ_y = RSZ_INTP_CUBIC,
+		.v_typ_c = RSZ_INTP_CUBIC,
+		.h_typ_y = RSZ_INTP_CUBIC,
+		.h_typ_c = RSZ_INTP_CUBIC,
+		.h_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+		.v_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+	},
+	.yuv_y_max = 255,
+	.yuv_c_max = 255,
+	.out_chr_pos = IPIPE_YUV422_CHR_POS_COSITE,
+};
+
+struct rsz_config dm365_rsz_cont_config_defs = {
+	.output1 = {
+		.v_typ_y = RSZ_INTP_CUBIC,
+		.v_typ_c = RSZ_INTP_CUBIC,
+		.h_typ_y = RSZ_INTP_CUBIC,
+		.h_typ_c = RSZ_INTP_CUBIC,
+		.h_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+		.v_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+	},
+	.output2 = {
+		.v_typ_y = RSZ_INTP_CUBIC,
+		.v_typ_c = RSZ_INTP_CUBIC,
+		.h_typ_y = RSZ_INTP_CUBIC,
+		.h_typ_c = RSZ_INTP_CUBIC,
+		.h_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+		.v_dscale_ave_sz = IPIPE_DWN_SCALE_1_OVER_2,
+	},
+	.yuv_y_max = 255,
+	.yuv_c_max = 255,
+	.out_chr_pos = IPIPE_YUV422_CHR_POS_COSITE,
+};
diff --git a/drivers/media/platform/davinci/dm365_def_para.h b/drivers/media/platform/davinci/dm365_def_para.h
new file mode 100644
index 0000000..6b3281e
--- /dev/null
+++ b/drivers/media/platform/davinci/dm365_def_para.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _DM365_DEF_PARA_H
+#define _DM365_DEF_PARA_H
+
+#include "dm365_ipipe.h"
+
+extern struct prev_lutdpc dm365_lutdpc_defaults;
+extern struct prev_otfdpc dm365_otfdpc_defaults;
+extern struct prev_nf dm365_nf_defaults;
+extern struct prev_gic dm365_gic_defaults;
+extern struct prev_wb dm365_wb_defaults;
+extern struct prev_cfa dm365_cfa_defaults;
+extern struct prev_rgb2rgb dm365_rgb2rgb_defaults;
+extern struct prev_gamma dm365_gamma_defaults;
+extern struct prev_3d_lut dm365_3d_lut_defaults;
+extern struct prev_rgb2yuv dm365_rgb2yuv_defaults;
+extern struct prev_yuv422_conv dm365_yuv422_conv_defaults;
+extern struct prev_gbce dm365_gbce_defaults;
+extern struct prev_yee dm365_yee_defaults;
+extern struct prev_car dm365_car_defaults;
+extern struct prev_cgs dm365_cgs_defaults;
+extern struct ipipe_params dm365_ipipe_defs;
+extern struct prev_single_shot_config dm365_prev_ss_config_defs;
+extern struct prev_continuous_config dm365_prev_cont_config_defs;
+extern struct rsz_single_shot_config dm365_rsz_ss_config_defs;
+extern struct rsz_continuous_config dm365_rsz_cont_config_defs;
+extern struct ipipeif_5_1 ipipeif_5_1_defaults;
+
+#endif
diff --git a/drivers/media/platform/davinci/dm365_ipipe.c b/drivers/media/platform/davinci/dm365_ipipe.c
new file mode 100644
index 0000000..5ca1138
--- /dev/null
+++ b/drivers/media/platform/davinci/dm365_ipipe.c
@@ -0,0 +1,3673 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+#include <linux/dma-mapping.h>
+#include <linux/v4l2-mediabus.h>
+
+#include "dm365_ipipe.h"
+#include "imp_hw_if.h"
+#include "dm365_ipipe_hw.h"
+#include "dm365_def_para.h"
+
+static int dpcm_predictor;
+static int ipipeif_gain;
+
+static int ipipe_enum_pix(void *ipipe, u32 *pix, int i)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	if (i >= ARRAY_SIZE(oper_state->ipipe_raw_yuv_pix_formats))
+		return -EINVAL;
+
+	*pix = oper_state->ipipe_raw_yuv_pix_formats[i];
+	return 0;
+}
+
+/* IPIPE hardware limits */
+#define IPIPE_MAX_OUTPUT_WIDTH_A	2176
+#define IPIPE_MAX_OUTPUT_WIDTH_B	640
+
+static int ipipe_get_max_output_width(int rsz)
+{
+	if (rsz == RSZ_A)
+		return IPIPE_MAX_OUTPUT_WIDTH_A;
+	return IPIPE_MAX_OUTPUT_WIDTH_B;
+}
+
+/* Based on max resolution supported. QXGA */
+#define IPIPE_MAX_OUTPUT_HEIGHT_A	1536
+/* Based on max resolution supported. VGA */
+#define IPIPE_MAX_OUTPUT_HEIGHT_B	480
+
+static int ipipe_get_max_output_height(int rsz)
+{
+	if (rsz == RSZ_A)
+		return IPIPE_MAX_OUTPUT_HEIGHT_A;
+	return IPIPE_MAX_OUTPUT_HEIGHT_B;
+}
+
+static int ipipe_serialize(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return oper_state->en_serializer;
+}
+
+static int ipipe_set_ipipe_if_address(void *config, unsigned int address)
+{
+	struct ipipeif *if_params;
+
+	if (!config)
+		return -EINVAL;
+
+	if_params = &((struct ipipe_params *)config)->ipipeif_param;
+
+	return ipipeif_set_address(if_params, address);
+}
+
+static void ipipe_lock_chain(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	mutex_lock(&oper_state->lock);
+	oper_state->resource_in_use = 1;
+	mutex_unlock(&oper_state->lock);
+}
+
+static void ipipe_unlock_chain(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	mutex_lock(&oper_state->lock);
+	oper_state->resource_in_use = 0;
+	oper_state->prev_config_state = STATE_NOT_CONFIGURED;
+	oper_state->rsz_config_state = STATE_NOT_CONFIGURED;
+	oper_state->rsz_chained = 0;
+	mutex_unlock(&oper_state->lock);
+}
+
+static int
+ipipe_process_pix_fmts(enum v4l2_mbus_pixelcode in_pix_fmt,
+		       enum v4l2_mbus_pixelcode out_pix_fmt,
+		       struct ipipe_params *param)
+{
+	enum v4l2_mbus_pixelcode temp_pix_fmt;
+
+	switch (in_pix_fmt) {
+	case V4L2_MBUS_FMT_SBGGR8_1X8:
+		temp_pix_fmt = V4L2_MBUS_FMT_SGRBG12_1X12;
+		param->ipipeif_param.var.if_5_1.pack_mode
+		    = IPIPEIF_5_1_PACK_8_BIT;
+		break;
+	case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
+		param->ipipeif_param.var.if_5_1.pack_mode
+		    = IPIPEIF_5_1_PACK_8_BIT_A_LAW;
+		temp_pix_fmt = V4L2_MBUS_FMT_SGRBG12_1X12;
+		break;
+	case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+		param->ipipeif_param.var.if_5_1.pack_mode
+		    = IPIPEIF_5_1_PACK_8_BIT;
+		param->ipipeif_param.var.if_5_1.dpcm.en = 1;
+		temp_pix_fmt = V4L2_MBUS_FMT_SGRBG12_1X12;
+		break;
+	case V4L2_MBUS_FMT_SGRBG12_1X12:
+		param->ipipeif_param.var.if_5_1.pack_mode
+		    = IPIPEIF_5_1_PACK_16_BIT;
+		temp_pix_fmt = V4L2_MBUS_FMT_SGRBG12_1X12;
+		break;
+	case V4L2_MBUS_FMT_SBGGR12_1X12:
+		param->ipipeif_param.var.if_5_1.pack_mode
+		    = IPIPEIF_5_1_PACK_12_BIT;
+		temp_pix_fmt = V4L2_MBUS_FMT_SGRBG12_1X12;
+		break;
+	case V4L2_MBUS_FMT_Y8_1X8:
+		param->ipipeif_param.var.if_5_1.pack_mode
+			= IPIPEIF_5_1_PACK_8_BIT;
+		temp_pix_fmt = V4L2_MBUS_FMT_UYVY8_2X8;
+		break;
+	case V4L2_MBUS_FMT_UV8_1X8:
+		param->ipipeif_param.var.if_5_1.pack_mode
+			= IPIPEIF_5_1_PACK_8_BIT;
+		temp_pix_fmt = V4L2_MBUS_FMT_UYVY8_2X8;
+		break;
+	default:
+		temp_pix_fmt = V4L2_MBUS_FMT_UYVY8_2X8;
+	}
+
+	if (temp_pix_fmt == V4L2_MBUS_FMT_SGRBG12_1X12) {
+		if (out_pix_fmt == V4L2_MBUS_FMT_SGRBG12_1X12)
+			param->ipipe_dpaths_fmt = IPIPE_RAW2RAW;
+		else if (out_pix_fmt == V4L2_MBUS_FMT_UYVY8_2X8 ||
+			 out_pix_fmt == V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+			param->ipipe_dpaths_fmt = IPIPE_RAW2YUV;
+		else
+			return -EINVAL;
+	} else if (temp_pix_fmt == V4L2_MBUS_FMT_UYVY8_2X8) {
+		switch (out_pix_fmt) {
+		case V4L2_MBUS_FMT_UYVY8_2X8:
+		case V4L2_MBUS_FMT_YDYUYDYV8_1X16:
+		case V4L2_MBUS_FMT_Y8_1X8:
+		case V4L2_MBUS_FMT_UV8_1X8:
+			param->ipipe_dpaths_fmt = IPIPE_YUV2YUV;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+/*
+ * calculate_resize_ratios() - Calculates resize ratio for resizer A or B.
+ *			       This is called after setting the input size
+ *			       or output size.
+ */
+static void calculate_resize_ratios(struct ipipe_params *param, int index)
+{
+	param->rsz_rsc_param[index].h_dif = ((param->ipipe_hsz + 1) * 256) /
+					(param->rsz_rsc_param[index].o_hsz + 1);
+	param->rsz_rsc_param[index].v_dif = ((param->ipipe_vsz + 1) * 256) /
+					(param->rsz_rsc_param[index].o_vsz + 1);
+}
+
+static int ipipe_do_hw_setup(struct device *dev, void *ipipe, void *config)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct ipipe_params *param = (struct ipipe_params *)config;
+	int ret;
+
+	dev_dbg(dev, "ipipe_do_hw_setup\n");
+	ret = mutex_lock_interruptible(&oper_state->lock);
+	if (ret)
+		return ret;
+
+	if (!config && oper_state->oper_mode == IMP_MODE_CONTINUOUS) {
+		/* continuous mode */
+		param = oper_state->shared_config_param;
+		if (param->rsz_en[RSZ_A])
+			calculate_resize_ratios(param, RSZ_A);
+		if (param->rsz_en[RSZ_B])
+			calculate_resize_ratios(param, RSZ_B);
+		ret = ipipe_hw_setup(param);
+	}
+	mutex_unlock(&oper_state->lock);
+
+	return ret;
+}
+
+static unsigned int ipipe_rsz_chain_state(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return oper_state->rsz_chained;
+}
+
+static void
+ipipe_update_outbuf1_address(void *ipipe, void *config, unsigned int address)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	if (!config && oper_state->oper_mode == IMP_MODE_CONTINUOUS)
+		return rsz_set_output_address(oper_state->shared_config_param,
+					      0, address);
+
+	rsz_set_output_address((struct ipipe_params *)config, 0, address);
+}
+
+static void
+ipipe_update_outbuf2_address(void *ipipe, void *config, unsigned int address)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	if (!config && oper_state->oper_mode == IMP_MODE_CONTINUOUS)
+		return rsz_set_output_address(oper_state->shared_config_param,
+					      1, address);
+
+	rsz_set_output_address((struct ipipe_params *)config, 1, address);
+}
+
+static void ipipe_enable(void *ipipe, unsigned char en, void *config)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct ipipe_params *param = (struct ipipe_params *)config;
+	unsigned char ret;
+
+	if (en)
+		en = !!en;
+
+	if (oper_state->oper_mode == IMP_MODE_CONTINUOUS)
+		param = oper_state->shared_config_param;
+
+	if (oper_state->oper_mode == IMP_MODE_SINGLE_SHOT && en) {
+		/* for single-shot mode, need to wait for h/w to
+		   reset many register bits */
+		if (param->rsz_common.source == IPIPE_DATA) {
+			do {
+				ret = regr_ip(IPIPE_SRC_EN);
+			} while (ret);
+		}
+		do {
+			ret = regr_rsz(RSZ_SRC_EN);
+		} while (ret);
+		if (param->rsz_en[RSZ_A]) {
+			do {
+				ret = regr_rsz(RSZ_A);
+			} while (ret);
+		}
+		if (en && param->rsz_en[RSZ_B]) {
+			do {
+				ret = regr_rsz(RSZ_B);
+			} while (ret);
+		}
+		do {
+			ret = ipipeif_get_enable();
+		} while (ret & 0x1);
+	}
+
+	if (param->rsz_common.source == IPIPE_DATA)
+		regw_ip(en, IPIPE_SRC_EN);
+
+	if (param->rsz_en[RSZ_A])
+		rsz_enable(RSZ_A, en);
+
+	if (param->rsz_en[RSZ_B])
+		rsz_enable(RSZ_B, en);
+
+	if (oper_state->oper_mode == IMP_MODE_SINGLE_SHOT)
+		ipipeif_set_enable();
+}
+
+static int
+validate_lutdpc_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	int i;
+
+	if (oper_state->lutdpc.en > 1 ||
+	    oper_state->lutdpc.repl_white > 1 ||
+	    oper_state->lutdpc.dpc_size > LUT_DPC_MAX_SIZE)
+		return -EINVAL;
+
+	if (oper_state->lutdpc.en && !oper_state->lutdpc.table)
+		return -EINVAL;
+
+	for (i = 0; i < oper_state->lutdpc.dpc_size; i++) {
+		if (oper_state->lutdpc.table[i].horz_pos > LUT_DPC_H_POS_MASK ||
+		    oper_state->lutdpc.table[i].vert_pos > LUT_DPC_V_POS_MASK)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+set_lutdpc_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_lutdpc *dpc_param;
+
+	if (!param) {
+		/* Copy defaults for lut dfc */
+		memcpy((void *)&oper_state->lutdpc,
+		       (void *)&dm365_lutdpc_defaults,
+		       sizeof(struct prev_lutdpc));
+		goto success;
+	}
+
+	if (len != sizeof(struct prev_lutdpc)) {
+		dev_err(dev,
+			"set_lutdpc_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	dpc_param = (struct prev_lutdpc *)param;
+	oper_state->lutdpc.en = dpc_param->en;
+	oper_state->lutdpc.repl_white = dpc_param->repl_white;
+	oper_state->lutdpc.dpc_size = dpc_param->dpc_size;
+
+	if (!memcpy((void *)&oper_state->lutdpc.table,
+		(void *)&dpc_param->table, (oper_state->lutdpc.dpc_size *
+		sizeof(struct ipipe_lutdpc_entry)))) {
+		dev_err(dev, "set_lutdpc_params: Error in copying dfc table\n");
+		return -EFAULT;
+	}
+	if (validate_lutdpc_params(dev, oper_state) < 0)
+		return -EINVAL;
+
+success:
+	ipipe_set_lutdpc_regs(&oper_state->lutdpc);
+
+	return 0;
+}
+
+static int
+get_lutdpc_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_lutdpc *lut_param = (struct prev_lutdpc *)param;
+
+	if (len != sizeof(struct prev_lutdpc)) {
+		dev_err(dev,
+			"get_lutdpc_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+
+	lut_param->en = oper_state->lutdpc.en;
+	lut_param->repl_white = oper_state->lutdpc.repl_white;
+	lut_param->dpc_size = oper_state->lutdpc.dpc_size;
+	if (!memcpy((void *)lut_param->table, (void *)oper_state->lutdpc.table,
+		(oper_state->lutdpc.dpc_size *
+		sizeof(struct ipipe_lutdpc_entry)))) {
+		dev_err(dev,
+			"get_lutdpc_params: Table Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_otfdpc_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	struct prev_otfdpc *dpc_param =
+				(struct prev_otfdpc *)&oper_state->otfdpc;
+	struct prev_otfdpc_2_0 *dpc_2_0;
+	struct prev_otfdpc_3_0 *dpc_3_0;
+
+	if (dpc_param->en > 1)
+		return -EINVAL;
+	if (dpc_param->alg == IPIPE_OTFDPC_2_0) {
+		dpc_2_0 = &dpc_param->alg_cfg.dpc_2_0;
+		if (dpc_2_0->det_thr.r > OTFDPC_DPC2_THR_MASK ||
+		    dpc_2_0->det_thr.gr > OTFDPC_DPC2_THR_MASK ||
+		    dpc_2_0->det_thr.gb > OTFDPC_DPC2_THR_MASK ||
+		    dpc_2_0->det_thr.b > OTFDPC_DPC2_THR_MASK ||
+		    dpc_2_0->corr_thr.r > OTFDPC_DPC2_THR_MASK ||
+		    dpc_2_0->corr_thr.gr > OTFDPC_DPC2_THR_MASK ||
+		    dpc_2_0->corr_thr.gb > OTFDPC_DPC2_THR_MASK ||
+		    dpc_2_0->corr_thr.b > OTFDPC_DPC2_THR_MASK)
+			return -EINVAL;
+		return 0;
+	}
+
+	dpc_3_0 = &dpc_param->alg_cfg.dpc_3_0;
+	if (dpc_3_0->act_adj_shf > OTF_DPC3_0_SHF_MASK ||
+	    dpc_3_0->det_thr > OTF_DPC3_0_DET_MASK ||
+	    dpc_3_0->det_slp > OTF_DPC3_0_SLP_MASK ||
+	    dpc_3_0->det_thr_min > OTF_DPC3_0_DET_MASK ||
+	    dpc_3_0->det_thr_max > OTF_DPC3_0_DET_MASK ||
+	    dpc_3_0->corr_thr > OTF_DPC3_0_CORR_MASK ||
+	    dpc_3_0->corr_slp > OTF_DPC3_0_SLP_MASK ||
+	    dpc_3_0->corr_thr_min > OTF_DPC3_0_CORR_MASK ||
+	    dpc_3_0->corr_thr_max > OTF_DPC3_0_CORR_MASK)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+set_otfdpc_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_otfdpc *dpc_param = (struct prev_otfdpc *)param;
+
+	if (!param) {
+		/* Copy defaults for dpc2.0 defaults */
+		memcpy((void *)&oper_state->otfdpc,
+		       (void *)&dm365_otfdpc_defaults,
+		       sizeof(struct ipipe_otfdpc_2_0));
+	} else {
+		if (len != sizeof(struct prev_otfdpc)) {
+			dev_err(dev,
+			  "set_otfdpc_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->otfdpc, (void *)dpc_param,
+				   sizeof(struct prev_otfdpc))) {
+			dev_err(dev, "set_otfdpc_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+
+		if (validate_otfdpc_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+
+	ipipe_set_otfdpc_regs(&oper_state->otfdpc);
+
+	return 0;
+}
+
+static int
+get_otfdpc_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_otfdpc *dpc_param = (struct prev_otfdpc *)param;
+
+	if (len != sizeof(struct prev_otfdpc)) {
+		dev_err(dev,
+			"get_otfdpc_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)dpc_param, (void *)&oper_state->otfdpc,
+				sizeof(struct prev_otfdpc))) {
+		dev_err(dev,
+			"get_otfdpc_params: Error in copy dpc table to user\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_nf_params(struct device *dev,
+		   struct ipipe_oper_state *oper_state,
+		   unsigned int id)
+{
+	struct prev_nf *nf_param = &oper_state->nf1;
+	int i;
+
+	if (id)
+		nf_param = &oper_state->nf2;
+	if (nf_param->en > 1 ||
+	    nf_param->shft_val > D2F_SHFT_VAL_MASK ||
+	    nf_param->spread_val > D2F_SPR_VAL_MASK ||
+	    nf_param->apply_lsc_gain > 1 ||
+	    nf_param->edge_det_min_thr > D2F_EDGE_DET_THR_MASK ||
+	    nf_param->edge_det_max_thr > D2F_EDGE_DET_THR_MASK)
+		return -EINVAL;
+
+	for (i = 0; i < IPIPE_NF_THR_TABLE_SIZE; i++)
+		if (nf_param->thr[i] > D2F_THR_VAL_MASK)
+			return -EINVAL;
+	for (i = 0; i < IPIPE_NF_STR_TABLE_SIZE; i++)
+		if (nf_param->str[i] > D2F_STR_VAL_MASK)
+			return -EINVAL;
+	return 0;
+}
+
+static int
+set_nf_params(struct device *dev, struct ipipe_oper_state *oper_state,
+	      unsigned int id, void *param, int len)
+{
+	struct prev_nf *nf_param = (struct prev_nf *)param;
+	struct prev_nf *nf = &oper_state->nf1;
+
+	if (id)
+		nf = &oper_state->nf2;
+	if (!nf_param) {
+		/* Copy defaults for nf */
+		memcpy((void *)nf, (void *)&dm365_nf_defaults,
+					sizeof(struct prev_nf));
+		memset((void *)nf->thr, 0, IPIPE_NF_THR_TABLE_SIZE);
+		memset((void *)nf->str, 0, IPIPE_NF_THR_TABLE_SIZE);
+	} else {
+		if (len != sizeof(struct prev_nf)) {
+			dev_err(dev,
+			       "set_nf_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)nf, (void *)nf_param,
+					sizeof(struct prev_nf))) {
+			dev_err(dev, "set_nf_params: Error in copy\n");
+			return -EFAULT;
+		}
+		if (validate_nf_params(dev, oper_state, id) < 0)
+			return -EINVAL;
+	}
+	/* Now set the values in the hw */
+	ipipe_set_d2f_regs(id, nf);
+
+	return 0;
+}
+
+static int set_nf1_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return set_nf_params(dev, oper_state, 0, param, len);
+}
+
+static int set_nf2_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return set_nf_params(dev, oper_state, 1, param, len);
+}
+
+static int
+get_nf_params(struct device *dev, struct ipipe_oper_state *oper_state,
+	      unsigned int id, void *param, int len)
+{
+	struct prev_nf *nf_param = (struct prev_nf *)param;
+	struct prev_nf *nf = &oper_state->nf1;
+
+	if (len != sizeof(struct prev_nf)) {
+		dev_err(dev, "get_nf_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	if (id)
+		nf = &oper_state->nf2;
+	if (!memcpy((void *)nf_param, (void *)nf, sizeof(struct prev_nf))) {
+		dev_err(dev, "get_nf_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int get_nf1_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return get_nf_params(dev, oper_state, 0, param, len);
+}
+
+static int get_nf2_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return get_nf_params(dev, oper_state, 1, param, len);
+}
+
+static int
+validate_gic_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	if (oper_state->gic.en > 1 ||
+	    oper_state->gic.gain > GIC_GAIN_MASK ||
+	    oper_state->gic.thr > GIC_THR_MASK ||
+	    oper_state->gic.slope > GIC_SLOPE_MASK ||
+	    oper_state->gic.apply_lsc_gain > 1 ||
+	    oper_state->gic.nf2_thr_gain.integer > GIC_NFGAN_INT_MASK ||
+	    oper_state->gic.nf2_thr_gain.decimal > GIC_NFGAN_DECI_MASK)
+		return -EINVAL;
+	return 0;
+}
+
+static int set_gic_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_gic *gic_param = (struct prev_gic *)param;
+
+	if (!gic_param) {
+		/* Copy defaults for nf */
+		memcpy((void *)&oper_state->gic, (void *)&dm365_gic_defaults,
+					sizeof(struct prev_gic));
+	} else {
+		if (len != sizeof(struct prev_gic)) {
+			dev_err(dev,
+			      "set_gic_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->gic, (void *)gic_param,
+					sizeof(struct prev_gic))) {
+			dev_err(dev, "set_gic_params: Error in copy\n");
+			return -EFAULT;
+		}
+		if (validate_gic_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+	/* Now set the values in the hw */
+	ipipe_set_gic_regs(&oper_state->gic);
+
+	return 0;
+}
+
+static int get_gic_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_gic *gic_param = (struct prev_gic *)param;
+
+	if (len != sizeof(struct prev_gic)) {
+		dev_err(dev, "get_gic_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+
+	if (!memcpy((void *)gic_param, (void *)&oper_state->gic,
+		sizeof(struct prev_gic))) {
+		dev_err(dev, "get_gic_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_wb_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	if (oper_state->wb.ofst_r > WB_OFFSET_MASK ||
+	    oper_state->wb.ofst_gr > WB_OFFSET_MASK ||
+	    oper_state->wb.ofst_gb > WB_OFFSET_MASK ||
+	    oper_state->wb.ofst_b > WB_OFFSET_MASK ||
+	    oper_state->wb.gain_r.integer > WB_GAIN_INT_MASK ||
+	    oper_state->wb.gain_r.decimal > WB_GAIN_DECI_MASK ||
+	    oper_state->wb.gain_gr.integer > WB_GAIN_INT_MASK ||
+	    oper_state->wb.gain_gr.decimal > WB_GAIN_DECI_MASK ||
+	    oper_state->wb.gain_gb.integer > WB_GAIN_INT_MASK ||
+	    oper_state->wb.gain_gb.decimal > WB_GAIN_DECI_MASK ||
+	    oper_state->wb.gain_b.integer > WB_GAIN_INT_MASK ||
+	    oper_state->wb.gain_b.decimal > WB_GAIN_DECI_MASK)
+		return -EINVAL;
+	return 0;
+}
+
+static int set_wb_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_wb *wb_param = (struct prev_wb *)param;
+
+	dev_dbg(dev, "set_wb_params\n");
+	if (!wb_param) {
+		/* Copy defaults for wb */
+		memcpy((void *)&oper_state->wb, (void *)&dm365_wb_defaults,
+						sizeof(struct prev_wb));
+	} else {
+		if (len != sizeof(struct prev_wb)) {
+			dev_err(dev,
+			      "set_wb_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->wb, (void *)wb_param,
+						sizeof(struct prev_wb))) {
+			dev_err(dev, "set_wb_params: Error in copy\n");
+			return -EFAULT;
+		}
+		if (validate_wb_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+	/* Now set the values in the hw */
+	ipipe_set_wb_regs(&oper_state->wb);
+
+	return 0;
+}
+
+static int get_wb_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_wb *wb_param = (struct prev_wb *)param;
+
+	if (len != sizeof(struct prev_wb)) {
+		dev_err(dev, "get_wb_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)wb_param, (void *)&oper_state->wb,
+		sizeof(struct prev_wb))) {
+		dev_err(dev, "get_wb_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_cfa_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	if (oper_state->cfa.hpf_thr_2dir > CFA_HPF_THR_2DIR_MASK ||
+	    oper_state->cfa.hpf_slp_2dir > CFA_HPF_SLOPE_2DIR_MASK ||
+	    oper_state->cfa.hp_mix_thr_2dir > CFA_HPF_MIX_THR_2DIR_MASK ||
+	    oper_state->cfa.hp_mix_slope_2dir > CFA_HPF_MIX_SLP_2DIR_MASK ||
+	    oper_state->cfa.dir_thr_2dir > CFA_DIR_THR_2DIR_MASK ||
+	    oper_state->cfa.dir_slope_2dir > CFA_DIR_SLP_2DIR_MASK ||
+	    oper_state->cfa.nd_wt_2dir > CFA_ND_WT_2DIR_MASK ||
+	    oper_state->cfa.hue_fract_daa > CFA_DAA_HUE_FRA_MASK ||
+	    oper_state->cfa.edge_thr_daa > CFA_DAA_EDG_THR_MASK ||
+	    oper_state->cfa.thr_min_daa > CFA_DAA_THR_MIN_MASK ||
+	    oper_state->cfa.thr_slope_daa > CFA_DAA_THR_SLP_MASK ||
+	    oper_state->cfa.slope_min_daa > CFA_DAA_SLP_MIN_MASK ||
+	    oper_state->cfa.slope_slope_daa > CFA_DAA_SLP_SLP_MASK ||
+	    oper_state->cfa.lp_wt_daa > CFA_DAA_LP_WT_MASK)
+		return -EINVAL;
+	return 0;
+}
+
+static int set_cfa_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_cfa *cfa_param = (struct prev_cfa *)param;
+
+	dev_dbg(dev, "set_cfa_params\n");
+	if (!cfa_param) {
+		/* Copy defaults for wb */
+		memcpy((void *)&oper_state->cfa, (void *)&dm365_cfa_defaults,
+						sizeof(struct prev_cfa));
+	} else {
+		if (len != sizeof(struct prev_cfa)) {
+			dev_err(dev,
+			       "set_cfa_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->cfa, (void *)cfa_param,
+					sizeof(struct prev_cfa))) {
+			dev_err(dev, "set_cfa_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+		if (validate_cfa_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+	/* Now set the values in the hw */
+	ipipe_set_cfa_regs(&oper_state->cfa);
+
+	return 0;
+}
+
+static int get_cfa_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_cfa *cfa_param = (struct prev_cfa *)param;
+
+	if (len != sizeof(struct prev_cfa)) {
+		dev_err(dev, "get_cfa_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)cfa_param, (void *)&oper_state->cfa,
+		sizeof(struct prev_cfa))) {
+		dev_err(dev, "get_cfa_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_rgb2rgb_params(struct device *dev, struct ipipe_oper_state *oper_state,
+			unsigned int id)
+{
+	struct prev_rgb2rgb *rgb2rgb = &oper_state->rgb2rgb_1;
+	u32 gain_int_upper = RGB2RGB_1_GAIN_INT_MASK;
+	u32 offset_upper = RGB2RGB_1_OFST_MASK;
+
+	if (id) {
+		rgb2rgb = &oper_state->rgb2rgb_2;
+		offset_upper = RGB2RGB_2_OFST_MASK;
+		gain_int_upper = RGB2RGB_2_GAIN_INT_MASK;
+	}
+	if (rgb2rgb->coef_rr.decimal > RGB2RGB_GAIN_DECI_MASK ||
+	    rgb2rgb->coef_rr.integer > gain_int_upper)
+		return -EINVAL;
+
+	if (rgb2rgb->coef_gr.decimal > RGB2RGB_GAIN_DECI_MASK ||
+	    rgb2rgb->coef_gr.integer > gain_int_upper)
+		return -EINVAL;
+
+	if (rgb2rgb->coef_br.decimal > RGB2RGB_GAIN_DECI_MASK ||
+	    rgb2rgb->coef_br.integer > gain_int_upper)
+		return -EINVAL;
+
+	if (rgb2rgb->coef_rg.decimal > RGB2RGB_GAIN_DECI_MASK ||
+	    rgb2rgb->coef_rg.integer > gain_int_upper)
+		return -EINVAL;
+
+	if (rgb2rgb->coef_gg.decimal > RGB2RGB_GAIN_DECI_MASK ||
+	    rgb2rgb->coef_gg.integer > gain_int_upper)
+		return -EINVAL;
+
+	if (rgb2rgb->coef_bg.decimal > RGB2RGB_GAIN_DECI_MASK ||
+	    rgb2rgb->coef_bg.integer > gain_int_upper)
+		return -EINVAL;
+
+	if (rgb2rgb->coef_rb.decimal > RGB2RGB_GAIN_DECI_MASK ||
+	    rgb2rgb->coef_rb.integer > gain_int_upper)
+		return -EINVAL;
+
+	if (rgb2rgb->coef_gb.decimal > RGB2RGB_GAIN_DECI_MASK ||
+	    rgb2rgb->coef_gb.integer > gain_int_upper)
+		return -EINVAL;
+
+	if (rgb2rgb->coef_bb.decimal > RGB2RGB_GAIN_DECI_MASK ||
+	    rgb2rgb->coef_bb.integer > gain_int_upper)
+		return -EINVAL;
+
+	if (rgb2rgb->out_ofst_r > offset_upper ||
+	    rgb2rgb->out_ofst_g > offset_upper ||
+	    rgb2rgb->out_ofst_b > offset_upper)
+		return -EINVAL;
+	return 0;
+}
+
+static int
+set_rgb2rgb_params(struct device *dev, struct ipipe_oper_state *oper_state,
+		   unsigned int id, void *param, int len)
+{
+	struct prev_rgb2rgb *rgb2rgb_param = (struct prev_rgb2rgb *)param;
+	struct prev_rgb2rgb *rgb2rgb = &oper_state->rgb2rgb_1;
+
+	if (id)
+		rgb2rgb = &oper_state->rgb2rgb_2;
+	if (!rgb2rgb_param) {
+		/* Copy defaults for rgb2rgb conversion */
+		memcpy((void *)rgb2rgb, (void *)&dm365_rgb2rgb_defaults,
+					sizeof(struct prev_rgb2rgb));
+	} else {
+		if (len != sizeof(struct prev_rgb2rgb)) {
+			dev_err(dev,
+			"set_rgb2rgb_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+
+		if (!memcpy((void *)rgb2rgb, (void *)rgb2rgb_param,
+					  sizeof(struct prev_rgb2rgb))) {
+			dev_err(dev, "set_rgb2rgb_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+		if (validate_rgb2rgb_params(dev, oper_state, id) < 0)
+			return -EINVAL;
+	}
+	ipipe_set_rgb2rgb_regs(id, rgb2rgb);
+
+	return 0;
+}
+
+static int
+set_rgb2rgb_1_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return set_rgb2rgb_params(dev, oper_state, 0, param, len);
+}
+
+static int
+set_rgb2rgb_2_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return set_rgb2rgb_params(dev, oper_state, 1, param, len);
+}
+
+static int
+get_rgb2rgb_params(struct device *dev, struct ipipe_oper_state *oper_state,
+		   unsigned int id, void *param, int len)
+{
+	struct prev_rgb2rgb *rgb2rgb_param = (struct prev_rgb2rgb *)param;
+	struct prev_rgb2rgb *rgb2rgb = &oper_state->rgb2rgb_1;
+
+	if (len != sizeof(struct prev_rgb2rgb)) {
+		dev_err(dev,
+			"get_rgb2rgb_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	if (id)
+		rgb2rgb = &oper_state->rgb2rgb_2;
+	if (!memcpy((void *)rgb2rgb_param, (void *)rgb2rgb,
+		sizeof(struct prev_rgb2rgb))) {
+		dev_err(dev, "get_rgb2rgb_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+get_rgb2rgb_1_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return get_rgb2rgb_params(dev, oper_state, 0, param, len);
+}
+
+static int
+get_rgb2rgb_2_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return get_rgb2rgb_params(dev, oper_state, 1, param, len);
+}
+
+static int validate_gamma_entry(struct ipipe_gamma_entry *table, int size)
+{
+	int i;
+
+	if (!table)
+		return -EINVAL;
+
+	for (i = 0; i < size; i++) {
+		if (table[i].slope > GAMMA_MASK ||
+		    table[i].offset > GAMMA_MASK)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+validate_gamma_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	int table_size;
+	int err;
+
+	if (oper_state->gamma.bypass_r > 1 ||
+	    oper_state->gamma.bypass_b > 1 ||
+	    oper_state->gamma.bypass_g > 1)
+		return -EINVAL;
+
+	if (oper_state->gamma.tbl_sel != IPIPE_GAMMA_TBL_RAM)
+		return 0;
+
+	table_size = oper_state->gamma.tbl_size;
+	if (!oper_state->gamma.bypass_r) {
+		err = validate_gamma_entry(oper_state->gamma.table_r,
+							table_size);
+		if (err) {
+			dev_err(dev, "GAMMA R - table entry invalid\n");
+			return err;
+		}
+	}
+	if (!oper_state->gamma.bypass_b) {
+		err = validate_gamma_entry(oper_state->gamma.table_b,
+							table_size);
+		if (err) {
+			dev_err(dev, "GAMMA B - table entry invalid\n");
+			return err;
+		}
+	}
+	if (!oper_state->gamma.bypass_g) {
+		err = validate_gamma_entry(oper_state->gamma.table_g,
+							table_size);
+		if (err) {
+			dev_err(dev, "GAMMA G - table entry invalid\n");
+			return err;
+		}
+	}
+	return 0;
+}
+
+static int
+set_gamma_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_gamma *gamma_param = (struct prev_gamma *)param;
+	int table_size;
+
+	if (!gamma_param) {
+		/* Copy defaults for gamma */
+		oper_state->gamma.bypass_r = dm365_gamma_defaults.bypass_r;
+		oper_state->gamma.bypass_g = dm365_gamma_defaults.bypass_g;
+		oper_state->gamma.bypass_b = dm365_gamma_defaults.bypass_b;
+		oper_state->gamma.tbl_sel = dm365_gamma_defaults.tbl_sel;
+		oper_state->gamma.tbl_size = dm365_gamma_defaults.tbl_size;
+		/* By default, we bypass the gamma correction.
+		 * So no values by default for tables
+		 */
+		goto success;
+	}
+	if (len != sizeof(struct prev_gamma)) {
+		dev_err(dev,
+			"set_gamma_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+
+	oper_state->gamma.bypass_r = gamma_param->bypass_r;
+	oper_state->gamma.bypass_b = gamma_param->bypass_b;
+	oper_state->gamma.bypass_g = gamma_param->bypass_g;
+	oper_state->gamma.tbl_sel = gamma_param->tbl_sel;
+	oper_state->gamma.tbl_size = gamma_param->tbl_size;
+
+	if (validate_gamma_params(dev, oper_state) < 0)
+		return -EINVAL;
+
+	if (gamma_param->tbl_sel != IPIPE_GAMMA_TBL_RAM)
+		goto success;
+
+	table_size = oper_state->gamma.tbl_size;
+
+	if (!gamma_param->bypass_r) {
+		if (!memcpy((void *)&oper_state->gamma.table_r,
+				    (void *)&gamma_param->table_r, (table_size *
+				    sizeof(struct ipipe_gamma_entry)))) {
+			dev_err(dev,
+			"set_gamma_params: Error in copying bypass_r table\n");
+			return -EFAULT;
+		}
+	}
+
+	if (!gamma_param->bypass_b) {
+		if (!memcpy((void *)&oper_state->gamma.table_b,
+				    (void *)&gamma_param->table_b, (table_size *
+				    sizeof(struct ipipe_gamma_entry)))) {
+			dev_err(dev,
+			"set_gamma_params: Error in copying bypass_b table\n");
+			return -EFAULT;
+		}
+	}
+
+	if (!gamma_param->bypass_g) {
+		if (!memcpy((void *)&oper_state->gamma.table_g,
+				    (void *)&gamma_param->table_g, (table_size *
+				    sizeof(struct ipipe_gamma_entry)))) {
+			dev_err(dev,
+			"set_gamma_params: Error in copying bypass_g table\n");
+			return -EFAULT;
+		}
+	}
+
+success:
+	ipipe_set_gamma_regs(&oper_state->gamma);
+
+	return 0;
+}
+
+static int
+get_gamma_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_gamma *gamma_param = (struct prev_gamma *)param;
+	int table_size;
+
+	if (len != sizeof(struct prev_gamma)) {
+		dev_err(dev,
+			"get_gamma_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	gamma_param->bypass_r = oper_state->gamma.bypass_r;
+	gamma_param->bypass_g = oper_state->gamma.bypass_g;
+	gamma_param->bypass_b = oper_state->gamma.bypass_b;
+	gamma_param->tbl_sel = oper_state->gamma.tbl_sel;
+	gamma_param->tbl_size = oper_state->gamma.tbl_size;
+
+	if (oper_state->gamma.tbl_sel != IPIPE_GAMMA_TBL_RAM)
+		return 0;
+
+	table_size = oper_state->gamma.tbl_size;
+	if (!oper_state->gamma.bypass_r && !gamma_param->table_r) {
+		dev_err(dev,
+			"get_gamma_params: table ptr empty for R\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)gamma_param->table_r,
+		(void *)oper_state->gamma.table_r, (table_size *
+				sizeof(struct ipipe_gamma_entry)))) {
+		dev_err(dev, "get_gamma_params: R-Table Error in copy\n");
+		return -EFAULT;
+	}
+
+	if (!oper_state->gamma.bypass_g && !gamma_param->table_g) {
+		dev_err(dev, "get_gamma_params: table ptr empty for G\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)gamma_param->table_g,
+		(void *)oper_state->gamma.table_g, (table_size *
+		sizeof(struct ipipe_gamma_entry)))) {
+		dev_err(dev, "get_gamma_params: G-Table copy error\n");
+		return -EFAULT;
+	}
+
+	if (!oper_state->gamma.bypass_b && !gamma_param->table_b) {
+		dev_err(dev, "get_gamma_params: table ptr empty for B\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)gamma_param->table_b,
+		(void *)oper_state->gamma.table_b, (table_size *
+				sizeof(struct ipipe_gamma_entry)))) {
+		dev_err(dev, "set_gamma_params: B-Table Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_3d_lut_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	int i;
+
+	if (!oper_state->lut_3d.en)
+		return 0;
+
+	for (i = 0; i < MAX_SIZE_3D_LUT; i++) {
+		if (oper_state->lut_3d.table[i].r > D3_LUT_ENTRY_MASK ||
+		    oper_state->lut_3d.table[i].g > D3_LUT_ENTRY_MASK ||
+		    oper_state->lut_3d.table[i].b > D3_LUT_ENTRY_MASK)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int get_3d_lut_params(struct device *dev, void *ipipe,
+						void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_3d_lut *lut_param = (struct prev_3d_lut *)param;
+
+	if (len != sizeof(struct prev_3d_lut)) {
+		dev_err(dev,
+			"get_3d_lut_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+
+	lut_param->en = oper_state->lut_3d.en;
+	if (!lut_param->table) {
+		dev_err(dev, "get_3d_lut_params: Invalid table ptr\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)lut_param->table, (void *)oper_state->lut_3d.table,
+		(MAX_SIZE_3D_LUT * sizeof(struct ipipe_3d_lut_entry)))) {
+		dev_err(dev, "get_3d_lut_params:Table Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+set_3d_lut_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_3d_lut *lut_param = (struct prev_3d_lut *)param;
+
+	if (!lut_param) {
+		/* Copy defaults for gamma */
+		oper_state->lut_3d.en = dm365_3d_lut_defaults.en;
+		/* By default, 3D lut is disabled
+		 */
+	} else {
+		if (len != sizeof(struct prev_3d_lut)) {
+			dev_err(dev,
+			"set_3d_lut_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->lut_3d, (void *)lut_param,
+				   sizeof(struct prev_3d_lut))) {
+			dev_err(dev, "set_3d_lut_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+		if (validate_3d_lut_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+
+	ipipe_set_3d_lut_regs(&oper_state->lut_3d);
+
+	return 0;
+}
+
+static int
+validate_rgb2yuv_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	if (oper_state->rgb2yuv.coef_ry.decimal > RGB2YCBCR_COEF_DECI_MASK ||
+	    oper_state->rgb2yuv.coef_ry.integer > RGB2YCBCR_COEF_INT_MASK)
+		return -EINVAL;
+
+	if (oper_state->rgb2yuv.coef_gy.decimal > RGB2YCBCR_COEF_DECI_MASK ||
+	    oper_state->rgb2yuv.coef_gy.integer > RGB2YCBCR_COEF_INT_MASK)
+		return -EINVAL;
+
+	if (oper_state->rgb2yuv.coef_by.decimal > RGB2YCBCR_COEF_DECI_MASK ||
+	    oper_state->rgb2yuv.coef_by.integer > RGB2YCBCR_COEF_INT_MASK)
+		return -EINVAL;
+
+	if (oper_state->rgb2yuv.coef_rcb.decimal > RGB2YCBCR_COEF_DECI_MASK ||
+	    oper_state->rgb2yuv.coef_rcb.integer > RGB2YCBCR_COEF_INT_MASK)
+		return -EINVAL;
+
+	if (oper_state->rgb2yuv.coef_gcb.decimal > RGB2YCBCR_COEF_DECI_MASK ||
+	    oper_state->rgb2yuv.coef_gcb.integer > RGB2YCBCR_COEF_INT_MASK)
+		return -EINVAL;
+
+	if (oper_state->rgb2yuv.coef_bcb.decimal > RGB2YCBCR_COEF_DECI_MASK ||
+	    oper_state->rgb2yuv.coef_bcb.integer > RGB2YCBCR_COEF_INT_MASK)
+		return -EINVAL;
+
+	if (oper_state->rgb2yuv.coef_rcr.decimal > RGB2YCBCR_COEF_DECI_MASK ||
+	    oper_state->rgb2yuv.coef_rcr.integer > RGB2YCBCR_COEF_INT_MASK)
+		return -EINVAL;
+
+	if (oper_state->rgb2yuv.coef_gcr.decimal > RGB2YCBCR_COEF_DECI_MASK ||
+	    oper_state->rgb2yuv.coef_gcr.integer > RGB2YCBCR_COEF_INT_MASK)
+		return -EINVAL;
+
+	if (oper_state->rgb2yuv.coef_bcr.decimal > RGB2YCBCR_COEF_DECI_MASK ||
+	    oper_state->rgb2yuv.coef_bcr.integer > RGB2YCBCR_COEF_INT_MASK)
+		return -EINVAL;
+
+	if (oper_state->rgb2yuv.out_ofst_y > RGB2YCBCR_OFST_MASK ||
+	    oper_state->rgb2yuv.out_ofst_cb > RGB2YCBCR_OFST_MASK ||
+	    oper_state->rgb2yuv.out_ofst_cr > RGB2YCBCR_OFST_MASK)
+		return -EINVAL;
+	return 0;
+}
+
+static int
+set_rgb2yuv_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_rgb2yuv *rgb2yuv_param = (struct prev_rgb2yuv *)param;
+
+	if (!rgb2yuv_param) {
+		/* Copy defaults for rgb2yuv conversion  */
+		memcpy((void *)&oper_state->rgb2yuv,
+		       (void *)&dm365_rgb2yuv_defaults,
+		       sizeof(struct prev_rgb2yuv));
+	} else {
+		if (len != sizeof(struct prev_rgb2yuv)) {
+			dev_err(dev,
+			"set_rgb2yuv_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->rgb2yuv,
+			(void *)rgb2yuv_param, sizeof(struct prev_rgb2yuv))) {
+			dev_err(dev, "set_rgb2yuv_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+		if (validate_rgb2yuv_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+
+	ipipe_set_rgb2ycbcr_regs(&oper_state->rgb2yuv);
+
+	return 0;
+}
+
+static int
+get_rgb2yuv_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_rgb2yuv *rgb2yuv_param = (struct prev_rgb2yuv *)param;
+
+	if (len != sizeof(struct prev_rgb2yuv)) {
+		dev_err(dev,
+			"get_rgb2yuv_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)rgb2yuv_param, (void *)&oper_state->rgb2yuv,
+		sizeof(struct prev_rgb2yuv))) {
+		dev_err(dev, "get_rgb2yuv_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_gbce_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	u32 max = GBCE_Y_VAL_MASK;
+	int i;
+
+	if (!oper_state->gbce.en)
+		return 0;
+
+	if (oper_state->gbce.type == IPIPE_GBCE_GAIN_TBL)
+		max = GBCE_GAIN_VAL_MASK;
+	for (i = 0; i < MAX_SIZE_GBCE_LUT; i++)
+		if (oper_state->gbce.table[i] > max)
+			return -EINVAL;
+	return 0;
+}
+
+static int
+set_gbce_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_gbce *gbce_param = (struct prev_gbce *)param;
+
+	if (!gbce_param) {
+		/* Copy defaults for gamma */
+		oper_state->gbce.en = dm365_gbce_defaults.en;
+		/* By default, GBCE is disabled
+		 */
+	} else {
+		if (len != sizeof(struct prev_gbce)) {
+			dev_err(dev,
+			"set_gbce_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->gbce, (void *)gbce_param,
+				   sizeof(struct prev_gbce))) {
+			dev_err(dev, "set_gbce_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+		if (validate_gbce_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+
+	ipipe_set_gbce_regs(&oper_state->gbce);
+
+	return 0;
+}
+
+static int
+get_gbce_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_gbce *gbce_param = (struct prev_gbce *)param;
+
+	if (len != sizeof(struct prev_gbce)) {
+		dev_err(dev,
+			"get_gbce_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+
+	gbce_param->en = oper_state->gbce.en;
+	gbce_param->type = oper_state->gbce.type;
+	if (!gbce_param->table) {
+		dev_err(dev, "get_gbce_params: Invalid table ptr\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)gbce_param->table, (void *)oper_state->gbce.table,
+		(MAX_SIZE_GBCE_LUT * sizeof(unsigned short)))) {
+		dev_err(dev, "get_gbce_params:Table Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_yuv422_conv_params(struct device *dev,
+			    struct ipipe_oper_state *oper_state)
+{
+	if (oper_state->yuv422_conv.en_chrom_lpf > 1)
+		return -EINVAL;
+	return 0;
+}
+
+static int
+set_yuv422_conv_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_yuv422_conv *yuv422_conv_param =
+					(struct prev_yuv422_conv *)param;
+
+	if (!yuv422_conv_param) {
+		/* Copy defaults for yuv 422 conversion */
+		memcpy((void *)&oper_state->yuv422_conv,
+		       (void *)&dm365_yuv422_conv_defaults,
+		       sizeof(struct prev_yuv422_conv));
+	} else {
+		if (len != sizeof(struct prev_yuv422_conv)) {
+			dev_err(dev,
+			"set_yuv422_conv_params: struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->yuv422_conv,
+		  (void *)yuv422_conv_param, sizeof(struct prev_yuv422_conv))) {
+			dev_err(dev, "set_yuv422_conv_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+		if (validate_yuv422_conv_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+
+	ipipe_set_yuv422_conv_regs(&oper_state->yuv422_conv);
+
+	return 0;
+}
+
+static int
+get_yuv422_conv_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_yuv422_conv *yuv422_conv_param =
+				(struct prev_yuv422_conv *)param;
+
+	if (len != sizeof(struct prev_yuv422_conv)) {
+		dev_err(dev,
+		     "get_yuv422_conv_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)yuv422_conv_param, (void *)&oper_state->yuv422_conv,
+				sizeof(struct prev_yuv422_conv))) {
+		dev_err(dev, "get_yuv422_conv_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_yee_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	int i;
+
+	if (oper_state->yee.en > 1 ||
+	    oper_state->yee.en_halo_red > 1 ||
+	    oper_state->yee.hpf_shft > YEE_HPF_SHIFT_MASK)
+		return -EINVAL;
+
+	if (oper_state->yee.hpf_coef_00 > YEE_COEF_MASK ||
+	    oper_state->yee.hpf_coef_01 > YEE_COEF_MASK ||
+	    oper_state->yee.hpf_coef_02 > YEE_COEF_MASK ||
+	    oper_state->yee.hpf_coef_10 > YEE_COEF_MASK ||
+	    oper_state->yee.hpf_coef_11 > YEE_COEF_MASK ||
+	    oper_state->yee.hpf_coef_12 > YEE_COEF_MASK ||
+	    oper_state->yee.hpf_coef_20 > YEE_COEF_MASK ||
+	    oper_state->yee.hpf_coef_21 > YEE_COEF_MASK ||
+	    oper_state->yee.hpf_coef_22 > YEE_COEF_MASK)
+		return -EINVAL;
+
+	if (oper_state->yee.yee_thr > YEE_THR_MASK ||
+	    oper_state->yee.es_gain > YEE_ES_GAIN_MASK ||
+	    oper_state->yee.es_thr1 > YEE_ES_THR1_MASK ||
+	    oper_state->yee.es_thr2 > YEE_THR_MASK ||
+	    oper_state->yee.es_gain_grad > YEE_THR_MASK ||
+	    oper_state->yee.es_ofst_grad > YEE_THR_MASK)
+		return -EINVAL;
+
+	for (i = 0; i < MAX_SIZE_YEE_LUT ; i++)
+		if (oper_state->yee.table[i] > YEE_ENTRY_MASK)
+			return -EINVAL;
+	return 0;
+}
+
+static int
+set_yee_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_yee *yee_param = (struct prev_yee *)param;
+
+	if (!yee_param) {
+		/* Copy defaults for ns */
+		memcpy((void *)&oper_state->yee, (void *)&dm365_yee_defaults,
+		       sizeof(struct prev_yee));
+	} else {
+		if (len != sizeof(struct prev_yee)) {
+			dev_err(dev,
+			     "set_yee_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->yee, (void *)yee_param,
+				   sizeof(struct prev_yee))) {
+			dev_err(dev, "set_yee_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+
+		if (validate_yee_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+
+	ipipe_set_ee_regs(&oper_state->yee);
+
+	return 0;
+}
+
+static int
+get_yee_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_yee *yee_param = (struct prev_yee *)param;
+
+	if (len != sizeof(struct prev_yee)) {
+		dev_err(dev, "get_yee_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	yee_param->en = oper_state->yee.en;
+	yee_param->en_halo_red = oper_state->yee.en_halo_red;
+	yee_param->merge_meth = oper_state->yee.merge_meth;
+	yee_param->hpf_shft = oper_state->yee.hpf_shft;
+	yee_param->hpf_coef_00 = oper_state->yee.hpf_coef_00;
+	yee_param->hpf_coef_01 = oper_state->yee.hpf_coef_01;
+	yee_param->hpf_coef_02 = oper_state->yee.hpf_coef_02;
+	yee_param->hpf_coef_10 = oper_state->yee.hpf_coef_10;
+	yee_param->hpf_coef_11 = oper_state->yee.hpf_coef_11;
+	yee_param->hpf_coef_12 = oper_state->yee.hpf_coef_12;
+	yee_param->hpf_coef_20 = oper_state->yee.hpf_coef_20;
+	yee_param->hpf_coef_21 = oper_state->yee.hpf_coef_21;
+	yee_param->hpf_coef_22 = oper_state->yee.hpf_coef_22;
+	yee_param->yee_thr = oper_state->yee.yee_thr;
+	yee_param->es_gain = oper_state->yee.es_gain;
+	yee_param->es_thr1 = oper_state->yee.es_thr1;
+	yee_param->es_thr2 = oper_state->yee.es_thr2;
+	yee_param->es_gain_grad = oper_state->yee.es_gain_grad;
+	yee_param->es_ofst_grad = oper_state->yee.es_ofst_grad;
+	if (!memcpy((void *)yee_param->table, (void *)oper_state->yee.table,
+		(MAX_SIZE_YEE_LUT * sizeof(short)))) {
+		dev_err(dev, "get_yee_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_car_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	if (oper_state->car.en > 1 ||
+	    oper_state->car.hpf_shft > CAR_HPF_SHIFT_MASK ||
+	    oper_state->car.gain1.shft > CAR_GAIN1_SHFT_MASK ||
+	    oper_state->car.gain1.gain_min > CAR_GAIN_MIN_MASK ||
+	    oper_state->car.gain2.shft > CAR_GAIN2_SHFT_MASK ||
+	    oper_state->car.gain2.gain_min > CAR_GAIN_MIN_MASK)
+		return -EINVAL;
+	return 0;
+}
+
+static int
+set_car_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_car *car_param = (struct prev_car *)param;
+
+	if (!car_param) {
+		/* Copy defaults for ns */
+		memcpy((void *)&oper_state->car, (void *)&dm365_car_defaults,
+				sizeof(struct prev_car));
+	} else {
+		if (len != sizeof(struct prev_car)) {
+			dev_err(dev,
+			    "set_car_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->car, (void *)car_param,
+					sizeof(struct prev_car))) {
+			dev_err(dev, "set_car_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+		if (validate_car_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+
+	ipipe_set_car_regs(&oper_state->car);
+
+	return 0;
+}
+
+static int
+get_car_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_car *car_param = (struct prev_car *)param;
+
+	if (len != sizeof(struct prev_car)) {
+		dev_err(dev, "get_car_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)car_param, (void *)&oper_state->car,
+		sizeof(struct prev_car))) {
+		dev_err(dev, "get_car_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+validate_cgs_params(struct device *dev, struct ipipe_oper_state *oper_state)
+{
+	if (oper_state->cgs.en > 1 ||
+			oper_state->cgs.h_shft > CAR_SHIFT_MASK)
+		return -EINVAL;
+	return 0;
+}
+
+static int
+set_cgs_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_cgs *cgs_param = (struct prev_cgs *)param;
+
+	if (!cgs_param) {
+		/* Copy defaults for ns */
+		memcpy((void *)&oper_state->cgs, (void *)&dm365_cgs_defaults,
+				sizeof(struct prev_cgs));
+	} else {
+		if (len != sizeof(struct prev_cgs)) {
+			dev_err(dev,
+			    "set_cgs_params: param struct length mismatch\n");
+			return -EINVAL;
+		}
+		if (!memcpy((void *)&oper_state->cgs, (void *)cgs_param,
+					sizeof(struct prev_cgs))) {
+			dev_err(dev, "set_cgs_params: Error in memcpy\n");
+			return -EFAULT;
+		}
+		if (validate_cgs_params(dev, oper_state) < 0)
+			return -EINVAL;
+	}
+
+	ipipe_set_cgs_regs(&oper_state->cgs);
+
+	return 0;
+}
+
+static int
+get_cgs_params(struct device *dev, void *ipipe, void *param, int len)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct prev_cgs *cgs_param = (struct prev_cgs *)param;
+
+	if (len != sizeof(struct prev_cgs)) {
+		dev_err(dev,
+			"get_cgs_params: param struct length mismatch\n");
+		return -EINVAL;
+	}
+	if (!memcpy((void *)cgs_param, (void *)&oper_state->cgs,
+		sizeof(struct prev_cgs))) {
+		dev_err(dev, "get_cgs_params: Error in copy\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static struct prev_module_if prev_modules[PREV_MAX_MODULES] = {
+	/* PREV_IPIPEIF */ {
+		offsetof(struct vpfe_prev_params, ipipeif_config),
+		FIELD_SIZEOF(struct vpfe_prev_params, ipipeif_config),
+		offsetof(struct vpfe_prev_config, ipipeif_config),
+		NULL,
+		NULL,
+	}, /* PREV_LUTDPC */ {
+		offsetof(struct vpfe_prev_params, lutdpc),
+		FIELD_SIZEOF(struct vpfe_prev_params, lutdpc),
+		offsetof(struct vpfe_prev_config, lutdpc),
+		set_lutdpc_params,
+		get_lutdpc_params,
+	}, /* PREV_OTFDPC */ {
+		offsetof(struct vpfe_prev_params, otfdpc),
+		FIELD_SIZEOF(struct vpfe_prev_params, otfdpc),
+		offsetof(struct vpfe_prev_config, otfdpc),
+		set_otfdpc_params,
+		get_otfdpc_params,
+	}, /* PREV_NF1 */ {
+		offsetof(struct vpfe_prev_params, nf1),
+		FIELD_SIZEOF(struct vpfe_prev_params, nf1),
+		offsetof(struct vpfe_prev_config, nf1),
+		set_nf1_params,
+		get_nf1_params,
+	}, /* PREV_NF2 */ {
+		offsetof(struct vpfe_prev_params, nf2),
+		FIELD_SIZEOF(struct vpfe_prev_params, nf2),
+		offsetof(struct vpfe_prev_config, nf2),
+		set_nf2_params,
+		get_nf2_params,
+	}, /* PREV_WB */ {
+		offsetof(struct vpfe_prev_params, wbal),
+		FIELD_SIZEOF(struct vpfe_prev_params, wbal),
+		offsetof(struct vpfe_prev_config, wbal),
+		set_wb_params,
+		get_wb_params,
+	}, /* PREV_RGB2RGB_1 */ {
+		offsetof(struct vpfe_prev_params, rgb2rgb1),
+		FIELD_SIZEOF(struct vpfe_prev_params, rgb2rgb1),
+		offsetof(struct vpfe_prev_config, rgb2rgb1),
+		set_rgb2rgb_1_params,
+		get_rgb2rgb_1_params,
+	}, /*PREV_RGB2RGB_2 */ {
+		offsetof(struct vpfe_prev_params, rgb2rgb2),
+		FIELD_SIZEOF(struct vpfe_prev_params, rgb2rgb2),
+		offsetof(struct vpfe_prev_config, rgb2rgb2),
+		set_rgb2rgb_2_params,
+		get_rgb2rgb_2_params,
+	}, /* PREV_GAMMA */ {
+		offsetof(struct vpfe_prev_params, gamma),
+		FIELD_SIZEOF(struct vpfe_prev_params, gamma),
+		offsetof(struct vpfe_prev_config, gamma),
+		set_gamma_params,
+		get_gamma_params,
+	}, /* PREV_3D_LUT */ {
+		offsetof(struct vpfe_prev_params, lut),
+		FIELD_SIZEOF(struct vpfe_prev_params, lut),
+		offsetof(struct vpfe_prev_config, lut),
+		set_3d_lut_params,
+		get_3d_lut_params,
+	}, /* PREV_RGB2YUV */ {
+		offsetof(struct vpfe_prev_params, rgb2yuv),
+		FIELD_SIZEOF(struct vpfe_prev_params, rgb2yuv),
+		offsetof(struct vpfe_prev_config, rgb2yuv),
+		set_rgb2yuv_params,
+		get_rgb2yuv_params,
+	}, /* PREV_YUV422_CONV */ {
+		offsetof(struct vpfe_prev_params, yuv422_conv),
+		FIELD_SIZEOF(struct vpfe_prev_params, yuv422_conv),
+		offsetof(struct vpfe_prev_config, yuv422_conv),
+		set_yuv422_conv_params,
+		get_yuv422_conv_params,
+	}, /* PREV_YEE */ {
+		offsetof(struct vpfe_prev_params, yee),
+		FIELD_SIZEOF(struct vpfe_prev_params, yee),
+		offsetof(struct vpfe_prev_config, yee),
+		set_yee_params,
+		get_yee_params,
+	}, /* PREV_GIC */ {
+		offsetof(struct vpfe_prev_params, gic),
+		FIELD_SIZEOF(struct vpfe_prev_params, gic),
+		offsetof(struct vpfe_prev_config, gic),
+		set_gic_params,
+		get_gic_params,
+	}, /* PREV_CFA */ {
+		offsetof(struct vpfe_prev_params, cfa),
+		FIELD_SIZEOF(struct vpfe_prev_params, cfa),
+		offsetof(struct vpfe_prev_config, cfa),
+		set_cfa_params,
+		get_cfa_params,
+	}, /* PREV_CAR */ {
+		offsetof(struct vpfe_prev_params, car),
+		FIELD_SIZEOF(struct vpfe_prev_params, car),
+		offsetof(struct vpfe_prev_config, car),
+		set_car_params,
+		get_car_params,
+	}, /* PREV_CGS */ {
+		offsetof(struct vpfe_prev_params, cgs),
+		FIELD_SIZEOF(struct vpfe_prev_params, cgs),
+		offsetof(struct vpfe_prev_config, cgs),
+		set_cgs_params,
+		get_cgs_params,
+	}, /* PREV_GBCE */ {
+		offsetof(struct vpfe_prev_params, gbce),
+		FIELD_SIZEOF(struct vpfe_prev_params, gbce),
+		offsetof(struct vpfe_prev_config, gbce),
+		set_gbce_params,
+		get_gbce_params,
+	},
+};
+
+static int
+ipipe_set_preview_module_params(struct device *dev, void *ipipe,
+				struct vpfe_prev_config *cfg)
+{
+	unsigned int i;
+	int rval = 0;
+
+	for (i = 1; i < ARRAY_SIZE(prev_modules); i++) {
+		unsigned int bit = 1 << i;
+		if (cfg->flag & bit) {
+			const struct prev_module_if *module_if =
+						&prev_modules[i];
+			struct vpfe_prev_params *params;
+			void __user *from = *(void * __user *)
+				((void *)cfg + module_if->config_offset);
+			size_t size;
+			void *to;
+
+			params =
+			   kmalloc(sizeof(struct vpfe_prev_params), GFP_KERNEL);
+			to = (void *)params + module_if->param_offset;
+			size = module_if->param_size;
+
+			if (to && from && size) {
+				if (copy_from_user(to, from, size)) {
+					rval = -EFAULT;
+					break;
+				}
+				rval = module_if->set(dev, ipipe, to, size);
+				if (rval)
+					goto error;
+			} else if (to && !from && size) {
+				rval = module_if->set(dev, ipipe, NULL, size);
+				if (rval)
+					goto error;
+			}
+			kfree(params);
+		}
+	}
+error:
+	return rval;
+}
+
+static int
+ipipe_get_preview_module_params(struct device *dev, void *ipipe,
+				struct vpfe_prev_config *cfg)
+{
+	unsigned int i;
+	int rval = 0;
+
+	for (i = 1; i < ARRAY_SIZE(prev_modules); i++) {
+		unsigned int bit = 1 << i;
+		if (cfg->flag & bit) {
+			const struct prev_module_if *module_if =
+						&prev_modules[i];
+			struct vpfe_prev_params *params;
+			void __user *to = *(void * __user *)
+				((void *)cfg + module_if->config_offset);
+			size_t size;
+			void *from;
+
+			params =  kmalloc(sizeof(struct vpfe_prev_params),
+						GFP_KERNEL);
+			from = (void *)params + module_if->param_offset;
+			size = module_if->param_size;
+
+			if (to && from && size) {
+				rval = module_if->get(dev, ipipe, from, size);
+				if (rval)
+					goto error;
+				if (copy_to_user(to, from, size)) {
+					rval = -EFAULT;
+					break;
+				}
+			}
+			kfree(params);
+		}
+	}
+error:
+	return rval;
+}
+
+static int preview_s_ctrl(void *ipipe, u32 ctrl_id, s32 val)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	switch (ctrl_id) {
+	case V4L2_CID_BRIGHTNESS:
+		oper_state->lum_adj.brightness = val;
+		ipipe_set_lum_adj_regs(&oper_state->lum_adj);
+		break;
+	case V4L2_CID_CONTRAST:
+		oper_state->lum_adj.contrast = val;
+		ipipe_set_lum_adj_regs(&oper_state->lum_adj);
+		break;
+	case V4L2_CID_DPCM_PREDICTOR:
+		dpcm_predictor = val;
+		break;
+	case V4L2_CID_GAIN:
+		ipipeif_gain = val;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct prev_module_if *prev_enum_preview_cap(struct device *dev,
+						    unsigned int index)
+{
+	dev_dbg(dev, "prev_enum_preview_cap: index = %d\n", index);
+
+	if (index < 0 || index >= PREV_MAX_MODULES)
+		return NULL;
+
+	return &prev_modules[index];
+}
+
+static int ipipe_set_oper_mode(void *ipipe, unsigned int mode)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	if (oper_state->oper_mode != IMP_MODE_NOT_CONFIGURED) {
+		pr_err("IPIPE is already active!\n");
+		return -EINVAL;
+	}
+	oper_state->oper_mode = mode;
+
+	return 0;
+}
+
+static void ipipe_reset_oper_mode(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	oper_state->oper_mode = IMP_MODE_NOT_CONFIGURED;
+	oper_state->prev_config_state = STATE_NOT_CONFIGURED;
+	oper_state->rsz_config_state = STATE_NOT_CONFIGURED;
+	oper_state->rsz_chained = 0;
+	oper_state->rsz_output_enabled[RSZ_A] = DISABLE;
+	oper_state->rsz_output_enabled[RSZ_B] = DISABLE;
+}
+
+static unsigned int prev_get_oper_mode(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return oper_state->oper_mode;
+}
+
+static unsigned int ipipe_get_oper_state(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return oper_state->state;
+}
+
+static void ipipe_set_oper_state(void *ipipe, unsigned int state)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	mutex_lock(&oper_state->lock);
+	oper_state->state = state;
+	mutex_unlock(&oper_state->lock);
+}
+
+static unsigned int ipipe_get_prev_config_state(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return oper_state->prev_config_state;
+}
+
+static unsigned int ipipe_get_rsz_config_state(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	return oper_state->rsz_config_state;
+}
+
+/* function: calculate_normal_f_div_param
+ * Algorithm to calculate the frame division parameters for resizer.
+ * in normal mode. Please refer the application note in DM360 functional
+ * spec for details of the algorithm
+ */
+static int
+calculate_normal_f_div_param(struct device *dev,
+			     int input_width,
+			     int output_width,
+			     struct ipipe_rsz_rescale_param *param)
+{
+	/* rsz = R, input_width = H, output width = h in the equation */
+	unsigned int val1;
+	unsigned int rsz;
+	unsigned int val;
+	unsigned int h1;
+	unsigned int h2;
+	unsigned int o;
+
+	if (output_width > input_width) {
+		dev_err(dev, "frame div mode is used for scale down only\n");
+		return -EINVAL;
+	}
+
+	rsz = (input_width << 8) / output_width;
+	val = rsz << 1;
+	val = ((input_width << 8) / val) + 1;
+	o = 14;
+	if (!(val % 2)) {
+		h1 = val;
+	} else {
+		val = (input_width << 7);
+		val -= rsz >> 1;
+		val /= rsz << 1;
+		val <<= 1;
+		val += 2;
+		o += ((CEIL(rsz, 1024)) << 1);
+		h1 = val;
+	}
+	h2 = output_width - h1;
+	/* phi */
+	val = (h1 * rsz) - (((input_width >> 1) - o) << 8);
+	/* skip */
+	val1 = ((val - 1024) >> 9) << 1;
+	param->f_div.num_passes = IPIPE_MAX_PASSES;
+	param->f_div.pass[0].o_hsz = h1 - 1;
+	param->f_div.pass[0].i_hps = 0;
+	param->f_div.pass[0].h_phs = 0;
+	param->f_div.pass[0].src_hps = 0;
+	param->f_div.pass[0].src_hsz = (input_width >> 2) + o;
+	param->f_div.pass[1].o_hsz = h2 - 1;
+	param->f_div.pass[1].i_hps = val1;
+	param->f_div.pass[1].h_phs = (val - (val1 << 8));
+	param->f_div.pass[1].src_hps = (input_width >> 2) - o;
+	param->f_div.pass[1].src_hsz = (input_width >> 2) + o;
+
+	return 0;
+}
+
+/* function: calculate_down_scale_f_div_param
+ * Algorithm to calculate the frame division parameters for resizer in
+ * downscale mode. Please refer the application note in DM360 functional
+ * spec for details of the algorithm
+ */
+static int
+calculate_down_scale_f_div_param(struct device *dev,
+				 int input_width, int output_width,
+				 struct ipipe_rsz_rescale_param *param)
+{
+	/* rsz = R, input_width = H, output width = h in the equation */
+	unsigned int two_power;
+	unsigned int upper_h1;
+	unsigned int upper_h2;
+	unsigned int val1;
+	unsigned int val;
+	unsigned int rsz;
+	unsigned int h1;
+	unsigned int h2;
+	unsigned int o;
+	unsigned int n;
+
+	upper_h1 = input_width >> 1;
+	n = param->h_dscale_ave_sz;
+	/* 2 ^ (scale+1) */
+	two_power = 1 << (n + 1);
+	upper_h1 = (upper_h1 >> (n + 1)) << (n + 1);
+	upper_h2 = input_width - upper_h1;
+	if (upper_h2 % two_power) {
+		dev_err(dev, "frame halves to be a multiple of 2 power n+1\n");
+		return -EINVAL;
+	}
+	two_power = 1 << n;
+	rsz = (input_width << 8) / output_width;
+	val = rsz * two_power;
+	val = ((upper_h1 << 8) / val) + 1;
+	if (!(val % 2))
+		h1 = val;
+	else {
+		val = upper_h1 << 8;
+		val >>= n + 1;
+		val -= rsz >> 1;
+		val /= rsz << 1;
+		val <<= 1;
+		val += 2;
+		h1 = val;
+	}
+	o = 10 + (two_power << 2);
+	if (((input_width << 7) / rsz) % 2)
+		o += (((CEIL(rsz, 1024)) << 1) << n);
+	h2 = output_width - h1;
+	/* phi */
+	val = (h1 * rsz) - (((upper_h1 - (o - 10)) / two_power) << 8);
+	/* skip */
+	val1 = ((val - 1024) >> 9) << 1;
+	param->f_div.num_passes = IPIPE_MAX_PASSES;
+	param->f_div.pass[0].o_hsz = h1 - 1;
+	param->f_div.pass[0].i_hps = 0;
+	param->f_div.pass[0].h_phs = 0;
+	param->f_div.pass[0].src_hps = 0;
+	param->f_div.pass[0].src_hsz = upper_h1 + o;
+	param->f_div.pass[1].o_hsz = h2 - 1;
+	param->f_div.pass[1].i_hps = 10 + (val1 * two_power);
+	param->f_div.pass[1].h_phs = (val - (val1 << 8));
+	param->f_div.pass[1].src_hps = upper_h1 - o;
+	param->f_div.pass[1].src_hsz = upper_h2 + o;
+
+	return 0;
+}
+
+/* update the parameter in param for a given input and output width */
+static int
+update_preview_f_div_params(struct device *dev,
+			    int input_width, int output_width,
+			    struct ipipe_rsz_rescale_param *param)
+{
+	unsigned int val;
+
+	val = input_width >> 1;
+	if (val < 8) {
+		dev_err(dev, "input width must me atleast 16 pixels\n");
+		return -EINVAL;
+	}
+	param->f_div.en = 1;
+	param->f_div.num_passes = IPIPE_MAX_PASSES;
+	param->f_div.pass[0].o_hsz = val;
+	param->f_div.pass[0].i_hps = 0;
+	param->f_div.pass[0].h_phs = 0;
+	param->f_div.pass[0].src_hps = 0;
+	param->f_div.pass[0].src_hsz = val + 10;
+	param->f_div.pass[1].o_hsz = val;
+	param->f_div.pass[1].i_hps = 0;
+	param->f_div.pass[1].h_phs = 0;
+	param->f_div.pass[1].src_hps = val - 8;
+	param->f_div.pass[1].src_hsz = val + 10;
+
+	return 0;
+}
+
+/* Use shared to allocate exclusive blocks as required
+ * by resize applications in single shot mode
+ */
+static void *ipipe_alloc_config_block(struct device *dev, void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	/* return common data block */
+	mutex_lock(&oper_state->lock);
+	if (oper_state->resource_in_use) {
+		dev_err(dev, "resource in use\n");
+		mutex_unlock(&oper_state->lock);
+		return NULL;
+	}
+	mutex_unlock(&oper_state->lock);
+
+	return oper_state->shared_config_param;
+}
+
+/* Used to free only non-shared config block allocated through
+ * imp_alloc_config_block
+ */
+static void
+ipipe_dealloc_config_block(struct device *dev, void *ipipe,
+			   void *config_block)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	if (!config_block)
+		return;
+
+	if (config_block != oper_state->shared_config_param)
+		kfree(config_block);
+	else
+		dev_err(dev, "Trying to free shared config block\n");
+}
+
+static void
+ipipe_dealloc_user_config_block(struct device *dev,
+				void *ipipe, void *config_block)
+{
+	kfree(config_block);
+}
+
+static void *
+ipipe_alloc_user_config_block(struct device *dev, void *ipipe,
+			      enum imp_log_chan_t chan_type)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	void *config = NULL;
+
+	if (oper_state->oper_mode == IMP_MODE_SINGLE_SHOT) {
+		if (chan_type == IMP_PREVIEWER) {
+			config =
+			    kmalloc(sizeof(struct prev_ipipeif_config),
+				    GFP_KERNEL);
+		} else if (chan_type == IMP_RESIZER) {
+			config =
+			    kmalloc(sizeof(struct rsz_config),
+				    GFP_KERNEL);
+		}
+		return config;
+	}
+
+	if (chan_type == IMP_PREVIEWER) {
+		config = kmalloc(sizeof(struct prev_ipipeif_config),
+			    GFP_KERNEL);
+	} else if (chan_type == IMP_RESIZER) {
+		config = kmalloc(sizeof(struct rsz_config),
+			    GFP_KERNEL);
+	}
+
+	return config;
+}
+
+static void
+ipipe_set_user_config_defaults(struct device *dev, void *ipipe,
+			       enum imp_log_chan_t chan_type, void *config)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	dev_dbg(dev, "ipipe_set_user_config_defaults\n");
+	if (oper_state->oper_mode == IMP_MODE_SINGLE_SHOT) {
+		if (chan_type == IMP_PREVIEWER) {
+			dev_dbg(dev, "SS-Preview\n");
+			/* preview channel in single shot mode */
+			memcpy(config, (void *)&dm365_prev_ss_config_defs,
+			       sizeof(struct prev_ipipeif_config));
+		} else {
+			dev_dbg(dev, "SS-Resize\n");
+			/* resizer channel in single shot mode */
+			memcpy(config, (void *)&dm365_rsz_ss_config_defs,
+			       sizeof(struct rsz_config));
+		}
+	} else if (oper_state->oper_mode == IMP_MODE_CONTINUOUS) {
+		/* Continuous mode */
+		if (chan_type == IMP_PREVIEWER) {
+			dev_dbg(dev, "Continuous Preview\n");
+			/* previewer defaults */
+			memcpy(config, (void *)&dm365_prev_cont_config_defs,
+			       sizeof(struct prev_ipipeif_config));
+		} else {
+			dev_dbg(dev, "Continuous resize\n");
+			/* resizer defaults */
+			memcpy(config, (void *)&dm365_rsz_cont_config_defs,
+			       sizeof(struct rsz_config));
+		}
+	} else {
+		dev_err(dev, "Incorrect mode used\n");
+	}
+}
+
+/* function :calculate_sdram_offsets()
+ *	This function calculates the offsets from start of buffer for the C
+ *	plane when output format is YUV420SP. It also calculates the offsets
+ *	from the start of the buffer when the image is flipped vertically
+ *	or horizontally for ycbcr/y/c planes
+ */
+static int calculate_sdram_offsets(struct ipipe_params *param, int index)
+{
+	int bytesperpixel = 2;
+	int image_height;
+	int image_width;
+	int yuv_420;
+	int offset;
+
+	if (!param->rsz_en[index])
+		return -EINVAL;
+
+	image_height = param->rsz_rsc_param[index].o_vsz + 1;
+	image_width = param->rsz_rsc_param[index].o_hsz + 1;
+	param->ext_mem_param[index].c_offset = 0;
+	param->ext_mem_param[index].flip_ofst_y = 0;
+	param->ext_mem_param[index].flip_ofst_c = 0;
+	if (param->ipipe_dpaths_fmt != IPIPE_RAW2RAW &&
+	    param->ipipe_dpaths_fmt != IPIPE_RAW2BOX &&
+	    param->rsz_rsc_param[index].cen &&
+	    param->rsz_rsc_param[index].yen) {
+		/* YUV 420 */
+		yuv_420 = 1;
+		bytesperpixel = 1;
+	}
+
+	/* set offset value */
+	offset = 0;
+
+	if (param->rsz_rsc_param[index].h_flip)
+		/* width * bytesperpixel - 1 */
+		offset = (image_width * bytesperpixel) - 1;
+	if (param->rsz_rsc_param[index].v_flip)
+		offset += (image_height - 1) *
+			param->ext_mem_param[index].rsz_sdr_oft_y;
+	param->ext_mem_param[index].flip_ofst_y = offset;
+	if (yuv_420) {
+		offset = 0;
+		/* half height for c-plane */
+		if (param->rsz_rsc_param[index].h_flip)
+			/* width * bytesperpixel - 1 */
+			offset = image_width - 1;
+		if (param->rsz_rsc_param[index].v_flip)
+			offset += (((image_height >> 1) - 1) *
+			param->ext_mem_param[index].
+			rsz_sdr_oft_c);
+		param->ext_mem_param[index].flip_ofst_c =
+			offset;
+		param->ext_mem_param[index].c_offset =
+		    param->ext_mem_param[index].
+		    rsz_sdr_oft_y * image_height;
+	}
+
+	return 0;
+}
+
+static void
+enable_422_420_conversion(struct ipipe_params *param, int index, boolean_t en)
+{
+	/* Enable 422 to 420 conversion */
+	param->rsz_rsc_param[index].cen = en;
+	param->rsz_rsc_param[index].yen = en;
+}
+
+static void
+configure_resizer_out_params(struct ipipe_oper_state *oper_state,
+			     struct ipipe_params *param,
+			     int index, void *output_spec,
+			     unsigned char partial, unsigned flag)
+{
+	struct rsz_output_spec *output = (struct rsz_output_spec *)output_spec;
+
+	if (partial) {
+		if (!oper_state->rsz_output_enabled[index]) {
+			param->rsz_en[index] = DISABLE;
+			return;
+		}
+		param->rsz_en[index] = ENABLE;
+		param->rsz_rsc_param[index].h_flip = output->h_flip;
+		param->rsz_rsc_param[index].v_flip = output->v_flip;
+		param->rsz_rsc_param[index].v_typ_y = output->v_typ_y;
+		param->rsz_rsc_param[index].v_typ_c = output->v_typ_c;
+		param->rsz_rsc_param[index].v_lpf_int_y =
+						output->v_lpf_int_y;
+		param->rsz_rsc_param[index].v_lpf_int_c =
+						output->v_lpf_int_c;
+		param->rsz_rsc_param[index].h_typ_y = output->h_typ_y;
+		param->rsz_rsc_param[index].h_typ_c = output->h_typ_c;
+		param->rsz_rsc_param[index].h_lpf_int_y =
+						output->h_lpf_int_y;
+		param->rsz_rsc_param[index].h_lpf_int_c =
+						output->h_lpf_int_c;
+		param->rsz_rsc_param[index].dscale_en =
+						output->en_down_scale;
+		param->rsz_rsc_param[index].h_dscale_ave_sz =
+						output->h_dscale_ave_sz;
+		param->rsz_rsc_param[index].v_dscale_ave_sz =
+						output->v_dscale_ave_sz;
+		param->ext_mem_param[index].user_y_ofst =
+				    (output->user_y_ofst + 31) & ~0x1f;
+		param->ext_mem_param[index].user_c_ofst =
+				    (output->user_c_ofst + 31) & ~0x1f;
+		return;
+	}
+
+	if (!oper_state->rsz_output_enabled[index]) {
+		param->rsz_en[index] = DISABLE;
+		return;
+	}
+
+	param->rsz_en[index] = ENABLE;
+	param->rsz_rsc_param[index].o_vsz =
+		oper_state->out_mbus_format[index].height - 1;
+	param->rsz_rsc_param[index].o_hsz =
+		oper_state->out_mbus_format[index].width - 1;
+	param->ext_mem_param[index].rsz_sdr_ptr_s_y =
+				output->vst_y;
+	param->ext_mem_param[index].rsz_sdr_ptr_e_y =
+		oper_state->out_mbus_format[index].height;
+	param->ext_mem_param[index].rsz_sdr_ptr_s_c =
+				output->vst_c;
+	param->ext_mem_param[index].rsz_sdr_ptr_e_c =
+		oper_state->out_mbus_format[index].height;
+
+	if (!flag)
+		return;
+	/* update common parameters */
+	param->rsz_rsc_param[index].h_flip = output->h_flip;
+	param->rsz_rsc_param[index].v_flip = output->v_flip;
+	param->rsz_rsc_param[index].v_typ_y = output->v_typ_y;
+	param->rsz_rsc_param[index].v_typ_c = output->v_typ_c;
+	param->rsz_rsc_param[index].v_lpf_int_y = output->v_lpf_int_y;
+	param->rsz_rsc_param[index].v_lpf_int_c = output->v_lpf_int_c;
+	param->rsz_rsc_param[index].h_typ_y = output->h_typ_y;
+	param->rsz_rsc_param[index].h_typ_c = output->h_typ_c;
+	param->rsz_rsc_param[index].h_lpf_int_y = output->h_lpf_int_y;
+	param->rsz_rsc_param[index].h_lpf_int_c = output->h_lpf_int_c;
+	param->rsz_rsc_param[index].dscale_en = output->en_down_scale;
+	param->rsz_rsc_param[index].h_dscale_ave_sz = output->h_dscale_ave_sz;
+	param->rsz_rsc_param[index].v_dscale_ave_sz = output->h_dscale_ave_sz;
+	param->ext_mem_param[index].user_y_ofst =
+					(output->user_y_ofst + 31) & ~0x1f;
+	param->ext_mem_param[index].user_c_ofst =
+					(output->user_c_ofst + 31) & ~0x1f;
+}
+
+/* function :calculate_line_length()
+ *	This function calculates the line length of various image
+ *	planes at the input and output
+ */
+static void
+calculate_line_length(enum v4l2_mbus_pixelcode pix,
+		      int width, int height, int *line_len, int *line_len_c)
+{
+	*line_len = 0;
+	*line_len_c = 0;
+
+	if (pix == V4L2_MBUS_FMT_UYVY8_2X8 ||
+				pix == V4L2_MBUS_FMT_SGRBG12_1X12) {
+		*line_len = width << 1;
+	} else if (pix == V4L2_MBUS_FMT_Y8_1X8 ||
+				pix == V4L2_MBUS_FMT_UV8_1X8) {
+		*line_len = width;
+		*line_len_c = width;
+	} else {
+		/* YUV 420 */
+		/* round width to upper 32 byte boundary */
+		*line_len = width;
+		*line_len_c = width;
+	}
+	/* adjust the line len to be a multiple of 32 */
+	*line_len += 31;
+	*line_len &= ~0x1f;
+	*line_len_c += 31;
+	*line_len_c &= ~0x1f;
+}
+
+static inline int
+rsz_validate_input_image_format(struct device *dev,
+				enum v4l2_mbus_pixelcode pix,
+				int width, int height, int *line_len)
+{
+	int val;
+
+	if (pix != V4L2_MBUS_FMT_UYVY8_2X8 && pix != V4L2_MBUS_FMT_Y8_1X8 &&
+						pix != V4L2_MBUS_FMT_UV8_1X8) {
+		dev_err(dev,
+		"resizer validate output: pix format not supported, %d\n", pix);
+		return -EINVAL;
+	}
+
+	if (width == 0 || height == 0) {
+		dev_err(dev,
+			"resizer validate input: invalid width or height\n");
+		return -EINVAL;
+	}
+
+	if (pix == V4L2_MBUS_FMT_UV8_1X8)
+		calculate_line_length(pix, width, height, &val, line_len);
+	else
+		calculate_line_length(pix, width, height, line_len, &val);
+
+	return 0;
+}
+
+static inline int
+rsz_validate_output_image_format(struct device *dev,
+				 enum v4l2_mbus_pixelcode pix, int width,
+				 int height, int *in_line_len,
+				 int *in_line_len_c)
+{
+	if (pix != V4L2_MBUS_FMT_UYVY8_2X8 && pix != V4L2_MBUS_FMT_Y8_1X8 &&
+	    pix != V4L2_MBUS_FMT_UV8_1X8 && pix !=
+	    V4L2_MBUS_FMT_YDYUYDYV8_1X16 && pix != V4L2_MBUS_FMT_SGRBG12_1X12) {
+		dev_err(dev,
+		"resizer validate output: pix format not supported, %d\n", pix);
+		return -EINVAL;
+	}
+
+	if (width == 0 || height == 0) {
+		dev_err(dev,
+			"resizer validate output: invalid width or height\n");
+		return -EINVAL;
+	}
+
+	calculate_line_length(pix, width, height, in_line_len, in_line_len_c);
+	return 0;
+}
+
+static void
+configure_common_rsz_params(struct device *dev,
+			    struct ipipe_params *param,
+			    struct rsz_config *ss_config)
+{
+	param->rsz_common.yuv_y_min = ss_config->yuv_y_min;
+	param->rsz_common.yuv_y_max = ss_config->yuv_y_max;
+	param->rsz_common.yuv_c_min = ss_config->yuv_c_min;
+	param->rsz_common.yuv_c_max = ss_config->yuv_c_max;
+	param->rsz_common.out_chr_pos = ss_config->out_chr_pos;
+	param->rsz_common.rsz_seq_crv = ss_config->chroma_sample_even;
+
+}
+
+static int
+configure_common_rsz_in_params(struct device *dev,
+			       struct ipipe_oper_state *oper_state,
+			       struct ipipe_params *param,
+			       int flag, int rsz_chained,
+			       int vst, int hst)
+{
+	enum v4l2_mbus_pixelcode pix;
+
+	pix = oper_state->in_mbus_format.code;
+
+	if (!flag) {
+		param->rsz_common.vsz = oper_state->in_mbus_format.width - 1;
+		param->rsz_common.hsz = oper_state->in_mbus_format.height - 1;
+	} else {
+		if (!rsz_chained) {
+			param->rsz_common.vps = vst;
+			param->rsz_common.hps = hst;
+		}
+		param->rsz_common.vsz = oper_state->in_mbus_format.height - 1;
+		param->rsz_common.hsz = oper_state->in_mbus_format.width - 1;
+	}
+	switch (pix) {
+	case V4L2_MBUS_FMT_SBGGR8_1X8:
+	case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
+	case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SBGGR12_1X12:
+	case V4L2_MBUS_FMT_SGRBG12_1X12:
+		param->rsz_common.src_img_fmt = RSZ_IMG_422;
+		param->rsz_common.source = IPIPE_DATA;
+		break;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		param->rsz_common.src_img_fmt = RSZ_IMG_422;
+		if (rsz_chained)
+			param->rsz_common.source = IPIPE_DATA;
+		else
+			param->rsz_common.source = IPIPEIF_DATA;
+		param->rsz_common.raw_flip = 0;
+		break;
+	case V4L2_MBUS_FMT_Y8_1X8:
+		param->rsz_common.src_img_fmt = RSZ_IMG_420;
+		/* Select y */
+		param->rsz_common.y_c = 0;
+		param->rsz_common.source = IPIPEIF_DATA;
+		param->rsz_common.raw_flip = 0;
+		break;
+	case V4L2_MBUS_FMT_UV8_1X8:
+		param->rsz_common.src_img_fmt = RSZ_IMG_420;
+		/* Select y */
+		param->rsz_common.y_c = 1;
+		param->rsz_common.source = IPIPEIF_DATA;
+		param->rsz_common.raw_flip = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+validate_ipipeif_decimation(struct device *dev,
+			    enum ipipeif_decimation dec_en,
+			    unsigned char rsz, unsigned char frame_div_mode_en,
+			    int width)
+{
+	if (dec_en && frame_div_mode_en) {
+		dev_err(dev,
+		 "dec_en & frame_div_mode_en can not enabled simultaneously\n");
+		return -EINVAL;
+	}
+	if (frame_div_mode_en) {
+		dev_err(dev, "frame_div_mode mode not supported\n");
+		return -EINVAL;
+	}
+	if (!dec_en)
+		return 0;
+
+	if (width <= IPIPE_MAX_INPUT_WIDTH) {
+		dev_err(dev,
+			"image width to be more than %d for decimation\n",
+			IPIPE_MAX_INPUT_WIDTH);
+		return -EINVAL;
+	}
+	if (rsz < IPIPEIF_RSZ_MIN || rsz > IPIPEIF_RSZ_MAX) {
+		dev_err(dev, "rsz range is %d to %d\n",
+			IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+ipipe_set_input_win(struct ipipe_oper_state *oper_state,
+		    struct v4l2_mbus_framefmt *format)
+{
+	struct ipipe_params *param = oper_state->shared_config_param;
+	struct imp_window win;
+
+	if (oper_state->oper_mode == IMP_MODE_SINGLE_SHOT)
+		return 0;
+
+	/* init */
+	win.width = format->width;
+	win.height = format->height;
+	win.hst = 0;
+	win.vst = 1;
+
+	if (param->ipipeif_param.decimation)
+		param->ipipe_hsz = ((win.width * IPIPEIF_RSZ_CONST) /
+				param->ipipeif_param.rsz) - 1;
+	else
+		param->ipipe_hsz = win.width - 1;
+
+	if (oper_state->in_mbus_format.field == V4L2_FIELD_INTERLACED) {
+		param->ipipe_vsz = (win.height >> 1) - 1;
+		param->ipipe_vps = win.vst >> 1;
+	} else {
+		param->ipipe_vsz = win.height - 1;
+		param->ipipe_vps = win.vst;
+	}
+	param->ipipe_hps = win.hst;
+	param->rsz_common.vsz = param->ipipe_vsz;
+	param->rsz_common.hsz = param->ipipe_hsz;
+
+	return 0;
+}
+
+static int
+ipipe_set_out_pixel_format(struct ipipe_oper_state *oper_state,
+			   struct v4l2_mbus_framefmt *format)
+{
+	struct ipipe_params *param = oper_state->shared_config_param;
+	enum v4l2_mbus_pixelcode output_pix;
+	enum v4l2_mbus_pixelcode input_pix;
+
+	input_pix = oper_state->in_mbus_format.code;
+	output_pix = oper_state->out_mbus_format[RSZ_A].code;
+
+	/* if image is RAW, preserve raw image format while flipping.
+	 * otherwise preserve, preserve ycbcr format while flipping
+	 */
+	if (output_pix == V4L2_MBUS_FMT_SGRBG12_1X12)
+		param->rsz_common.raw_flip = 1;
+	else
+		param->rsz_common.raw_flip = 0;
+
+	return ipipe_process_pix_fmts(input_pix, output_pix, param);
+}
+
+static int
+ipipe_set_output_win(struct ipipe_oper_state *oper_state,
+		     struct v4l2_mbus_framefmt *format)
+{
+	struct ipipe_params *param = oper_state->shared_config_param;
+	struct rsz_output_spec output_specs;
+	enum v4l2_mbus_pixelcode out_pix;
+	struct imp_window win;
+	int ret = -EINVAL;
+	int line_len_c;
+	int line_len;
+
+	/* for single-shot output window settings
+	   are done as part of set config */
+	if (oper_state->oper_mode == IMP_MODE_SINGLE_SHOT)
+		return 0;
+
+	win.width = format->width;
+	/* Always set output height same as in height
+	   for de-interlacing
+	 */
+	win.height = format->height;
+	win.hst = 0;
+	win.vst = 0;
+
+	if (!param->rsz_en[RSZ_A]) {
+		pr_err("Resizer output1 not enabled\n");
+		return ret;
+	}
+
+	output_specs.vst_y = win.vst;
+
+	if (oper_state->out_mbus_format[RSZ_A].code ==
+				V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+		output_specs.vst_c = win.vst;
+
+	configure_resizer_out_params(oper_state, param, RSZ_A,
+						&output_specs, 0, 0);
+	out_pix = oper_state->out_mbus_format[RSZ_A].code;
+	calculate_line_length(out_pix, param->rsz_rsc_param[0].o_hsz + 1,
+			param->rsz_rsc_param[0].o_vsz + 1, &line_len,
+					&line_len_c);
+	param->ext_mem_param[0].rsz_sdr_oft_y = line_len;
+	param->ext_mem_param[0].rsz_sdr_oft_c = line_len_c;
+	calculate_resize_ratios(param, RSZ_A);
+
+	if (param->rsz_en[RSZ_B])
+		calculate_resize_ratios(param, RSZ_B);
+
+	if (oper_state->out_mbus_format[RSZ_A].code ==
+				V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+		enable_422_420_conversion(param, RSZ_A, ENABLE);
+	else
+		enable_422_420_conversion(param, RSZ_A, DISABLE);
+
+	ret = calculate_sdram_offsets(param, RSZ_A);
+	if (param->rsz_en[RSZ_B])
+		ret = calculate_sdram_offsets(param, RSZ_B);
+
+	if (ret)
+		pr_err("Error in calculating sdram offsets\n");
+
+	return ret;
+}
+
+static int configure_formats_in_cont_mode(struct ipipe_oper_state *oper_state)
+{
+	struct v4l2_mbus_framefmt *in_format = &oper_state->in_mbus_format;
+	struct v4l2_mbus_framefmt *out_format =
+					&oper_state->out_mbus_format[RSZ_A];
+	struct ipipe_params *param = oper_state->shared_config_param;
+	int ret = 0;
+
+	param->rsz_common.src_img_fmt = RSZ_IMG_422;
+
+	ret = ipipe_set_input_win(oper_state, in_format);
+	if (ret)
+		return ret;
+
+	/* output format */
+	ret = ipipe_set_out_pixel_format(oper_state, out_format);
+	if (ret)
+		return ret;
+
+	return ipipe_set_output_win(oper_state, out_format);
+}
+
+static int
+configure_resizer_in_ss_mode(struct device *dev,
+			     struct ipipe_oper_state *oper_state,
+			     void *user_config, int resizer_chained,
+			     struct ipipe_params *param)
+{
+	/* resizer in standalone mode. In this mode if serializer
+	 * is enabled, we need to set config params in the hw.
+	 */
+	struct rsz_config *ss_config = (struct rsz_config *)user_config;
+	enum v4l2_mbus_pixelcode output1_pix;
+	enum v4l2_mbus_pixelcode output2_pix;
+	enum v4l2_mbus_pixelcode input_pix;
+	int line_len_c;
+	int line_len;
+	int ret;
+
+	input_pix = oper_state->in_mbus_format.code;
+	/* If input to IPIPE is BAYER format, for resizer it will
+	   be UYVY.
+	 */
+	if (input_pix == V4L2_MBUS_FMT_SGRBG12_1X12)
+		input_pix = V4L2_MBUS_FMT_UYVY8_2X8;
+
+	ret = rsz_validate_input_image_format(dev, input_pix, oper_state->
+					      in_mbus_format.width,
+					      oper_state->in_mbus_format.height,
+					      &line_len);
+
+	if (ret)
+		return -EINVAL;
+
+	ret = mutex_lock_interruptible(&oper_state->lock);
+	if (ret)
+		return ret;
+	if (!ss_config->input.line_length)
+		param->ipipeif_param.adofs = line_len;
+	else {
+		param->ipipeif_param.adofs = ss_config->input.line_length;
+		param->ipipeif_param.adofs =
+				(param->ipipeif_param.adofs + 31) & ~0x1f;
+	}
+
+	if (oper_state->rsz_output_enabled[RSZ_A]) {
+		param->rsz_en[RSZ_A] = ENABLE;
+		param->rsz_rsc_param[RSZ_A].mode = IPIPEIF_ONE_SHOT;
+
+		output1_pix = oper_state->out_mbus_format[RSZ_A].code;
+
+		ret = rsz_validate_output_image_format(dev, output1_pix,
+						oper_state->
+						out_mbus_format[RSZ_A].
+						width, oper_state->
+						out_mbus_format[RSZ_A].
+						height, &line_len, &line_len_c);
+		if (ret) {
+			mutex_unlock(&oper_state->lock);
+			return ret;
+		}
+		param->ext_mem_param[RSZ_A].rsz_sdr_oft_y = line_len;
+		param->ext_mem_param[RSZ_A].rsz_sdr_oft_c = line_len_c;
+		configure_resizer_out_params(oper_state, param, RSZ_A,
+					&ss_config->output1, 0, 1);
+
+		if (output1_pix == V4L2_MBUS_FMT_SGRBG12_1X12)
+			param->rsz_common.raw_flip = 1;
+		else
+			param->rsz_common.raw_flip = 0;
+
+		if (output1_pix == V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+			enable_422_420_conversion(param, RSZ_A, ENABLE);
+		else
+			enable_422_420_conversion(param, RSZ_A, DISABLE);
+	}
+
+	if (oper_state->rsz_output_enabled[RSZ_B]) {
+		param->rsz_en[RSZ_B] = ENABLE;
+		param->rsz_rsc_param[RSZ_B].mode = IPIPEIF_ONE_SHOT;
+
+		output2_pix = oper_state->out_mbus_format[RSZ_B].code;
+		ret = rsz_validate_output_image_format(dev, output2_pix,
+						oper_state->
+						out_mbus_format[RSZ_B].
+						width, oper_state->
+						out_mbus_format[RSZ_B].
+						height, &line_len, &line_len_c);
+		if (ret) {
+			mutex_unlock(&oper_state->lock);
+			return ret;
+		}
+		param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
+		param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
+		configure_resizer_out_params(oper_state, param, RSZ_B,
+					&ss_config->output2, 0, 1);
+		if (output2_pix == V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+			enable_422_420_conversion(param, RSZ_B, ENABLE);
+		else
+			enable_422_420_conversion(param, RSZ_B, DISABLE);
+	}
+	configure_common_rsz_params(dev, param, ss_config);
+	if (resizer_chained) {
+		oper_state->rsz_chained = 1;
+		oper_state->rsz_config_state = STATE_CONFIGURED;
+	} else {
+		oper_state->rsz_chained = 0;
+		ret = validate_ipipeif_decimation(dev, ss_config->input.dec_en,
+						  ss_config->input.rsz,
+						  ss_config->input.
+						  frame_div_mode_en,
+						  oper_state->
+						  in_mbus_format.width);
+		if (ret) {
+			mutex_unlock(&oper_state->lock);
+			return ret;
+		}
+		output1_pix = oper_state->out_mbus_format[RSZ_A].code;
+		if (ipipe_process_pix_fmts(input_pix, output1_pix, param) < 0) {
+			dev_err(dev, "Error in input or output pix format\n");
+			mutex_unlock(&oper_state->lock);
+			return -EINVAL;
+		}
+
+		param->ipipeif_param.source = IPIPEIF_SDRAM_YUV;
+		param->ipipeif_param.glob_hor_size = ss_config->input.ppln;
+		param->ipipeif_param.glob_ver_size = ss_config->input.lpfr;
+		param->ipipeif_param.hnum = oper_state->in_mbus_format.width;
+		param->ipipeif_param.vnum = oper_state->in_mbus_format.height;
+		param->ipipeif_param.var.if_5_1.clk_div =
+						ss_config->input.clk_div;
+		if (ss_config->input.dec_en) {
+			param->ipipeif_param.decimation = IPIPEIF_DECIMATION_ON;
+			param->ipipeif_param.rsz = ss_config->input.rsz;
+			param->ipipeif_param.avg_filter =
+			    (enum ipipeif_avg_filter)ss_config->input.
+								avg_filter_en;
+			param->ipipe_hsz =
+					(((oper_state->in_mbus_format.width *
+				IPIPEIF_RSZ_CONST) / ss_config->input.rsz) - 1);
+		}
+		if (input_pix == V4L2_MBUS_FMT_Y8_1X8 ||
+					  input_pix == V4L2_MBUS_FMT_UV8_1X8) {
+			param->ipipeif_param.var.if_5_1.pack_mode =
+							IPIPEIF_5_1_PACK_8_BIT;
+			param->ipipeif_param.var.if_5_1.source1 = IPIPEIF_CCDC;
+			param->ipipeif_param.var.if_5_1.isif_port.if_type =
+						      V4L2_MBUS_FMT_YUYV8_1X16;
+			param->ipipeif_param.var.if_5_1.data_shift =
+							IPIPEIF_5_1_BITS11_0;
+			param->ipipeif_param.source = IPIPEIF_SDRAM_RAW;
+		}
+		if (input_pix == V4L2_MBUS_FMT_UV8_1X8)
+			param->ipipeif_param.var.if_5_1.isif_port.if_type =
+						V4L2_MBUS_FMT_SGRBG12_1X12;
+		param->ipipe_hsz = oper_state->in_mbus_format.width - 1;
+		param->ipipe_vsz = oper_state->in_mbus_format.height - 1;
+		param->ipipe_vps = ss_config->input.vst;
+		param->ipipe_hps = ss_config->input.hst;
+		param->ipipe_dpaths_fmt = IPIPE_YUV2YUV;
+		configure_common_rsz_in_params(dev, oper_state, param, 1,
+				resizer_chained, ss_config->input.vst,
+				 ss_config->input.hst);
+		if (param->rsz_en[RSZ_A]) {
+			calculate_resize_ratios(param, RSZ_A);
+			calculate_sdram_offsets(param, RSZ_A);
+			/* Overriding resize ratio calculation */
+			if (input_pix == V4L2_MBUS_FMT_UV8_1X8) {
+				param->rsz_rsc_param[RSZ_A].v_dif =
+				    (((param->ipipe_vsz + 1) * 2) * 256) /
+				    (param->rsz_rsc_param[RSZ_A].o_vsz + 1);
+			}
+		}
+
+		if (param->rsz_en[RSZ_B]) {
+			calculate_resize_ratios(param, RSZ_B);
+			calculate_sdram_offsets(param, RSZ_B);
+			/* Overriding resize ratio calculation */
+			if (input_pix == V4L2_MBUS_FMT_UV8_1X8) {
+				param->rsz_rsc_param[RSZ_B].v_dif =
+				    (((param->ipipe_vsz + 1) * 2) * 256) /
+				    (param->rsz_rsc_param[RSZ_B].o_vsz + 1);
+			}
+		}
+	}
+	mutex_unlock(&oper_state->lock);
+
+	return 0;
+}
+
+static int
+configure_resizer_in_cont_mode(struct device *dev,
+			       struct ipipe_oper_state *oper_state,
+			       void *user_config, int resizer_chained,
+			       struct ipipe_params *param)
+{
+	/* Continuous mode. This is a shared config block */
+	struct rsz_config *cont_config = (struct rsz_config *)user_config;
+	int line_len_c;
+	int line_len;
+	int ret;
+
+	if (!resizer_chained) {
+		dev_err(dev,
+		"Resizer cannot be configured standalone in continuous mode\n");
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&oper_state->lock);
+	if (ret)
+		return ret;
+
+	if (!oper_state->rsz_output_enabled[RSZ_A]) {
+		dev_err(dev, "enable resizer - 0\n");
+		mutex_unlock(&oper_state->lock);
+		return -EINVAL;
+	}
+	param->rsz_en[RSZ_A] = ENABLE;
+	param->rsz_rsc_param[RSZ_A].mode = IPIPEIF_CONTINUOUS;
+	configure_resizer_out_params(oper_state, param, RSZ_A,
+				&cont_config->output1, 1, 0);
+	param->rsz_en[RSZ_B] = DISABLE;
+
+	if (oper_state->rsz_output_enabled[RSZ_B]) {
+		enum v4l2_mbus_pixelcode out2_pix;
+
+		out2_pix = oper_state->out_mbus_format[RSZ_B].code;
+		param->rsz_rsc_param[RSZ_B].mode = IPIPEIF_CONTINUOUS;
+		ret = rsz_validate_output_image_format(dev, out2_pix,
+						       oper_state->
+						       out_mbus_format[RSZ_B].
+						       width, oper_state->
+						       out_mbus_format[RSZ_B].
+						       height, &line_len,
+						       &line_len_c);
+		if (ret) {
+			mutex_unlock(&oper_state->lock);
+			return ret;
+		}
+		param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
+		param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
+		configure_resizer_out_params(oper_state, param, RSZ_B,
+						&cont_config->output2, 0, 1);
+		if (out2_pix == V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+			enable_422_420_conversion(param, RSZ_B, ENABLE);
+		else
+			enable_422_420_conversion(param, RSZ_B, DISABLE);
+	}
+	oper_state->rsz_chained = 1;
+	oper_state->rsz_config_state = STATE_CONFIGURED;
+	mutex_unlock(&oper_state->lock);
+
+	return 0;
+}
+
+static int
+ipipe_set_resize_config(struct device *dev, void *ipipe,
+			int resizer_chained, void *user_config, void *config)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct ipipe_params *param = (struct ipipe_params *)config;
+	int ret;
+
+	dev_dbg(dev, "ipipe_set_resize_config, resizer_chained = %d\n",
+						resizer_chained);
+	if (!user_config || !config) {
+		dev_err(dev, "Invalid user_config or config ptr\n");
+		return -EINVAL;
+	}
+
+	memcpy((void *)config, (void *)&dm365_ipipe_defs,
+			sizeof(struct ipipe_params));
+
+	/* restore if_param */
+	if (oper_state->oper_mode == IMP_MODE_CONTINUOUS)
+		param->ipipeif_param.var.if_5_1.isif_port =
+						oper_state->if_param;
+
+	if (oper_state->oper_mode != IMP_MODE_SINGLE_SHOT) {
+		ret =  configure_resizer_in_cont_mode(dev, oper_state,
+					user_config, resizer_chained, param);
+		if (ret)
+			return ret;
+
+		/* In continuous mode, after setting config,
+		   set input and output format for IPIPE */
+		return configure_formats_in_cont_mode(oper_state);
+	}
+
+	ret = configure_resizer_in_ss_mode(dev, oper_state,
+				user_config, resizer_chained, param);
+	if (!ret && !oper_state->en_serializer && !resizer_chained)
+		ret = ipipe_hw_setup(config);
+
+	return ret;
+}
+
+static void configure_resize_passthru(struct ipipe_params *param, int bypass)
+{
+	param->rsz_rsc_param[RSZ_A].cen = DISABLE;
+	param->rsz_rsc_param[RSZ_A].yen = DISABLE;
+	param->rsz_rsc_param[RSZ_A].v_phs_y = 0;
+	param->rsz_rsc_param[RSZ_A].v_phs_c = 0;
+	param->rsz_rsc_param[RSZ_A].v_dif = 256;
+	param->rsz_rsc_param[RSZ_A].v_lpf_int_y = 0;
+	param->rsz_rsc_param[RSZ_A].v_lpf_int_c = 0;
+	param->rsz_rsc_param[RSZ_A].h_phs = 0;
+	param->rsz_rsc_param[RSZ_A].h_dif = 256;
+	param->rsz_rsc_param[RSZ_A].h_lpf_int_y = 0;
+	param->rsz_rsc_param[RSZ_A].h_lpf_int_c = 0;
+	param->rsz_rsc_param[RSZ_A].dscale_en = DISABLE;
+	param->rsz2rgb[RSZ_A].rgb_en = DISABLE;
+	param->rsz_en[RSZ_A] = ENABLE;
+	param->rsz_en[RSZ_B] = DISABLE;
+	if (bypass) {
+		param->rsz_rsc_param[RSZ_A].i_vps = 0;
+		param->rsz_rsc_param[RSZ_A].i_hps = 0;
+		/* Raw Bypass */
+		param->rsz_common.passthrough = IPIPE_BYPASS_ON;
+	}
+}
+
+static inline int
+prev_validate_output_image_format(struct device *dev,
+				  enum v4l2_mbus_pixelcode pix, int *line_len,
+				  int in_width, int in_height)
+{
+	if (pix != V4L2_MBUS_FMT_UYVY8_2X8 &&
+				  pix != V4L2_MBUS_FMT_SGRBG12_1X12) {
+		dev_err(dev,
+		       "previewer output: pix format not supported, %d\n", pix);
+		return -EINVAL;
+	}
+
+	if (in_width == 0 || in_height == 0) {
+		dev_err(dev, "previewer output: invalid width or height\n");
+		return -EINVAL;
+	}
+
+	*line_len = in_width * 2;
+
+	/* Adjust line length to be a multiple of 32 */
+	*line_len += 31;
+	*line_len &= ~0x1f;
+
+	return 0;
+}
+
+static inline int
+validate_preview_input_spec(struct device *dev,
+			    enum v4l2_mbus_pixelcode pix,
+			    int width,
+			    int height, int *line_len)
+{
+	if (pix != V4L2_MBUS_FMT_UYVY8_2X8 &&
+	    pix != V4L2_MBUS_FMT_SGRBG12_1X12 &&
+	    pix != V4L2_MBUS_FMT_SBGGR8_1X8 &&
+	    pix != V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8 &&
+	    pix != V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 &&
+			pix != V4L2_MBUS_FMT_SBGGR12_1X12) {
+		dev_err(dev,
+		"validate_preview_input_spec:pix format not supported, %d\n",
+		pix);
+		return -EINVAL;
+	}
+	if (width == 0 || height == 0) {
+		dev_err(dev,
+		    "validate_preview_input_spec: invalid width or height\n");
+		return -EINVAL;
+	}
+
+	if (pix == V4L2_MBUS_FMT_UYVY8_2X8 || pix == V4L2_MBUS_FMT_SGRBG12_1X12)
+		*line_len = width * 2;
+	else if (pix == V4L2_MBUS_FMT_SBGGR8_1X8 ||
+		 pix == V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8 ||
+		 pix == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8)
+		*line_len = width;
+	else
+		/* 12 bit */
+		*line_len = width + (width >> 1);
+	/* Adjust line length to be a multiple of 32 */
+	*line_len += 31;
+	*line_len &= ~0x1f;
+
+	return 0;
+}
+
+static int
+configure_previewer_in_cont_mode(struct device *dev,
+				 struct ipipe_oper_state *oper_state,
+				 void *user_config,
+				 struct ipipe_params *param)
+{
+	struct prev_ipipeif_config *config =
+			(struct prev_ipipeif_config *)user_config;
+	int ret;
+
+	if (config->dec_en && (config->rsz <
+		IPIPEIF_RSZ_MIN || config->rsz > IPIPEIF_RSZ_MAX)) {
+		dev_err(dev, "Resizer range is %d to %d\n",
+			IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&oper_state->lock);
+	if (ret)
+		return ret;
+
+	param->rsz_common.passthrough = config->bypass;
+	param->ipipeif_param.source = IPIPEIF_CCDC;
+	param->ipipeif_param.clock_select = IPIPEIF_PIXCEL_CLK;
+	param->ipipeif_param.mode = IPIPEIF_CONTINUOUS;
+
+	if (config->dec_en) {
+		param->ipipeif_param.decimation = IPIPEIF_DECIMATION_ON;
+		param->ipipeif_param.rsz = config->rsz;
+		param->ipipeif_param.avg_filter =
+			(enum ipipeif_avg_filter)config->avg_filter_en;
+	}
+	/* IPIPE mode */
+	param->ipipe_mode = IPIPEIF_CONTINUOUS;
+
+	switch (oper_state->in_mbus_format.code) {
+	case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
+	case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SGRBG12_1X12:
+		param->ipipe_colpat = ipipe_sgrbg_pattern;
+		break;
+	default:
+		param->ipipe_colpat = ipipe_srggb_pattern;
+		break;
+	}
+
+	param->ipipeif_param.gain = ipipeif_gain;
+	param->ipipeif_param.var.if_5_1.clip = config->clip;
+	param->ipipeif_param.var.if_5_1.dpc = config->dpc;
+	param->ipipeif_param.var.if_5_1.align_sync = config->align_sync;
+	param->ipipeif_param.var.if_5_1.rsz_start = config->rsz_start;
+
+	if (!oper_state->rsz_chained) {
+		param->rsz_rsc_param[0].mode = IPIPEIF_CONTINUOUS;
+		/* setup bypass resizer */
+		configure_resize_passthru(param, 0);
+	}
+
+	if (config->bypass)
+		configure_resize_passthru(param, 1);
+
+	oper_state->prev_config_state = STATE_CONFIGURED;
+	mutex_unlock(&oper_state->lock);
+
+	return 0;
+}
+
+/*
+ * preview_chroma_phase - Configure byte layout of YUV image.
+ */
+static int preview_chroma_phase(enum v4l2_mbus_pixelcode pixelcode)
+{
+	switch (pixelcode) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		return IPIPEIF_CBCR_Y;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int
+configure_previewer_in_ss_mode(struct device *dev,
+			       struct ipipe_oper_state *oper_state,
+			       void *user_config, struct ipipe_params *param)
+{
+	struct prev_ipipeif_config *config =
+			(struct prev_ipipeif_config *)user_config;
+	enum v4l2_mbus_pixelcode output_pix;
+	enum v4l2_mbus_pixelcode input_pix;
+	int chroma_phase;
+	int line_len;
+	int ret;
+
+	output_pix = oper_state->out_mbus_format[RSZ_A].code;
+	input_pix = oper_state->in_mbus_format.code;
+
+	ret = validate_preview_input_spec(dev, input_pix,
+					  oper_state->in_mbus_format.width,
+					  oper_state->in_mbus_format.height,
+					  &line_len);
+	if (ret)
+		return -EINVAL;
+
+	ret = mutex_lock_interruptible(&oper_state->lock);
+	if (ret)
+		return ret;
+
+	if (!config->input_spec.line_length) {
+		param->ipipeif_param.adofs = line_len;
+	} else {
+		param->ipipeif_param.adofs = config->input_spec.line_length;
+		param->ipipeif_param.adofs =
+				(param->ipipeif_param.adofs + 31) & ~0x1f;
+	}
+	if (config->dec_en && config->input_spec.frame_div_mode_en) {
+		dev_err(dev,
+		"dec_en & frame_div_mode_en cannot enabled simultaneously\n");
+		mutex_unlock(&oper_state->lock);
+		return -EINVAL;
+	}
+
+	ret = validate_ipipeif_decimation(dev, config->dec_en,
+					  config->rsz,
+					  config->input_spec.frame_div_mode_en,
+					  oper_state->in_mbus_format.width);
+	if (ret) {
+		mutex_unlock(&oper_state->lock);
+		return -EINVAL;
+	}
+
+	if (!oper_state->rsz_chained) {
+		ret = prev_validate_output_image_format(dev, output_pix,
+							&line_len,
+							oper_state->
+							in_mbus_format.width,
+							oper_state->
+							in_mbus_format.height);
+		if (ret) {
+			mutex_unlock(&oper_state->lock);
+			return -EINVAL;
+		}
+		param->ext_mem_param[RSZ_A].rsz_sdr_oft_y = line_len;
+		if (config->input_spec.frame_div_mode_en)
+			ret = update_preview_f_div_params(dev, oper_state->
+							  in_mbus_format.width,
+							  oper_state->
+							  in_mbus_format.width,
+							  &param->
+							  rsz_rsc_param[RSZ_A]);
+		if (ret) {
+			mutex_unlock(&oper_state->lock);
+			return -EINVAL;
+		}
+	} else {
+		if (config->input_spec.frame_div_mode_en &&
+		    param->rsz_en[RSZ_A]) {
+			if (!param->rsz_rsc_param[RSZ_A].dscale_en)
+				ret = calculate_normal_f_div_param(dev,
+							oper_state->
+							in_mbus_format.width,
+							param->rsz_rsc_param
+							  [RSZ_A].
+							  o_vsz + 1,
+							&param->rsz_rsc_param
+							  [RSZ_A]);
+			else
+				ret = calculate_down_scale_f_div_param(dev,
+							oper_state->
+							in_mbus_format.width,
+							param->rsz_rsc_param
+							  [RSZ_A].o_vsz + 1,
+							&param->rsz_rsc_param
+							  [RSZ_A]);
+			if (ret) {
+				mutex_unlock(&oper_state->lock);
+				return -EINVAL;
+			}
+		}
+		if (config->input_spec.frame_div_mode_en &&
+		    param->rsz_en[RSZ_B]) {
+			if (!param->rsz_rsc_param[RSZ_B].dscale_en)
+				ret = calculate_normal_f_div_param(dev,
+							oper_state->
+							in_mbus_format.width,
+							param->rsz_rsc_param
+							   [RSZ_B].o_vsz + 1,
+							&param->rsz_rsc_param
+							   [RSZ_B]);
+			else
+				ret = calculate_down_scale_f_div_param(dev,
+							oper_state->
+							in_mbus_format.width,
+							param->rsz_rsc_param
+							   [RSZ_B].o_vsz + 1,
+							&param->rsz_rsc_param
+							   [RSZ_B]);
+			if (ret) {
+				mutex_unlock(&oper_state->lock);
+				return -EINVAL;
+			}
+		}
+	}
+	if (ipipe_process_pix_fmts(input_pix, output_pix, param) < 0) {
+		dev_err(dev, "Error in input or output pix format\n");
+		mutex_unlock(&oper_state->lock);
+		return -EINVAL;
+	}
+	param->ipipeif_param.hnum = oper_state->in_mbus_format.width;
+	param->ipipeif_param.vnum = oper_state->in_mbus_format.height;
+	param->ipipeif_param.glob_hor_size = config->input_spec.ppln;
+	param->ipipeif_param.glob_ver_size = config->input_spec.lpfr;
+	param->ipipeif_param.var.if_5_1.clk_div = config->input_spec.clk_div;
+	chroma_phase = preview_chroma_phase(output_pix);
+	if (chroma_phase < 0) {
+		dev_err(dev, "Error in calculating chroma phase\n");
+		mutex_unlock(&oper_state->lock);
+		return -EINVAL;
+	}
+	param->ipipeif_param.var.if_5_1.chroma_phase = chroma_phase;
+	param->ipipeif_param.var.if_5_1.align_sync = config->align_sync;
+	param->ipipeif_param.var.if_5_1.rsz_start = config->rsz_start;
+	if (param->ipipeif_param.var.if_5_1.dpcm.en) {
+		param->ipipeif_param.var.if_5_1.dpcm.pred = dpcm_predictor;
+		param->ipipeif_param.var.if_5_1.dpcm.type =
+					IPIPEIF_DPCM_8BIT_12BIT;
+	}
+	/*
+	 * currently V4L2_MBUS_FMT_SGRBG12_1X12 is supported
+	 * add case's when different MBUS is also supported.
+	 */
+	switch (oper_state->in_mbus_format.code) {
+	case V4L2_MBUS_FMT_SGRBG12_1X12:
+		param->ipipeif_param.var.if_5_1.data_shift =
+				IPIPEIF_5_1_BITS11_0;
+		break;
+	default:
+		param->ipipeif_param.var.if_5_1.data_shift =
+				IPIPEIF_5_1_BITS11_0;
+	}
+
+	param->ipipe_hsz = oper_state->in_mbus_format.width - 1;
+	if (config->dec_en) {
+		if (config->rsz < IPIPEIF_RSZ_MIN ||
+		    config->rsz > IPIPEIF_RSZ_MAX) {
+			dev_err(dev, "Resizer range is %d to %d\n",
+				IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
+			mutex_unlock(&oper_state->lock);
+			return -EINVAL;
+		}
+		param->ipipeif_param.decimation = IPIPEIF_DECIMATION_ON;
+		param->ipipeif_param.rsz = config->rsz;
+		param->ipipeif_param.avg_filter =
+		    (enum ipipeif_avg_filter)config->avg_filter_en;
+		param->ipipe_hsz =
+		    (((oper_state->in_mbus_format.width * IPIPEIF_RSZ_CONST) /
+					config->rsz) - 1);
+	}
+	param->ipipeif_param.gain = ipipeif_gain;
+	param->ipipeif_param.var.if_5_1.clip = config->clip;
+	param->ipipeif_param.var.if_5_1.dpc = config->dpc;
+	switch (oper_state->in_mbus_format.code) {
+	case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
+	case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SGRBG12_1X12:
+		param->ipipe_colpat = ipipe_sgrbg_pattern;
+		break;
+	default:
+		param->ipipe_colpat = ipipe_srggb_pattern;
+		break;
+	}
+	param->ipipe_vps = config->input_spec.vst;
+	param->ipipe_hps = config->input_spec.hst;
+	param->ipipe_vsz = oper_state->in_mbus_format.height - 1;
+	if (input_pix == V4L2_MBUS_FMT_UYVY8_2X8)
+		param->ipipeif_param.source = IPIPEIF_SDRAM_YUV;
+	else
+		param->ipipeif_param.source = IPIPEIF_SDRAM_RAW;
+
+	configure_common_rsz_in_params(dev, oper_state, param, 1,
+		oper_state->rsz_chained, config->input_spec.vst,
+		config->input_spec.hst);
+
+	param->rsz_common.passthrough = config->bypass;
+	/* update the resize parameters */
+	if (config->bypass == IPIPE_BYPASS_ON ||
+			param->ipipe_dpaths_fmt == IPIPE_RAW2RAW) {
+		/* Bypass resizer */
+		configure_resize_passthru(param, 1);
+	} else {
+		if (oper_state->rsz_chained) {
+			if (param->rsz_en[RSZ_A]) {
+				calculate_resize_ratios(param, RSZ_A);
+				calculate_sdram_offsets(param, RSZ_A);
+			}
+			if (param->rsz_en[RSZ_B]) {
+				calculate_resize_ratios(param, RSZ_B);
+				calculate_sdram_offsets(param, RSZ_B);
+			}
+		} else {
+			struct rsz_output_spec *output_specs =
+				kmalloc(sizeof(struct rsz_output_spec),
+					GFP_KERNEL);
+			if (!output_specs) {
+				dev_err(dev, "Failed to allocate memory\n");
+				mutex_unlock(&oper_state->lock);
+				return -EINVAL;
+			}
+				/* Using resizer as pass through */
+			configure_resize_passthru(param, 0);
+			memset((void *)output_specs, 0,
+				sizeof(struct rsz_output_spec));
+
+			output_specs->vst_y = config->input_spec.vst;
+			configure_resizer_out_params(oper_state, param, RSZ_A,
+						output_specs, 0, 0);
+			calculate_sdram_offsets(param, RSZ_A);
+			kfree(output_specs);
+		}
+	}
+	mutex_unlock(&oper_state->lock);
+
+	return 0;
+}
+
+static int
+ipipe_set_preview_config(struct device *dev, void *ipipe,
+			 void *user_config, void *config)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct ipipe_params *param = (struct ipipe_params *)config;
+	int ret;
+
+	dev_dbg(dev, "ipipe_set_preview_config\n");
+
+	if (!user_config || !config) {
+		dev_err(dev, "Invalid user_config or config ptr\n");
+		return -EINVAL;
+	}
+
+	if (!oper_state->rsz_chained) {
+		/* For chained resizer, defaults are set by resizer */
+		memcpy((void *)config, (void *)&dm365_ipipe_defs,
+				sizeof(struct ipipe_params));
+
+		/* restore if_param */
+		if (oper_state->oper_mode == IMP_MODE_CONTINUOUS)
+			param->ipipeif_param.var.if_5_1.isif_port =
+							oper_state->if_param;
+
+		/* for previewer only continuous mode, RSZ_A should be on */
+		oper_state->rsz_output_enabled[RSZ_A] = 1;
+	}
+
+	/* continuous mode */
+	if (oper_state->oper_mode == IMP_MODE_CONTINUOUS) {
+		ret = configure_previewer_in_cont_mode(dev, oper_state,
+						  user_config, param);
+		if (ret)
+			return ret;
+
+		/* In continuous mode, after setting config,
+		   set input and output format for IPIPE */
+		return configure_formats_in_cont_mode(oper_state);
+	}
+
+	/* previewer in standalone mode. In this mode if serializer
+	 * is enabled, we need to set config params for hw.
+	 */
+	ret = configure_previewer_in_ss_mode(dev, oper_state,
+							user_config, param);
+
+	if (!ret && !oper_state->en_serializer)
+		ret = ipipe_hw_setup(config);
+
+	return ret;
+}
+
+static void
+ipipe_set_in_mbus_format(void *ipipe, struct v4l2_mbus_framefmt *format)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	memcpy((void *)&oper_state->in_mbus_format, (void *)format,
+				sizeof(struct v4l2_mbus_framefmt));
+}
+
+static void
+ipipe_set_out_mbus_format(void *ipipe, struct v4l2_mbus_framefmt *format)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	memcpy((void *)&oper_state->out_mbus_format[RSZ_A], (void *)format,
+					sizeof(struct v4l2_mbus_framefmt));
+	oper_state->rsz_output_enabled[RSZ_A] = ENABLE;
+}
+
+static void
+ipipe_set_out2_mbus_format(void *ipipe, struct v4l2_mbus_framefmt *format)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	memcpy((void *)&oper_state->out_mbus_format[RSZ_B], (void *)format,
+					sizeof(struct v4l2_mbus_framefmt));
+	oper_state->rsz_output_enabled[RSZ_B] = ENABLE;
+}
+
+static int ipipe_get_output_state(void *ipipe, unsigned char out_sel)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct ipipe_params *param = oper_state->shared_config_param;
+
+	if (out_sel != RSZ_A && out_sel != RSZ_B)
+		return 0;
+	return param->rsz_en[out_sel];
+}
+
+/* This should be called only after setting the output
+ * window params. This also assumes the corresponding
+ * output is configured prior to calling this.
+ */
+static int ipipe_get_line_length(void *ipipe, unsigned char out_sel)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct ipipe_params *param = oper_state->shared_config_param;
+
+	if (out_sel != RSZ_A && out_sel != RSZ_B)
+		return -EINVAL;
+	/* assume output is always UYVY. Change this if we
+	 * support RGB
+	 */
+	if (!param->rsz_en[out_sel])
+		return -EINVAL;
+	return param->ext_mem_param[out_sel].rsz_sdr_oft_y;
+}
+
+static int ipipe_get_image_height(void *ipipe, unsigned char out_sel)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	struct ipipe_params *param = oper_state->shared_config_param;
+
+	if (out_sel != RSZ_A && out_sel != RSZ_B)
+		return -EINVAL;
+	if (!param->rsz_en[out_sel])
+		return -EINVAL;
+	return param->rsz_rsc_param[out_sel].o_vsz + 1;
+}
+
+/* Assume valid param ptr */
+static int ipipe_set_hw_if_param(void *ipipe, struct vpfe_hw_if_param *if_param)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+	int ret;
+
+	ret = mutex_lock_interruptible(&oper_state->lock);
+	if (ret)
+		return ret;
+	/* save if_param locally */
+	memcpy((void *)&oper_state->if_param, (void *)if_param,
+				sizeof(struct vpfe_hw_if_param));
+	mutex_unlock(&oper_state->lock);
+	return 0;
+}
+
+static struct imp_hw_interface dm365_ipipe_interface = {
+	.name = "DM365 IPIPE",
+	.owner = THIS_MODULE,
+	.prev_enum_modules = prev_enum_preview_cap,
+	.set_oper_mode = ipipe_set_oper_mode,
+	.reset_oper_mode = ipipe_reset_oper_mode,
+	.get_oper_mode = prev_get_oper_mode,
+	.get_hw_state = ipipe_get_oper_state,
+	.set_hw_state = ipipe_set_oper_state,
+	.resizer_chain = ipipe_rsz_chain_state,
+	.lock_chain = ipipe_lock_chain,
+	.unlock_chain = ipipe_unlock_chain,
+	.serialize = ipipe_serialize,
+	.alloc_config_block = ipipe_alloc_config_block,
+	.dealloc_config_block = ipipe_dealloc_config_block,
+	.alloc_user_config_block = ipipe_alloc_user_config_block,
+	.dealloc_config_block = ipipe_dealloc_user_config_block,
+	.set_user_config_defaults = ipipe_set_user_config_defaults,
+	.set_preview_config = ipipe_set_preview_config,
+	.set_resizer_config = ipipe_set_resize_config,
+	.set_preview_module_params = ipipe_set_preview_module_params,
+	.get_preview_module_params = ipipe_get_preview_module_params,
+	.update_inbuf_address = ipipe_set_ipipe_if_address,
+	.update_outbuf1_address = ipipe_update_outbuf1_address,
+	.update_outbuf2_address = ipipe_update_outbuf2_address,
+	.enable = ipipe_enable,
+	.enable_resize = rsz_src_enable,
+	.hw_setup = ipipe_do_hw_setup,
+	.get_resizer_config_state = ipipe_get_rsz_config_state,
+	.get_previewer_config_state = ipipe_get_prev_config_state,
+	.set_hw_if_param = ipipe_set_hw_if_param,
+	.set_in_mbus_format = ipipe_set_in_mbus_format,
+	.set_out_mbus_format = ipipe_set_out_mbus_format,
+	.set_out2_mbus_format = ipipe_set_out2_mbus_format,
+	.get_output_state = ipipe_get_output_state,
+	.get_line_length = ipipe_get_line_length,
+	.get_image_height = ipipe_get_image_height,
+	.get_image_height = ipipe_get_image_height,
+	.get_max_output_width = ipipe_get_max_output_width,
+	.get_max_output_height = ipipe_get_max_output_height,
+	.enum_pix = ipipe_enum_pix,
+	.prv_s_ctrl = preview_s_ctrl,
+};
+
+struct imp_hw_interface *imp_get_hw_if(void)
+{
+	return &dm365_ipipe_interface;
+}
+
+void enable_serializer(void *ipipe, int val)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	oper_state->en_serializer = val;
+}
+
+int ipipe_init(void **ipipe)
+{
+	struct ipipe_oper_state *oper_state;
+
+	*ipipe = kmalloc(sizeof(struct ipipe_oper_state), GFP_KERNEL);
+	if (!*ipipe) {
+		pr_err("dm365_ipipe_init: Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+	oper_state = (struct ipipe_oper_state *)*ipipe;
+
+	/* ipipe module operation state & configuration */
+	oper_state->oper_mode = IMP_MODE_NOT_CONFIGURED;
+	oper_state->ipipe_raw_yuv_pix_formats[0] = V4L2_PIX_FMT_UYVY;
+	oper_state->ipipe_raw_yuv_pix_formats[1] = V4L2_PIX_FMT_NV12;
+
+	oper_state->shared_config_param =
+			kmalloc(sizeof(struct ipipe_params), GFP_KERNEL);
+
+	if (!oper_state->shared_config_param) {
+		pr_err("dm365_ipipe_init: failed to allocate memory\n");
+		return -ENOMEM;
+	}
+	memcpy(&dm365_ipipe_defs.ipipeif_param.var.if_5_1,
+		&ipipeif_5_1_defaults, sizeof(struct ipipeif_5_1));
+	memcpy(&oper_state->lutdpc.table, &oper_state->ipipe_lutdpc_table,
+	       sizeof(oper_state->lutdpc.table));
+	memcpy(&oper_state->lut_3d.table , &oper_state->ipipe_3d_lut_table,
+		sizeof(oper_state->lut_3d.table));
+	memcpy(&oper_state->gbce.table, &oper_state->ipipe_gbce_table,
+		sizeof(oper_state->gbce.table));
+	memcpy(&oper_state->gamma.table_r, &oper_state->ipipe_gamma_table_r,
+		sizeof(oper_state->gamma.table_r));
+	memcpy(&oper_state->gamma.table_g, &oper_state->ipipe_gamma_table_g,
+		sizeof(oper_state->gamma.table_g));
+	memcpy(&oper_state->gamma.table_b, &oper_state->ipipe_gamma_table_b,
+		sizeof(oper_state->gamma.table_b));
+	memcpy(&oper_state->yee.table, &oper_state->ipipe_yee_table,
+		sizeof(oper_state->yee.table));
+	mutex_init(&oper_state->lock);
+	oper_state->state = CHANNEL_FREE;
+	oper_state->prev_config_state = STATE_NOT_CONFIGURED;
+	oper_state->rsz_config_state = STATE_NOT_CONFIGURED;
+	oper_state->out_mbus_format[RSZ_A].code = V4L2_MBUS_FMT_UYVY8_2X8;
+	oper_state->out_mbus_format[RSZ_B].code = V4L2_MBUS_FMT_UYVY8_2X8;
+	oper_state->resource_in_use = 0;
+	oper_state->rsz_chained = 0;
+
+	return 0;
+}
+
+void ipipe_cleanup(void *ipipe)
+{
+	struct ipipe_oper_state *oper_state = (struct ipipe_oper_state *)ipipe;
+
+	kfree(oper_state->shared_config_param);
+	kfree(oper_state);
+}
diff --git a/drivers/media/platform/davinci/dm365_ipipe.h b/drivers/media/platform/davinci/dm365_ipipe.h
new file mode 100644
index 0000000..2611498
--- /dev/null
+++ b/drivers/media/platform/davinci/dm365_ipipe.h
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ *
+ * Feature description
+ * ===================
+ *
+ * VPFE hardware setup
+ *
+ * case 1: Capture to SDRAM with out IPIPE
+ * ****************************************
+ *
+ *            parallel
+ *                port
+ *
+ * Image sensor/       ________
+ * Yuv decoder    ---->| CCDC |--> SDRAM
+ *                     |______|
+ *
+ * case 2: Capture to SDRAM with IPIPE Preview modules in Continuous
+ *          (On the Fly mode)
+ *
+ * Image sensor/       ________    ____________________
+ * Yuv decoder    ---->| CCDC |--> | Previewer modules |--> SDRAM
+ *                     |______|    |___________________|
+ *
+ * case 3: Capture to SDRAM with IPIPE Preview modules  & Resizer
+ *         in continuous (On the Fly mode)
+ *
+ * Image sensor/       ________    _____________   ___________
+ * Yuv decoder    ---->| CCDC |--> | Previewer  |->| Resizer  |-> SDRAM
+ *                     |______|    |____________|  |__________|
+ *
+ * case 4: Capture to SDRAM with IPIPE Resizer
+ *         in continuous (On the Fly mode)
+ *
+ * Image sensor/       ________    ___________
+ * Yuv decoder    ---->| CCDC |--> | Resizer  |-> SDRAM
+ *                     |______|    |__________|
+ *
+ * case 5: Read from SDRAM and do preview and/or Resize
+ *         in Single shot mode
+ *
+ *                   _____________   ___________
+ *    SDRAM   ----> | Previewer  |->| Resizer  |-> SDRAM
+ *                  |____________|  |__________|
+ *
+ *
+ * Previewer allows fine tuning of the input image using different
+ * tuning modules in IPIPE. Some examples :- Noise filter, Defect
+ * pixel correction etc. It essentially operate on Bayer Raw data
+ * or YUV raw data. To do image tuning, application call,
+ * PREV_QUERY_CAP, and then call PREV_SET_PARAM to set parameter
+ * for a module.
+ *
+ *
+ * Resizer allows upscaling or downscaling a image to a desired
+ * resolution. There are 2 resizer modules. both operating on the
+ * same input image, but can have different output resolution.
+ */
+
+#ifndef _DM365_IPIPE_H
+#define _DM365_IPIPE_H
+
+#include <linux/davinci_vpfe.h>
+
+#include "dm3xx_ipipeif.h"
+
+#define CEIL(a, b)	(((a) + (b-1)) / (b))
+
+/* Used for driver storage */
+struct ipipe_otfdpc_2_0 {
+	/* 0 - disable, 1 - enable */
+	unsigned char en;
+	/* defect detection method */
+	enum ipipe_otfdpc_det_meth det_method;
+	/* Algorith used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is
+	 * used
+	 */
+	enum ipipe_otfdpc_alg alg;
+	struct prev_otfdpc_2_0 otfdpc_2_0;
+};
+
+struct ipipe_otfdpc_3_0 {
+	/* 0 - disable, 1 - enable */
+	unsigned char en;
+	/* defect detection method */
+	enum ipipe_otfdpc_det_meth det_method;
+	/* Algorith used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is
+	 * used
+	 */
+	enum ipipe_otfdpc_alg alg;
+	struct prev_otfdpc_3_0 otfdpc_3_0;
+};
+
+struct f_div_pass {
+	unsigned int o_hsz;
+	unsigned int i_hps;
+	unsigned int h_phs;
+	unsigned int src_hps;
+	unsigned int src_hsz;
+};
+
+#define IPIPE_MAX_PASSES	2
+
+struct f_div_param {
+	unsigned char en;
+	unsigned int num_passes;
+	struct f_div_pass pass[IPIPE_MAX_PASSES];
+};
+
+#define boolean_t	int
+#define ENABLE		1
+#define DISABLE		(!ENABLE)
+
+/* Resizer Rescale Parameters*/
+struct ipipe_rsz_rescale_param {
+	enum ipipe_oper_mode mode;
+	boolean_t h_flip;
+	boolean_t v_flip;
+	boolean_t cen;
+	boolean_t yen;
+	unsigned short i_vps;
+	unsigned short i_hps;
+	unsigned short o_vsz;
+	unsigned short o_hsz;
+	unsigned short v_phs_y;
+	unsigned short v_phs_c;
+	unsigned short v_dif;
+	/* resize method - Luminance */
+	enum rsz_intp_t v_typ_y;
+	/* resize method - Chrominance */
+	enum rsz_intp_t v_typ_c;
+	/* vertical lpf intensity - Luminance */
+	unsigned char v_lpf_int_y;
+	/* vertical lpf intensity - Chrominance */
+	unsigned char v_lpf_int_c;
+	unsigned short h_phs;
+	unsigned short h_dif;
+	/* resize method - Luminance */
+	enum rsz_intp_t h_typ_y;
+	/* resize method - Chrominance */
+	enum rsz_intp_t h_typ_c;
+	/* horizontal lpf intensity - Luminance */
+	unsigned char h_lpf_int_y;
+	/* horizontal lpf intensity - Chrominance */
+	unsigned char h_lpf_int_c;
+	boolean_t dscale_en;
+	enum down_scale_ave_sz h_dscale_ave_sz;
+	enum down_scale_ave_sz v_dscale_ave_sz;
+	/* store the calculated frame division parameter */
+	struct f_div_param f_div;
+};
+
+enum ipipe_rsz_rgb_t {
+	OUTPUT_32BIT,
+	OUTPUT_16BIT
+};
+
+enum ipipe_rsz_rgb_msk_t {
+	NOMASK,
+	MASKLAST2
+};
+
+/* Resizer RGB Conversion Parameters */
+struct ipipe_rsz_resize2rgb {
+	boolean_t rgb_en;
+	enum ipipe_rsz_rgb_t rgb_typ;
+	enum ipipe_rsz_rgb_msk_t rgb_msk0;
+	enum ipipe_rsz_rgb_msk_t rgb_msk1;
+	unsigned int rgb_alpha_val;
+};
+
+/* Resizer External Memory Parameters */
+struct ipipe_ext_mem_param {
+	unsigned int rsz_sdr_oft_y;
+	unsigned int rsz_sdr_ptr_s_y;
+	unsigned int rsz_sdr_ptr_e_y;
+	unsigned int rsz_sdr_oft_c;
+	unsigned int rsz_sdr_ptr_s_c;
+	unsigned int rsz_sdr_ptr_e_c;
+	/* offset to be added to buffer start when flipping for y/ycbcr */
+	unsigned int flip_ofst_y;
+	/* offset to be added to buffer start when flipping for c */
+	unsigned int flip_ofst_c;
+	/* c offset for YUV 420SP */
+	unsigned int c_offset;
+	/* User Defined Y offset for YUV 420SP or YUV420ILE data */
+	unsigned int user_y_ofst;
+	/* User Defined C offset for YUV 420SP data */
+	unsigned int user_c_ofst;
+};
+
+enum rsz_data_source {
+	IPIPE_DATA,
+	IPIPEIF_DATA
+};
+
+/* data paths */
+enum ipipe_data_paths {
+	IPIPE_RAW2YUV,
+	/* Bayer RAW input to YCbCr output */
+	IPIPE_RAW2RAW,
+	/* Bayer Raw to Bayer output */
+	IPIPE_RAW2BOX,
+	/* Bayer Raw to Boxcar output */
+	IPIPE_YUV2YUV
+	/* YUV Raw to YUV Raw output */
+};
+
+enum rsz_src_img_fmt {
+	RSZ_IMG_422,
+	RSZ_IMG_420
+};
+
+struct rsz_common_params {
+	unsigned int vps;
+	unsigned int vsz;
+	unsigned int hps;
+	unsigned int hsz;
+	/* 420 or 422 */
+	enum rsz_src_img_fmt src_img_fmt;
+	/* Y or C when src_fmt is 420, 0 - y, 1 - c */
+	unsigned char y_c;
+	/* flip raw or ycbcr */
+	unsigned char raw_flip;
+	/* IPIPE or IPIPEIF data */
+	enum rsz_data_source source;
+	enum ipipe_dpaths_bypass_t passthrough;
+	unsigned char yuv_y_min;
+	unsigned char yuv_y_max;
+	unsigned char yuv_c_min;
+	unsigned char yuv_c_max;
+	boolean_t rsz_seq_crv;
+	enum ipipe_chr_pos out_chr_pos;
+};
+
+struct ipipe_params {
+	struct ipipeif ipipeif_param;
+	enum ipipe_oper_mode ipipe_mode;
+	/* input/output datapath through IPIPE */
+	enum ipipe_data_paths ipipe_dpaths_fmt;
+	u32 ipipe_colpat;
+	/* horizontal/vertical start, horizontal/vertical size
+	 * for both IPIPE and RSZ input
+	 */
+	unsigned int ipipe_vps;
+	unsigned int ipipe_vsz;
+	unsigned int ipipe_hps;
+	unsigned int ipipe_hsz;
+
+	struct rsz_common_params rsz_common;
+	struct ipipe_rsz_rescale_param rsz_rsc_param[2];
+	struct ipipe_rsz_resize2rgb rsz2rgb[2];
+	struct ipipe_ext_mem_param ext_mem_param[2];
+	boolean_t rsz_en[2];
+};
+
+/* Struct for configuring Luminance Adjustment module */
+struct prev_lum_adj {
+	/* Brightness adjustments */
+	unsigned char brightness;
+	/* contrast adjustments */
+	unsigned char contrast;
+};
+
+#define MAX_IPIPE_RAW_YUV_PIX_FORMATS		2
+
+/* IPIPE module operation state */
+struct ipipe_oper_state {
+	/* Channel state 0 - free, 1 - busy */
+	unsigned int state;
+	/* Semaphore to protect the common hardware configuration */
+	struct mutex lock;
+	/* previewer config state */
+	unsigned int prev_config_state;
+	/* Shared configuration of the hardware */
+	struct ipipe_params *shared_config_param;
+	/* shared resource in use */
+	unsigned int resource_in_use;
+	/* resizer config state */
+	unsigned int rsz_config_state;
+	/* resizer chained with previewer */
+	unsigned int rsz_chained;
+	/* resizer output A/B is enabled? */
+	unsigned int rsz_output_enabled[2];
+	/* input mbus frame format */
+	struct v4l2_mbus_framefmt in_mbus_format;
+	/* output mbus frame format */
+	struct v4l2_mbus_framefmt out_mbus_format[2];
+	/* if_param for IPIPEIF */
+	struct vpfe_hw_if_param if_param;
+	/* Operation mode of image processor (imp)
+	 * 0 - continuous mode, 1 - single shot mode
+	 * 2 - invalid mode, 4 - not configured
+	 */
+	u32 oper_mode;
+	/* enable/disable serializer */
+	u32 en_serializer;
+	/* LUT Defect pixel correction data */
+	struct prev_lutdpc lutdpc;
+	/* LUT Defect pixel correction data */
+	struct prev_otfdpc otfdpc;
+	/* Noise filter */
+	struct prev_nf nf1;
+	struct prev_nf nf2;
+	/* Green Imbalance Correction */
+	struct prev_gic gic;
+	/* White Balance */
+	struct prev_wb wb;
+	/* CFA */
+	struct prev_cfa cfa;
+	/* RGB2RGB conversion */
+	struct prev_rgb2rgb rgb2rgb_1;
+	struct prev_rgb2rgb rgb2rgb_2;
+	/* Gamma correction */
+	struct prev_gamma gamma;
+	/* 3D LUT */
+	struct prev_3d_lut lut_3d;
+	/* Lumina Adjustment */
+	struct prev_lum_adj lum_adj;
+	/* RGB2YUV conversion */
+	struct prev_rgb2yuv rgb2yuv;
+	/* YUV 422 conversion */
+	struct prev_yuv422_conv yuv422_conv;
+	/* GBCE */
+	struct prev_gbce gbce;
+	/* Edge Enhancement */
+	struct prev_yee yee;
+	/* Chromatic Artifact Reduction, CAR */
+	struct prev_car car;
+	/* Chromatic Artifact Reduction, CAR */
+	struct prev_cgs cgs;
+	/* Tables for various tuning modules */
+	struct ipipe_lutdpc_entry ipipe_lutdpc_table[MAX_SIZE_DPC];
+	struct ipipe_3d_lut_entry ipipe_3d_lut_table[MAX_SIZE_3D_LUT];
+	unsigned short ipipe_gbce_table[MAX_SIZE_GBCE_LUT];
+	struct ipipe_gamma_entry ipipe_gamma_table_r[MAX_SIZE_GAMMA];
+	struct ipipe_gamma_entry ipipe_gamma_table_b[MAX_SIZE_GAMMA];
+	struct ipipe_gamma_entry ipipe_gamma_table_g[MAX_SIZE_GAMMA];
+	short ipipe_yee_table[MAX_SIZE_YEE_LUT];
+
+	/* Raw YUV formats */
+	u32 ipipe_raw_yuv_pix_formats[MAX_IPIPE_RAW_YUV_PIX_FORMATS];
+};
+
+#define IPIPE_COLPTN_R_Ye	0x0
+#define IPIPE_COLPTN_Gr_Cy	0x1
+#define IPIPE_COLPTN_Gb_G	0x2
+#define IPIPE_COLPTN_B_Mg	0x3
+
+#define COLPAT_EE_SHIFT		0
+#define COLPAT_EO_SHIFT		2
+#define COLPAT_OE_SHIFT		4
+#define COLPAT_OO_SHIFT		6
+
+#define ipipe_sgrbg_pattern \
+	(IPIPE_COLPTN_Gr_Cy <<  COLPAT_EE_SHIFT | \
+	IPIPE_COLPTN_R_Ye  << COLPAT_EO_SHIFT | \
+	IPIPE_COLPTN_B_Mg  << COLPAT_OE_SHIFT | \
+	IPIPE_COLPTN_Gb_G  << COLPAT_OO_SHIFT)
+
+#define ipipe_srggb_pattern \
+	(IPIPE_COLPTN_R_Ye <<  COLPAT_EE_SHIFT | \
+	IPIPE_COLPTN_Gr_Cy  << COLPAT_EO_SHIFT | \
+	IPIPE_COLPTN_Gb_G  << COLPAT_OE_SHIFT | \
+	IPIPE_COLPTN_B_Mg  << COLPAT_OO_SHIFT)
+
+struct vpfe_prev_params {
+	__u32 flag;
+	struct prev_ipipeif_config ipipeif_config;
+	struct prev_lutdpc lutdpc;
+	struct prev_otfdpc otfdpc;
+	struct prev_nf nf1;
+	struct prev_nf nf2;
+	struct prev_gic gic;
+	struct prev_wb wbal;
+	struct prev_cfa cfa;
+	struct prev_rgb2rgb rgb2rgb1;
+	struct prev_rgb2rgb rgb2rgb2;
+	struct prev_gamma gamma;
+	struct prev_3d_lut lut;
+	struct prev_rgb2yuv rgb2yuv;
+	struct prev_gbce gbce;
+	struct prev_yuv422_conv yuv422_conv;
+	struct prev_yee yee;
+	struct prev_car car;
+	struct prev_cgs cgs;
+};
+
+void ipipe_set_d2f_regs(unsigned int id, struct prev_nf *noise_filter);
+void ipipe_set_rgb2rgb_regs(unsigned int id, struct prev_rgb2rgb *rgb);
+void rsz_set_output_address(struct ipipe_params *params,
+			      int resize_no, unsigned int address);
+void ipipe_set_yuv422_conv_regs(struct prev_yuv422_conv *conv);
+void ipipe_set_lum_adj_regs(struct prev_lum_adj *lum_adj);
+void ipipe_set_rgb2ycbcr_regs(struct prev_rgb2yuv *yuv);
+void ipipe_set_lutdpc_regs(struct prev_lutdpc *lutdpc);
+void ipipe_set_otfdpc_regs(struct prev_otfdpc *otfdpc);
+void ipipe_set_3d_lut_regs(struct prev_3d_lut *lut_3d);
+void ipipe_set_gamma_regs(struct prev_gamma *gamma);
+int ipipe_hw_setup(struct ipipe_params *config);
+void ipipe_set_gbce_regs(struct prev_gbce *gbce);
+void ipipe_set_gic_regs(struct prev_gic *gic);
+void ipipe_set_cfa_regs(struct prev_cfa *cfa);
+void ipipe_set_car_regs(struct prev_car *car);
+void ipipe_set_cgs_regs(struct prev_cgs *cgs);
+void rsz_set_in_pix_format(unsigned char y_c);
+void ipipe_set_ee_regs(struct prev_yee *ee);
+void ipipe_set_wb_regs(struct prev_wb *wb);
+int rsz_enable(int rsz_id, int enable);
+void rsz_src_enable(int enable);
+
+#endif
diff --git a/drivers/media/platform/davinci/imp_hw_if.h b/drivers/media/platform/davinci/imp_hw_if.h
new file mode 100644
index 0000000..14187c9
--- /dev/null
+++ b/drivers/media/platform/davinci/imp_hw_if.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _IMP_HW_IF_H
+#define _IMP_HW_IF_H
+
+#include "vpfe_imp_common.h"
+
+struct prev_module_if {
+	unsigned int param_offset;
+	unsigned int param_size;
+	unsigned int config_offset;
+	int (*set)(struct device *dev, void *ipipe, void *param, int len);
+	int (*get)(struct device *dev, void *ipipe, void *param, int len);
+};
+
+struct imp_window {
+	/* horizontal size */
+	unsigned int width;
+	/* vertical size */
+	unsigned int height;
+	/* horizontal start position */
+	unsigned int hst;
+	/* vertical start position */
+	unsigned int vst;
+};
+
+struct imp_hw_interface {
+	/* Name of the image processor hardware */
+	char *name;
+	/* module owner */
+	struct module *owner;
+	/*
+	 * enumerate preview modules. Return interface to the
+	 * the module
+	 */
+	struct prev_module_if *(*prev_enum_modules) (struct device *dev,
+							unsigned int index);
+	/*
+	 * set operating mode for IPIPE; 1-single shot, 0-continous
+	 */
+	int (*set_oper_mode) (void *ipipe, unsigned int mode);
+	/*
+	 * reset operating mode for IPIPE;
+	 */
+	void (*reset_oper_mode) (void *ipipe);
+	/*
+	 *  get IPIPE operation mode
+	 */
+	unsigned int (*get_oper_mode) (void *ipipe);
+	/* check if hw is busy in continuous mode.
+	 * Used for checking if hw is used by ccdc driver in
+	 * continuous mode. If streaming is ON, this will be
+	 * set to busy
+	 */
+	unsigned int (*get_hw_state) (void *ipipe);
+	/* set hw state */
+	void (*set_hw_state) (void *ipipe, unsigned int state);
+	/* is resizer chained ? */
+	unsigned int (*resizer_chain) (void *ipipe);
+	/* this is used to lock shared resource */
+	void (*lock_chain) (void *ipipe);
+	/* this is used unlock shared resouce */
+	void (*unlock_chain) (void *ipipe);
+	/* Allocate a shared or exclusive config block for hardware
+	 * configuration
+	 */
+	void *(*alloc_config_block) (struct device *dev, void *ipipe);
+	/* hw serialization enabled ?? */
+	int (*serialize) (void *ipipe);
+	/* De-allocate the exclusive config block */
+	void (*dealloc_config_block) (struct device *dev, void *ipipe,
+						void *config);
+	/* Allocate a user confguration block */
+	void *(*alloc_user_config_block) (struct device *dev, void *ipipe,
+					  enum imp_log_chan_t chan_type);
+
+	/* de-allocate user config block */
+	void (*dealloc_user_config_block) (struct device *dev, void *ipipe,
+							  void *config);
+
+	/* set default configuration in the config block */
+	void (*set_user_config_defaults) (struct device *dev, void *ipipe,
+					  enum imp_log_chan_t chan_type,
+					  void *user_config);
+	/* set user configuration for preview */
+	int (*set_preview_config) (struct device *dev, void *ipipe,
+				   void *user_config, void *config);
+	/* set user configuration for resize */
+	int (*set_resizer_config) (struct device *dev, void *ipipe,
+				   int resizer_chained,
+				   void *user_config, void *config);
+	/* set previewer module params */
+	int (*set_preview_module_params) (struct device *dev, void *ipipe,
+				struct vpfe_prev_config *cfg);
+	/* get previewer module params */
+	int (*get_preview_module_params) (struct device *dev, void *ipipe,
+				struct vpfe_prev_config *cfg);
+	/* update output buffer address for a channel
+	 * if config is NULL, the shared config is assumed
+	 * this is used only in single shot mode
+	 */
+	int (*update_inbuf_address) (void *config, unsigned int address);
+	/* update output buffer address for a channel
+	 * if config is NULL, the shared config is assumed
+	 */
+	void (*update_outbuf1_address) (void *ipipe, void *config,
+						  unsigned int address);
+	/* update output buffer address for a channel
+	 * if config is NULL, the shared config is assumed
+	 */
+	void (*update_outbuf2_address) (void *ipipe, void *config,
+						  unsigned int address);
+	/* enable or disable hw */
+	void (*enable) (void *ipipe, unsigned char en, void *config);
+	/* enable or disable resizer to allow frame by frame resize in
+	 * continuous mode
+	 */
+	void (*enable_resize) (int en);
+	/* setup hardware for processing. if config is NULL,
+	 * shared channel is assumed
+	 */
+	int (*hw_setup) (struct device *dev, void *ipipe, void *config);
+	/* Get configuration state of resizer in continuous mode */
+	unsigned int (*get_resizer_config_state) (void *ipipe);
+	/* Get configuration state of previewer in continuous mode */
+	unsigned int (*get_previewer_config_state) (void *ipipe);
+	/* Get current input crop window param at the IMP */
+	int (*get_input_win) (void *ipipe, struct imp_window *win);
+	/* Set interface parameter at IPIPEIF. Only valid for DM360 */
+	int (*set_hw_if_param) (void *ipipe, struct vpfe_hw_if_param *param);
+	/* Set input mbus format */
+	void (*set_in_mbus_format) (void *ipipe,
+					struct v4l2_mbus_framefmt *format);
+	/* set output mbus format */
+	void (*set_out_mbus_format) (void *ipipe,
+					struct v4l2_mbus_framefmt *format);
+	/* set output2(resizer-B) mbus format */
+	void (*set_out2_mbus_format) (void *ipipe,
+					struct v4l2_mbus_framefmt *format);
+	/* Get output enable/disable status */
+	int (*get_output_state) (void *ipipe, unsigned char out_sel);
+	/* Get output line lenght */
+	int (*get_line_length) (void *ipipe, unsigned char out_sel);
+	/* Get the output image height */
+	int (*get_image_height) (void *ipipe, unsigned char out_sel);
+	/* Get current output window param at the IMP */
+	int (*get_output_win) (void *ipipe, struct imp_window *win);
+	/* get maximum output width of rsz-a or rsz_b*/
+	int (*get_max_output_width) (int rsz);
+	/* get maximum output height of rsa-a or rsz-b */
+	int (*get_max_output_height) (int rsz);
+	/* Enumerate pixel format for a given input format */
+	int (*enum_pix) (void *ipipe, u32 *output_pix, int index);
+	/* set control */
+	int (*prv_s_ctrl) (void *ipipe, u32 ctrl_id, s32 val);
+
+};
+
+struct imp_hw_interface *imp_get_hw_if(void);
+
+#endif
diff --git a/drivers/media/platform/davinci/vpfe_imp_common.h b/drivers/media/platform/davinci/vpfe_imp_common.h
new file mode 100644
index 0000000..89aea31
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_imp_common.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _DAVINCI_VPFE_IMP_COMMON_H
+#define _DAVINCI_VPFE_IMP_COMMON_H
+
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/davinci_vpfe.h>
+
+#define MAX_CHANNELS		2
+#define MAX_BUFFERS		6
+#define MAX_PRIORITY		5
+#define MIN_PRIORITY		0
+#define DEFAULT_PRIORITY	3
+#define ENABLED			1
+#define DISABLED		0
+#define CHANNEL_BUSY		1
+#define CHANNEL_FREE		0
+
+#define IMP_MODE_CONTINUOUS	0
+#define IMP_MODE_SINGLE_SHOT	1
+#define IMP_MODE_INVALID	2
+#define IMP_MODE_NOT_CONFIGURED	4
+
+/* driver configured by application */
+#define STATE_CONFIGURED	1
+/* driver not configured by application */
+#define STATE_NOT_CONFIGURED	0
+
+enum imp_log_chan_t {
+	IMP_PREVIEWER,
+	IMP_RESIZER,
+	IMP_HISTOGRAM,
+	IMP_BOXCAR
+};
+
+/* IMP channel structure */
+struct imp_logical_channel {
+	/* channel type */
+	enum imp_log_chan_t type;
+	/* channel configuration for this logial channel */
+	void *config;
+	/* Saves the user configuration */
+	void *user_config;
+	/* configure State of the channel */
+	unsigned int config_state;
+};
+
+/* Where hardware channel is shared, this is used for serialisation */
+struct imp_serializer {
+	/* channel config array for serialization */
+	struct imp_logical_channel *channel_config[MAX_CHANNELS];
+	/* number of elements in the array */
+	int array_count;
+	/* Semaphore for above config array */
+	struct mutex array_sem;
+	/* Completion semaphore when hw channel is common
+	 * Use device specific completion semaphore when request is serialized
+	 */
+	struct completion sem_isr;
+};
+
+#endif
diff --git a/include/linux/davinci_vpfe.h b/include/linux/davinci_vpfe.h
new file mode 100644
index 0000000..35a5dd9
--- /dev/null
+++ b/include/linux/davinci_vpfe.h
@@ -0,0 +1,929 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _DAVINCI_VPFE_H
+#define _DAVINCI_VPFE_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include "dm3xx_ipipeif.h"
+
+/**********************************************************************
+      Previewer API Structures
+**********************************************************************/
+
+/* Preview module configurations */
+
+/* IPIEIF configuration */
+#define PREV_IPIPEIF		(1 << 0)
+/* LUT based Defect Pixel Correction */
+#define PREV_LUTDPC		(1 << 1)
+/* On the fly (OTF) Defect Pixel Correction */
+#define PREV_OTFDPC		(1 << 2)
+/* Noise Filter - 1 */
+#define PREV_NF1		(1 << 3)
+/* Noise Filter - 2 */
+#define PREV_NF2		(1 << 4)
+/* White Balance.  Also a control ID */
+#define PREV_WB			(1 << 5)
+/* 1st RGB to RBG Blend module */
+#define PREV_RGB2RGB_1		(1 << 6)
+/* 2nd RGB to RBG Blend module */
+#define PREV_RGB2RGB_2		(1 << 7)
+/* Gamma Correction */
+#define PREV_GAMMA		(1 << 8)
+/* 3D LUT color conversion */
+#define PREV_3D_LUT		(1 << 9)
+/* RGB to YCbCr module */
+#define PREV_RGB2YUV		(1 << 10)
+/* YUV 422 conversion module */
+#define PREV_YUV422_CONV	(1 << 11)
+/* Edge Enhancement */
+#define PREV_YEE		(1 << 12)
+/* Green Imbalance Correction */
+#define PREV_GIC		(1 << 13)
+/* CFA Interpolation */
+#define PREV_CFA		(1 << 14)
+/* Chroma Artifact Reduction */
+#define PREV_CAR		(1 << 15)
+/* Chroma Gain Suppression */
+#define PREV_CGS		(1 << 16)
+/* Global brighness and contrast control */
+#define PREV_GBCE		(1 << 17)
+/* Last module ID */
+#define PREV_MAX_MODULES	18
+
+struct ipipe_float_u16 {
+	unsigned short integer;
+	unsigned short decimal;
+};
+
+struct ipipe_float_s16 {
+	short integer;
+	unsigned short decimal;
+};
+
+struct ipipe_float_u8 {
+	unsigned char integer;
+	unsigned char decimal;
+};
+
+/* Copy method selection for vertical correction
+ *  Used when ipipe_dfc_corr_meth is PREV_DPC_CTORB_AFTER_HINT
+ */
+enum ipipe_dpc_corr_meth {
+	/* replace by black or white dot specified by repl_white */
+	IPIPE_DPC_REPL_BY_DOT = 0,
+	/* Copy from left */
+	IPIPE_DPC_CL,
+	/* Copy from right */
+	IPIPE_DPC_CR,
+	/* Horizontal interpolation */
+	IPIPE_DPC_H_INTP,
+	/* Vertical interpolation */
+	IPIPE_DPC_V_INTP,
+	/* Copy from top  */
+	IPIPE_DPC_CT,
+	/* Copy from bottom */
+	IPIPE_DPC_CB,
+	/* 2D interpolation */
+	IPIPE_DPC_2D_INTP,
+};
+
+struct ipipe_lutdpc_entry {
+	/* Horizontal position */
+	unsigned short horz_pos;
+	/* vertical position */
+	unsigned short vert_pos;
+	enum ipipe_dpc_corr_meth method;
+};
+
+#define MAX_SIZE_DPC 256
+/* Struct for configuring DPC module */
+struct prev_lutdpc {
+	/* 0 - disable, 1 - enable */
+	unsigned char en;
+	/* 0 - replace with black dot, 1 - white dot when correction
+	 * method is  IPIPE_DFC_REPL_BY_DOT=0,
+	 */
+	unsigned char repl_white;
+	/* number of entries in the correction table. Currently only
+	 * support upto 256 entries. infinite mode is not supported
+	 */
+	unsigned short dpc_size;
+	struct ipipe_lutdpc_entry table[MAX_SIZE_DPC];
+};
+
+enum ipipe_otfdpc_det_meth {
+	IPIPE_DPC_OTF_MIN_MAX,
+	IPIPE_DPC_OTF_MIN_MAX2
+};
+
+struct ipipe_otfdpc_thr {
+	unsigned short r;
+	unsigned short gr;
+	unsigned short gb;
+	unsigned short b;
+};
+
+enum ipipe_otfdpc_alg {
+	IPIPE_OTFDPC_2_0,
+	IPIPE_OTFDPC_3_0
+};
+
+struct prev_otfdpc_2_0 {
+	/* defect detection threshold for MIN_MAX2 method  (DPC 2.0 alg) */
+	struct ipipe_otfdpc_thr det_thr;
+	/* defect correction threshold for MIN_MAX2 method (DPC 2.0 alg) or
+	 * maximum value for MIN_MAX method
+	 */
+	struct ipipe_otfdpc_thr corr_thr;
+};
+
+struct prev_otfdpc_3_0 {
+	/* DPC3.0 activity adj shf. activity = (max2-min2) >> (6 -shf)
+	 */
+	unsigned char act_adj_shf;
+	/* DPC3.0 detection threshold, THR */
+	unsigned short det_thr;
+	/* DPC3.0 detection threshold slope, SLP */
+	unsigned short det_slp;
+	/* DPC3.0 detection threshold min, MIN */
+	unsigned short det_thr_min;
+	/* DPC3.0 detection threshold max, MAX */
+	unsigned short det_thr_max;
+	/* DPC3.0 correction threshold, THR */
+	unsigned short corr_thr;
+	/* DPC3.0 correction threshold slope, SLP */
+	unsigned short corr_slp;
+	/* DPC3.0 correction threshold min, MIN */
+	unsigned short corr_thr_min;
+	/* DPC3.0 correction threshold max, MAX */
+	unsigned short corr_thr_max;
+};
+
+struct prev_otfdpc {
+	/* 0 - disable, 1 - enable */
+	unsigned char en;
+	/* defect detection method */
+	enum ipipe_otfdpc_det_meth det_method;
+	/* Algorith used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is
+	 * used
+	 */
+	enum ipipe_otfdpc_alg alg;
+	union {
+		/* if alg is IPIPE_OTFDPC_2_0 */
+		struct prev_otfdpc_2_0 dpc_2_0;
+		/* if alg is IPIPE_OTFDPC_3_0 */
+		struct prev_otfdpc_3_0 dpc_3_0;
+	} alg_cfg;
+};
+
+/* Threshold values table size */
+#define IPIPE_NF_THR_TABLE_SIZE 8
+/* Intensity values table size */
+#define IPIPE_NF_STR_TABLE_SIZE 8
+
+/* NF, sampling method for green pixels */
+enum ipipe_nf_sampl_meth {
+	/* Same as R or B */
+	IPIPE_NF_BOX,
+	/* Diamond mode */
+	IPIPE_NF_DIAMOND
+};
+
+/* Struct for configuring NF module */
+struct prev_nf {
+	/* 0 - disable, 1 - enable */
+	unsigned char en;
+	/* Sampling method for green pixels */
+	enum ipipe_nf_sampl_meth gr_sample_meth;
+	/* Down shift value in LUT reference address
+	 */
+	unsigned char shft_val;
+	/* Spread value in NF algorithm
+	 */
+	unsigned char spread_val;
+	/* Apply LSC gain to threshold. Enable this only if
+	 * LSC is enabled in ISIF
+	 */
+	unsigned char apply_lsc_gain;
+	/* Threshold values table */
+	unsigned short thr[IPIPE_NF_THR_TABLE_SIZE];
+	/* intensity values table */
+	unsigned char str[IPIPE_NF_STR_TABLE_SIZE];
+	/* Edge detection minimum threshold */
+	unsigned short edge_det_min_thr;
+	/* Edge detection maximum threshold */
+	unsigned short edge_det_max_thr;
+};
+
+enum ipipe_gic_alg {
+	IPIPE_GIC_ALG_CONST_GAIN,
+	IPIPE_GIC_ALG_ADAPT_GAIN
+};
+
+enum ipipe_gic_thr_sel {
+	IPIPE_GIC_THR_REG,
+	IPIPE_GIC_THR_NF
+};
+
+enum ipipe_gic_wt_fn_type {
+	/* Use difference as index */
+	IPIPE_GIC_WT_FN_TYP_DIF,
+	/* Use weight function as index */
+	IPIPE_GIC_WT_FN_TYP_HP_VAL
+};
+
+/* structure for Green Imbalance Correction */
+struct prev_gic {
+	/* 0 - disable, 1 - enable */
+	unsigned char en;
+	/* 0 - Constant gain , 1 - Adaptive gain algorithm */
+	enum ipipe_gic_alg gic_alg;
+	/* GIC gain or weight. Used for Constant gain and Adaptive algorithms
+	 */
+	unsigned short gain;
+	/* Threshold selection. GIC register values or NF2 thr table */
+	enum ipipe_gic_thr_sel thr_sel;
+	/* thr1. Used when thr_sel is  IPIPE_GIC_THR_REG */
+	unsigned short thr;
+	/* this value is used for thr2-thr1, thr3-thr2 or
+	 * thr4-thr3 when wt_fn_type is index. Otherwise it
+	 * is the
+	 */
+	unsigned short slope;
+	/* Apply LSC gain to threshold. Enable this only if
+	 * LSC is enabled in ISIF & thr_sel is IPIPE_GIC_THR_REG
+	 */
+	unsigned char apply_lsc_gain;
+	/* Multiply Nf2 threshold by this gain. Use this when thr_sel
+	 * is IPIPE_GIC_THR_NF
+	 */
+	struct ipipe_float_u8 nf2_thr_gain;
+	/* Weight function uses difference as index or high pass value.
+	 * Used for adaptive gain algorithm
+	 */
+	enum ipipe_gic_wt_fn_type wt_fn_type;
+};
+
+/* Struct for configuring WB module */
+struct prev_wb {
+	/* Offset (S12) for R */
+	short ofst_r;
+	/* Offset (S12) for Gr */
+	short ofst_gr;
+	/* Offset (S12) for Gb */
+	short ofst_gb;
+	/* Offset (S12) for B */
+	short ofst_b;
+	/* Gain (U13Q9) for Red */
+	struct ipipe_float_u16 gain_r;
+	/* Gain (U13Q9) for Gr */
+	struct ipipe_float_u16 gain_gr;
+	/* Gain (U13Q9) for Gb */
+	struct ipipe_float_u16 gain_gb;
+	/* Gain (U13Q9) for Blue */
+	struct ipipe_float_u16 gain_b;
+};
+
+enum ipipe_cfa_alg {
+	/* Algorithm is 2DirAC */
+	IPIPE_CFA_ALG_2DIRAC,
+	/* Algorithm is 2DirAC + Digital Antialiasing (DAA) */
+	IPIPE_CFA_ALG_2DIRAC_DAA,
+	/* Algorithm is DAA */
+	IPIPE_CFA_ALG_DAA
+};
+
+/* Structure for CFA Interpolation */
+struct prev_cfa {
+	/* 2DirAC or 2DirAC + DAA */
+	enum ipipe_cfa_alg alg;
+	/* 2Dir CFA HP value Low Threshold */
+	unsigned short hpf_thr_2dir;
+	/* 2Dir CFA HP value slope */
+	unsigned short hpf_slp_2dir;
+	/* 2Dir CFA HP mix threshold */
+	unsigned short hp_mix_thr_2dir;
+	/* 2Dir CFA HP mix slope */
+	unsigned short hp_mix_slope_2dir;
+	/* 2Dir Direction threshold */
+	unsigned short dir_thr_2dir;
+	/* 2Dir Direction slope */
+	unsigned short dir_slope_2dir;
+	/* 2Dir NonDirectional Weight */
+	unsigned short nd_wt_2dir;
+	/* DAA Mono Hue Fraction */
+	unsigned short hue_fract_daa;
+	/* DAA Mono Edge threshold */
+	unsigned short edge_thr_daa;
+	/* DAA Mono threshold minimum */
+	unsigned short thr_min_daa;
+	/* DAA Mono threshold slope */
+	unsigned short thr_slope_daa;
+	/* DAA Mono slope minimum */
+	unsigned short slope_min_daa;
+	/* DAA Mono slope slope */
+	unsigned short slope_slope_daa;
+	/* DAA Mono LP wight */
+	unsigned short lp_wt_daa;
+};
+
+/* Struct for configuring RGB2RGB blending module */
+struct prev_rgb2rgb {
+	/* Matrix coefficient for RR S12Q8 for ID = 1 and S11Q8 for ID = 2 */
+	struct ipipe_float_s16 coef_rr;
+	/* Matrix coefficient for GR S12Q8/S11Q8 */
+	struct ipipe_float_s16 coef_gr;
+	/* Matrix coefficient for BR S12Q8/S11Q8 */
+	struct ipipe_float_s16 coef_br;
+	/* Matrix coefficient for RG S12Q8/S11Q8 */
+	struct ipipe_float_s16 coef_rg;
+	/* Matrix coefficient for GG S12Q8/S11Q8 */
+	struct ipipe_float_s16 coef_gg;
+	/* Matrix coefficient for BG S12Q8/S11Q8 */
+	struct ipipe_float_s16 coef_bg;
+	/* Matrix coefficient for RB S12Q8/S11Q8 */
+	struct ipipe_float_s16 coef_rb;
+	/* Matrix coefficient for GB S12Q8/S11Q8 */
+	struct ipipe_float_s16 coef_gb;
+	/* Matrix coefficient for BB S12Q8/S11Q8 */
+	struct ipipe_float_s16 coef_bb;
+	/* Output offset for R S13/S11 */
+	int out_ofst_r;
+	/* Output offset for G S13/S11 */
+	int out_ofst_g;
+	/* Output offset for B S13/S11 */
+	int out_ofst_b;
+};
+
+#define MAX_SIZE_GAMMA 512
+
+enum ipipe_gamma_tbl_size {
+	IPIPE_GAMMA_TBL_SZ_64 = 64,
+	IPIPE_GAMMA_TBL_SZ_128 = 128,
+	IPIPE_GAMMA_TBL_SZ_256 = 256,
+	IPIPE_GAMMA_TBL_SZ_512 = 512
+};
+
+enum ipipe_gamma_tbl_sel {
+	IPIPE_GAMMA_TBL_RAM,
+	IPIPE_GAMMA_TBL_ROM
+};
+
+struct ipipe_gamma_entry {
+	/* 10 bit slope */
+	short slope;
+	/* 10 bit offset */
+	unsigned short offset;
+};
+
+/* Struct for configuring Gamma correction module */
+struct prev_gamma {
+	/* 0 - Enable Gamma correction for Red
+	 * 1 - bypass Gamma correction. Data is divided by 16
+	 */
+	unsigned char bypass_r;
+	/* 0 - Enable Gamma correction for Blue
+	 * 1 - bypass Gamma correction. Data is divided by 16
+	 */
+	unsigned char bypass_b;
+	/* 0 - Enable Gamma correction for Green
+	 * 1 - bypass Gamma correction. Data is divided by 16
+	 */
+	unsigned char bypass_g;
+	/* PREV_GAMMA_TBL_RAM or PREV_GAMMA_TBL_ROM */
+	enum ipipe_gamma_tbl_sel tbl_sel;
+	/* Table size for RAM gamma table.
+	 */
+	enum ipipe_gamma_tbl_size tbl_size;
+	/* R table */
+	struct ipipe_gamma_entry table_r[MAX_SIZE_GAMMA];
+	/* Blue table */
+	struct ipipe_gamma_entry table_b[MAX_SIZE_GAMMA];
+	/* Green table */
+	struct ipipe_gamma_entry table_g[MAX_SIZE_GAMMA];
+};
+
+#define MAX_SIZE_3D_LUT		729
+
+struct ipipe_3d_lut_entry {
+	/* 10 bit entry for red */
+	unsigned short r;
+	/* 10 bit entry for green */
+	unsigned short g;
+	/* 10 bit entry for blue */
+	unsigned short b;
+};
+
+/* structure for 3D-LUT */
+struct prev_3d_lut {
+	/* enable/disable 3D lut */
+	unsigned char en;
+	/* 3D - LUT table entry */
+	struct ipipe_3d_lut_entry table[MAX_SIZE_3D_LUT];
+};
+
+/* Struct for configuring rgb2ycbcr module */
+struct prev_rgb2yuv {
+	/* Matrix coefficient for RY S12Q8 */
+	struct ipipe_float_s16 coef_ry;
+	/* Matrix coefficient for GY S12Q8 */
+	struct ipipe_float_s16 coef_gy;
+	/* Matrix coefficient for BY S12Q8 */
+	struct ipipe_float_s16 coef_by;
+	/* Matrix coefficient for RCb S12Q8 */
+	struct ipipe_float_s16 coef_rcb;
+	/* Matrix coefficient for GCb S12Q8 */
+	struct ipipe_float_s16 coef_gcb;
+	/* Matrix coefficient for BCb S12Q8 */
+	struct ipipe_float_s16 coef_bcb;
+	/* Matrix coefficient for RCr S12Q8 */
+	struct ipipe_float_s16 coef_rcr;
+	/* Matrix coefficient for GCr S12Q8 */
+	struct ipipe_float_s16 coef_gcr;
+	/* Matrix coefficient for BCr S12Q8 */
+	struct ipipe_float_s16 coef_bcr;
+	/* Output offset for R S11 */
+	int out_ofst_y;
+	/* Output offset for Cb S11 */
+	int out_ofst_cb;
+	/* Output offset for Cr S11 */
+	int out_ofst_cr;
+};
+
+enum ipipe_gbce_type {
+	IPIPE_GBCE_Y_VAL_TBL,
+	IPIPE_GBCE_GAIN_TBL
+};
+
+#define MAX_SIZE_GBCE_LUT 1024
+
+/* structure for Global brighness and Contrast */
+struct prev_gbce {
+	/* enable/disable GBCE */
+	unsigned char en;
+	/* Y - value table or Gain table */
+	enum ipipe_gbce_type type;
+	/* ptr to LUT for GBCE with 1024 entries */
+	unsigned short table[MAX_SIZE_GBCE_LUT];
+};
+
+/* Chrominance position. Applicable only for YCbCr input
+ * Applied after edge enhancement
+ */
+enum ipipe_chr_pos {
+	/* Cositing, same position with luminance */
+	IPIPE_YUV422_CHR_POS_COSITE,
+	/* Centering, In the middle of luminance */
+	IPIPE_YUV422_CHR_POS_CENTRE
+};
+
+/* Struct for configuring yuv422 conversion module */
+struct prev_yuv422_conv {
+	/* Max Chrominance value */
+	unsigned char en_chrom_lpf;
+	/* 1 - enable LPF for chrminance, 0 - disable */
+	enum ipipe_chr_pos chrom_pos;
+};
+
+#define MAX_SIZE_YEE_LUT 1024
+
+enum ipipe_yee_merge_meth {
+	IPIPE_YEE_ABS_MAX,
+	IPIPE_YEE_EE_ES
+};
+
+/* Struct for configuring YUV Edge Enhancement module */
+struct prev_yee {
+	/* 1 - enable enhancement, 0 - disable */
+	unsigned char en;
+	/* enable/disable halo reduction in edge sharpner */
+	unsigned char en_halo_red;
+	/* Merge method between Edge Enhancer and Edge sharpner */
+	enum ipipe_yee_merge_meth merge_meth;
+	/* HPF Shift length */
+	unsigned char hpf_shft;
+	/* HPF Coefficient 00, S10 */
+	short hpf_coef_00;
+	/* HPF Coefficient 01, S10 */
+	short hpf_coef_01;
+	/* HPF Coefficient 02, S10 */
+	short hpf_coef_02;
+	/* HPF Coefficient 10, S10 */
+	short hpf_coef_10;
+	/* HPF Coefficient 11, S10 */
+	short hpf_coef_11;
+	/* HPF Coefficient 12, S10 */
+	short hpf_coef_12;
+	/* HPF Coefficient 20, S10 */
+	short hpf_coef_20;
+	/* HPF Coefficient 21, S10 */
+	short hpf_coef_21;
+	/* HPF Coefficient 22, S10 */
+	short hpf_coef_22;
+	/* Lower threshold before refering to LUT */
+	unsigned short yee_thr;
+	/* Edge sharpener Gain */
+	unsigned short es_gain;
+	/* Edge sharpener lowe threshold */
+	unsigned short es_thr1;
+	/* Edge sharpener upper threshold */
+	unsigned short es_thr2;
+	/* Edge sharpener gain on gradient */
+	unsigned short es_gain_grad;
+	/* Edge sharpener offset on gradient */
+	unsigned short es_ofst_grad;
+	/* Ptr to EE table. Must have 1024 entries */
+	short table[MAX_SIZE_YEE_LUT];
+};
+
+enum ipipe_car_meth {
+	/* Chromatic Gain Control */
+	IPIPE_CAR_CHR_GAIN_CTRL,
+	/* Dynamic switching between CHR_GAIN_CTRL
+	 * and MED_FLTR
+	 */
+	IPIPE_CAR_DYN_SWITCH,
+	/* Median Filter */
+	IPIPE_CAR_MED_FLTR
+};
+
+enum ipipe_car_hpf_type {
+	IPIPE_CAR_HPF_Y,
+	IPIPE_CAR_HPF_H,
+	IPIPE_CAR_HPF_V,
+	IPIPE_CAR_HPF_2D,
+	/* 2D HPF from YUV Edge Enhancement */
+	IPIPE_CAR_HPF_2D_YEE
+};
+
+struct ipipe_car_gain {
+	/* csup_gain */
+	unsigned char gain;
+	/* csup_shf. */
+	unsigned char shft;
+	/* gain minimum */
+	unsigned short gain_min;
+};
+
+/* Structure for Chromatic Artifact Reduction */
+struct prev_car {
+	/* enable/disable */
+	unsigned char en;
+	/* Gain control or Dynamic switching */
+	enum ipipe_car_meth meth;
+	/* Gain1 function configuration for Gain control */
+	struct ipipe_car_gain gain1;
+	/* Gain2 function configuration for Gain control */
+	struct ipipe_car_gain gain2;
+	/* HPF type used for CAR */
+	enum ipipe_car_hpf_type hpf;
+	/* csup_thr: HPF threshold for Gain control */
+	unsigned char hpf_thr;
+	/* Down shift value for hpf. 2 bits */
+	unsigned char hpf_shft;
+	/* switch limit for median filter */
+	unsigned char sw0;
+	/* switch coefficient for Gain control */
+	unsigned char sw1;
+};
+
+/* structure for Chromatic Gain Suppression */
+struct prev_cgs {
+	/* enable/disable */
+	unsigned char en;
+	/* gain1 bright side threshold */
+	unsigned char h_thr;
+	/* gain1 bright side slope */
+	unsigned char h_slope;
+	/* gain1 down shift value for bright side */
+	unsigned char h_shft;
+	/* gain1 bright side minimum gain */
+	unsigned char h_min;
+};
+
+enum ipipe_dpaths_bypass_t {
+	IPIPE_BYPASS_OFF,
+	IPIPE_BYPASS_ON
+};
+
+/* Max pixels allowed in the input. If above this either decimation
+ * or frame division mode to be enabled
+ */
+#define IPIPE_MAX_INPUT_WIDTH 2600
+
+/* Max pixels in resizer - A output. In downscale
+ * (DSCALE) mode, image quality is better, but has lesser
+ * maximum width allowed
+ */
+#define IPIPE_MAX_OUTPUT1_WIDTH_NORMAL 2176
+#define IPIPE_MAX_OUTPUT1_WIDTH_DSCALE 1088
+
+/* Max pixels in resizer - B output. In downscale
+ * (DSCALE) mode, image quality is better, but has lesser
+ * maximum width allowed
+ */
+#define IPIPE_MAX_OUTPUT2_WIDTH_NORMAL 1088
+#define IPIPE_MAX_OUTPUT2_WIDTH_DSCALE 544
+
+struct prev_ipipef_input_spec {
+	/* line length. This will allow application to set a
+	 * different line length than that calculated based on
+	 * width. Set it to zero, if not used,
+	 */
+	unsigned int line_length;
+	/* vertical start position of the image
+	 * data to IPIPE
+	 */
+	unsigned int vst;
+	/* horizontal start position of the image
+	 * data to IPIPE
+	 */
+	unsigned int hst;
+	/* Global frame HD rate */
+	unsigned int ppln;
+	/* Global frame VD rate */
+	unsigned int lpfr;
+	/* clock divide to bring down the pixel clock */
+	struct ipipeif_5_1_clkdiv clk_div;
+	/* When input image width is greater that line buffer
+	 * size, use this to do resize using frame division. The
+	 * frame is divided into two vertical slices and resize
+	 * is performed on each slice. Use either frame division
+	 *  mode or decimation, NOT both
+	 */
+	unsigned char frame_div_mode_en;
+};
+
+struct prev_ipipeif_config {
+	/* used for single shot mode */
+	struct prev_ipipef_input_spec input_spec;
+	/* Bypass image processing. RAW -> RAW */
+	enum ipipe_dpaths_bypass_t bypass;
+	/* Enable decimation 1 - enable, 0 - disable
+	 * This is used when image width is greater than
+	 * ipipe line buffer size
+	 */
+	enum ipipeif_decimation dec_en;
+	/* used when en_dec = 1. Resize ratio for decimation
+	 * when frame size is  greater than what hw can handle.
+	 * 16 to 112. IPIPE input width is calculated as follows.
+	 * width = image_width * 16/ipipeif_rsz. For example
+	 * if image_width is 1920 and user want to scale it down
+	 * to 1280, use ipipeif_rsz = 24. 1920*16/24 = 1280
+	 */
+	unsigned char rsz;
+	/* Enable/Disable avg filter at IPIPEIF.
+	 * 1 - enable, 0 - disable
+	 */
+	unsigned char avg_filter_en;
+	/* clipped to this value at the ipipeif */
+	unsigned short clip;
+	/* Align HSync and VSync to rsz_start */
+	unsigned char align_sync;
+	/* ipipeif resize start position */
+	unsigned int rsz_start;
+	/* Simple defect pixel correction based on a threshold value */
+	struct ipipeif_dpc dpc;
+};
+
+/**
+ * struct vpfe_prev_config - Preview engine configuration (user)
+ * @ipipeif_config: Pointer to structure for ipipeif configuration.
+ * @flag: Specifies which ISP Preview functions should be enabled.
+ * @lutdpc: Pointer to luma enhancement structure.
+ * @otfdpc: Pointer to structure for defect correction.
+ * @nf1: Pointer to structure for Noise Filter.
+ * @nf2: Pointer to structure for Noise Filter.
+ * @gic: Pointer to structure for Green Imbalance.
+ * @wbal: Pointer to structure for White Balance.
+ * @cfa: Pointer to structure containing the CFA interpolation.
+ * @rgb2rgb1: Pointer to structure for RGB to RGB Blending.
+ * @rgb2rgb2: Pointer to structure for RGB to RGB Blending.
+ * @gamma: Pointer to gamma structure.
+ * @lut: Pointer to structure for 3D LUT.
+ * @rgb2yuv: Pointer to structure for RGB-YCbCr conversion.
+ * @gbce: Pointer to structure for Global Brightness,Contrast Control.
+ * @yuv422_conv: Pointer to structure for YUV 422 conversion.
+ * @yee: Pointer to structure for Edge Enhancer.
+ * @car: Pointer to structure for Chromatic Artifact Reduction.
+ * @cgs: Pointer to structure for Chromatic Gain Suppression.
+ */
+struct vpfe_prev_config {
+	__u32 flag;
+	struct prev_ipipeif_config __user *ipipeif_config;
+	struct prev_lutdpc __user *lutdpc;
+	struct prev_otfdpc __user *otfdpc;
+	struct prev_nf __user *nf1;
+	struct prev_nf __user *nf2;
+	struct prev_gic __user *gic;
+	struct prev_wb __user *wbal;
+	struct prev_cfa __user *cfa;
+	struct prev_rgb2rgb __user *rgb2rgb1;
+	struct prev_rgb2rgb __user *rgb2rgb2;
+	struct prev_gamma __user *gamma;
+	struct prev_3d_lut __user *lut;
+	struct prev_rgb2yuv __user *rgb2yuv;
+	struct prev_gbce __user *gbce;
+	struct prev_yuv422_conv __user *yuv422_conv;
+	struct prev_yee __user *yee;
+	struct prev_car __user *car;
+	struct prev_cgs __user *cgs;
+};
+
+/*******************************************************************
+**  Resizer API structures
+*******************************************************************/
+/* Interpolation types used for horizontal rescale */
+enum rsz_intp_t {
+	RSZ_INTP_CUBIC,
+	RSZ_INTP_LINEAR
+};
+
+/* Horizontal LPF intensity selection */
+enum rsz_h_lpf_lse_t {
+	RSZ_H_LPF_LSE_INTERN,
+	RSZ_H_LPF_LSE_USER_VAL
+};
+
+enum down_scale_ave_sz {
+	IPIPE_DWN_SCALE_1_OVER_2,
+	IPIPE_DWN_SCALE_1_OVER_4,
+	IPIPE_DWN_SCALE_1_OVER_8,
+	IPIPE_DWN_SCALE_1_OVER_16,
+	IPIPE_DWN_SCALE_1_OVER_32,
+	IPIPE_DWN_SCALE_1_OVER_64,
+	IPIPE_DWN_SCALE_1_OVER_128,
+	IPIPE_DWN_SCALE_1_OVER_256
+};
+
+/* Structure for configuring resizer in single shot mode.
+ * This structure is used when operation mode of the
+ * resizer is single shot. The related IOCTL is
+ * RSZ_S_CONFIG & RSZ_G_CONFIG. When chained, data to
+ * resizer comes from previewer. When not chained, only
+ * UYVY data input is allowed for resizer operation.
+ */
+
+struct rsz_ipipeif_input_spec {
+	/* line length. This will allow application to set a
+	 * different line length than that calculated based on
+	 * width. Set it to zero, if not used,
+	 */
+	unsigned int line_length;
+	/* vertical start position of the image
+	 * data to IPIPE
+	 */
+	unsigned int vst;
+	/* horizontal start position of the image
+	 * data to IPIPE
+	 */
+	unsigned int hst;
+	/* Global frame HD rate */
+	unsigned int ppln;
+	/* Global frame VD rate */
+	unsigned int lpfr;
+	/* clock divide to bring down the pixel clock */
+	struct ipipeif_5_1_clkdiv clk_div;
+	/* Enable decimation 1 - enable, 0 - disable.
+	 * Used when input image width is greater than ipipe
+	 * line buffer size, this is enabled to do resize
+	 * at the input of the IPIPE to clip the size
+	 */
+	enum ipipeif_decimation dec_en;
+	/* used when en_dec = 1. Resize ratio for decimation
+	 * when frame size is  greater than what hw can handle.
+	 * 16 to 112. IPIPE input width is calculated as follows.
+	 * width = image_width * 16/ipipeif_rsz. For example
+	 * if image_width is 1920 and user want to scale it down
+	 * to 1280, use ipipeif_rsz = 24. 1920*16/24 = 1280
+	 */
+	unsigned char rsz;
+	/* When input image width is greater that line buffer
+	 * size, use this to do resize using frame division. The
+	 * frame is divided into two vertical slices and resize
+	 * is performed on each slice
+	 */
+	unsigned char frame_div_mode_en;
+	/* Enable/Disable avg filter at IPIPEIF.
+	 * 1 - enable, 0 - disable
+	 */
+	unsigned char avg_filter_en;
+	/* Align HSync and VSync to rsz_start */
+	unsigned char align_sync;
+	/* ipipeif resize start position */
+	unsigned int rsz_start;
+};
+
+struct rsz_output_spec {
+	/* enable horizontal flip */
+	unsigned char h_flip;
+	/* enable vertical flip */
+	unsigned char v_flip;
+	/* line start offset for y. */
+	unsigned int vst_y;
+	/* line start offset for c. Only for 420 */
+	unsigned int vst_c;
+	/* vertical rescale interpolation type, YCbCr or Luminance */
+	enum rsz_intp_t v_typ_y;
+	/* vertical rescale interpolation type for Chrominance */
+	enum rsz_intp_t v_typ_c;
+	/* vertical lpf intensity - Luminance */
+	unsigned char v_lpf_int_y;
+	/* vertical lpf intensity - Chrominance */
+	unsigned char v_lpf_int_c;
+	/* horizontal rescale interpolation types, YCbCr or Luminance  */
+	enum rsz_intp_t h_typ_y;
+	/* horizontal rescale interpolation types, Chrominance */
+	enum rsz_intp_t h_typ_c;
+	/* horizontal lpf intensity - Luminance */
+	unsigned char h_lpf_int_y;
+	/* horizontal lpf intensity - Chrominance */
+	unsigned char h_lpf_int_c;
+	/* Use down scale mode for scale down */
+	unsigned char en_down_scale;
+	/* if downscale, set the downscale more average size for horizontal
+	 * direction. Used only if output width and height is less than
+	 * input sizes
+	 */
+	enum down_scale_ave_sz h_dscale_ave_sz;
+	/* if downscale, set the downscale more average size for vertical
+	 * direction. Used only if output width and height is less than
+	 * input sizes
+	 */
+	enum down_scale_ave_sz v_dscale_ave_sz;
+	/* Y offset. If set, the offset would be added to the base address
+	 */
+	unsigned int user_y_ofst;
+	/* C offset. If set, the offset would be added to the base address
+	 */
+	unsigned int user_c_ofst;
+};
+
+struct rsz_config {
+	/* input spec of the image data (UYVY). non-chained
+	 * mode. Only valid when not chained. For chained
+	 * operation, previewer settings are used. Mainly
+	 * used for single shot.
+	 */
+	struct rsz_ipipeif_input_spec input;
+	/* output spec of the image data coming out of resizer - 0(UYVY).
+	 */
+	struct rsz_output_spec output1;
+	/* output spec of the image data coming out of resizer - 1(UYVY).
+	 */
+	struct rsz_output_spec output2;
+	/* 0 , chroma sample at odd pixel, 1 - even pixel */
+	unsigned char chroma_sample_even;
+	unsigned char yuv_y_min;
+	unsigned char yuv_y_max;
+	unsigned char yuv_c_min;
+	unsigned char yuv_c_max;
+	enum ipipe_chr_pos out_chr_pos;
+};
+
+/* Structure for VIDIOC_VPFE_RSZ_[S/G]_CONFIG IOCTLs */
+struct vpfe_rsz_config {
+	struct rsz_config *config;
+};
+
+/*
+ * Private IOCTL
+ *
+ * VIDIOC_VPFE_PRV_S_CONFIG: Set preview engine configuration
+ * VIDIOC_VPFE_PRV_G_CONFIG: Get preview engine configuration
+ * VIDIOC_VPFE_RSZ_S_CONFIG: Set resizer engine configuration
+ * VIDIOC_VPFE_RSZ_G_CONFIG: Get resizer engine configuration
+ */
+
+#define VIDIOC_VPFE_PRV_S_CONFIG \
+	_IOWR('P', BASE_VIDIOC_PRIVATE + 1, struct vpfe_prev_config)
+#define VIDIOC_VPFE_PRV_G_CONFIG \
+	_IOWR('P', BASE_VIDIOC_PRIVATE + 2, struct vpfe_prev_config)
+#define VIDIOC_VPFE_RSZ_S_CONFIG \
+	_IOWR('R', BASE_VIDIOC_PRIVATE + 3, struct vpfe_rsz_config)
+#define VIDIOC_VPFE_RSZ_G_CONFIG \
+	_IOWR('R', BASE_VIDIOC_PRIVATE + 4, struct vpfe_rsz_config)
+
+#endif
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 04/14] davinci: vpfe: add support for CCDC hardware for dm365
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (2 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 03/14] davinci: vpfe: add IPIPE support for media controller driver Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 05/14] davinci: vpfe: add ccdc driver with media controller interface Prabhakar Lad
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

add support for ccdc on dm365 SoC. ccdc is responsible for
capturing video data- both raw bayer through sync seperate
signals and through BT656/1120 interfaces. This driver implements
the hardware functionality. Mainly- setting of hardware, validation
of parameters, and isr configuration.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/dm365_ccdc.c      | 1424 ++++++++++++++++++++++
 drivers/media/platform/davinci/dm365_ccdc.h      |  137 +++
 drivers/media/platform/davinci/dm365_ccdc_regs.h |  314 +++++
 include/linux/dm365_ccdc.h                       |  592 +++++++++
 4 files changed, 2467 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/platform/davinci/dm365_ccdc.c
 create mode 100644 drivers/media/platform/davinci/dm365_ccdc.h
 create mode 100644 drivers/media/platform/davinci/dm365_ccdc_regs.h
 create mode 100644 include/linux/dm365_ccdc.h

diff --git a/drivers/media/platform/davinci/dm365_ccdc.c b/drivers/media/platform/davinci/dm365_ccdc.c
new file mode 100644
index 0000000..eee2d58
--- /dev/null
+++ b/drivers/media/platform/davinci/dm365_ccdc.c
@@ -0,0 +1,1424 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+
+#include <mach/mux.h>
+
+#include <media/davinci/vpfe_types.h>
+#include <media/davinci/vpss.h>
+
+#include "dm365_ccdc.h"
+#include "ccdc_hw_device.h"
+#include "dm365_ccdc_regs.h"
+
+static struct device *dev;
+
+/* Defauts for module configuation paramaters */
+static struct ccdc_config_params_raw ccdc_config_defaults = {
+	.linearize = {
+		.corr_shft = CCDC_NO_SHIFT,
+		.scale_fact = {1, 0},
+	},
+	.culling = {
+		.hcpat_odd = 0xff,
+		.hcpat_even = 0xff,
+		.vcpat = 0xff
+	},
+};
+
+static struct ccdc_gain_values ccdc_gain_params;
+static unsigned char ccdc_test_pat_gen;
+
+/* ISIF operation configuration */
+struct ccdc_oper_config {
+	enum v4l2_mbus_pixelcode if_type;
+	struct ccdc_ycbcr_config ycbcr;
+	struct ccdc_params_raw bayer;
+	enum ccdc_data_pack data_pack;
+	void *__iomem base_addr;
+	void *__iomem linear_tbl0_addr;
+	void *__iomem linear_tbl1_addr;
+};
+
+static struct ccdc_oper_config ccdc_cfg = {
+	.ycbcr = {
+		.v4l2_pix_fmt = V4L2_PIX_FMT_UYVY,
+		.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+		.frm_fmt = CCDC_FRMFMT_INTERLACED,
+		.win = CCDC_WIN_NTSC,
+		.fid_pol = VPFE_PINPOL_POSITIVE,
+		.vd_pol = VPFE_PINPOL_POSITIVE,
+		.hd_pol = VPFE_PINPOL_POSITIVE,
+		.pix_order = CCDC_PIXORDER_CBYCRY,
+		.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
+	},
+	.bayer = {
+		.v4l2_pix_fmt = V4L2_PIX_FMT_SGRBG10ALAW8,
+		.pix_fmt = CCDC_PIXFMT_RAW,
+		.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+		.win = CCDC_WIN_VGA,
+		.fid_pol = VPFE_PINPOL_POSITIVE,
+		.vd_pol = VPFE_PINPOL_POSITIVE,
+		.hd_pol = VPFE_PINPOL_POSITIVE,
+		.gain = {
+			.r_ye = {1, 0},
+			.gr_cy = {1, 0},
+			.gb_g = {1, 0},
+			.b_mg = {1, 0},
+		},
+		.cfa_pat = CCDC_CFA_PAT_MOSAIC,
+		.data_msb = CCDC_BIT_MSB_11,
+	},
+	.data_pack = CCDC_DATA_PACK8,
+};
+
+/* Raw Bayer formats */
+static u32 ccdc_raw_bayer_pix_formats[] = { V4L2_PIX_FMT_SGRBG10ALAW8,
+						V4L2_PIX_FMT_SGRBG10DPCM8,
+						V4L2_PIX_FMT_SBGGR16 };
+
+/* Raw YUV formats */
+static u32 ccdc_raw_yuv_pix_formats[] = { V4L2_PIX_FMT_UYVY,
+					      V4L2_PIX_FMT_YUYV };
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+	return readl(ccdc_cfg.base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+	writel(val, ccdc_cfg.base_addr + offset);
+}
+
+static inline u32 ccdc_merge(u32 mask, u32 val, u32 offset)
+{
+	u32 new_val = (regr(offset) & ~mask) | (val & mask);
+
+	regw(new_val, offset);
+
+	return new_val;
+}
+
+static inline void regw_lin_tbl(u32 val, u32 offset, int i)
+{
+	if (!i)
+		writel(val, ccdc_cfg.linear_tbl0_addr + offset);
+	else
+		writel(val, ccdc_cfg.linear_tbl1_addr + offset);
+}
+
+static void ccdc_disable_all_modules(void)
+{
+	/* disable BC */
+	regw(0, CLAMPCFG);
+	/* disable vdfc */
+	regw(0, DFCCTL);
+	/* disable CSC */
+	regw(0, CSCCTL);
+	/* disable linearization */
+	regw(0, LINCFG0);
+	/* disable other modules here as they are supported */
+}
+
+static void ccdc_enable(int en)
+{
+	if (!en) {
+		/* Before disable isif, disable all ISIF modules */
+		ccdc_disable_all_modules();
+		/**
+		 * wait for next VD. Assume lowest scan rate is 12 Hz. So
+		 * 100 msec delay is good enough
+		 */
+	}
+	msleep(100);
+	ccdc_merge(CCDC_SYNCEN_VDHDEN_MASK, en, SYNCEN);
+}
+
+static void ccdc_enable_output_to_sdram(int en)
+{
+	ccdc_merge(CCDC_SYNCEN_WEN_MASK, en << CCDC_SYNCEN_WEN_SHIFT, SYNCEN);
+}
+
+static void ccdc_config_culling(struct ccdc_cul *cul)
+{
+	u32 val;
+
+	/* Horizontal pattern */
+	val = cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT;
+	val |= cul->hcpat_odd;
+	regw(val, CULH);
+
+	/* vertical pattern */
+	regw(cul->vcpat, CULV);
+
+	/* LPF */
+	ccdc_merge((CCDC_LPF_MASK << CCDC_LPF_SHIFT),
+		   (cul->en_lpf << CCDC_LPF_SHIFT), MODESET);
+}
+
+static void ccdc_config_gain_offset(void)
+{
+	struct ccdc_gain_offsets_adj *gain_off_ptr =
+		&ccdc_cfg.bayer.config_params.gain_offset;
+	u32 val;
+
+	val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) |
+	((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) |
+	((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) |
+	((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) |
+	((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) |
+	((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT);
+
+	ccdc_merge(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
+
+	regw(ccdc_gain_params.cr_gain, CRGAIN);
+	regw(ccdc_gain_params.cgr_gain, CGRGAIN);
+	regw(ccdc_gain_params.cgb_gain, CGBGAIN);
+	regw(ccdc_gain_params.cb_gain, CBGAIN);
+	regw((ccdc_gain_params.offset & OFFSET_MASK), COFSTA);
+
+}
+
+static void ccdc_restore_defaults(void)
+{
+	enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
+	int i;
+
+	memcpy(&ccdc_cfg.bayer.config_params, &ccdc_config_defaults,
+			sizeof(struct ccdc_config_params_raw));
+
+	dev_dbg(dev, "ccdc_restore_defaults...\n");
+	/* Enable clock to ISIF, IPIPEIF and BL */
+	vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
+	vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
+	vpss_enable_clock(VPSS_BL_CLOCK, 1);
+
+	/* set all registers to default value */
+	for (i = 0; i <= 0x1f8; i += 4)
+		regw(0, i);
+	/* no culling support */
+	regw(0xffff, CULH);
+	regw(0xff, CULV);
+
+	/* Set default offset and gain */
+	ccdc_config_gain_offset();
+	vpss_select_ccdc_source(source);
+}
+
+static int ccdc_open(struct device *device)
+{
+	dev = device;
+	ccdc_restore_defaults();
+	return 0;
+}
+
+/* This function will configure the window size to be capture in CCDC reg */
+static void ccdc_setwin(struct v4l2_rect *image_win,
+			enum ccdc_frmfmt frm_fmt, int ppc, int mode)
+{
+	int horz_nr_pixels;
+	int vert_nr_lines;
+	int horz_start;
+	int vert_start;
+	int mid_img;
+
+	dev_dbg(dev, "ccdc_setwin...\n");
+	/**
+	 * ppc - per pixel count. indicates how many pixels per cell
+	 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+	 * raw capture this is 1
+	 */
+	horz_start = image_win->left << (ppc - 1);
+	horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
+
+	/* Writing the horizontal info into the registers */
+	regw(horz_start & START_PX_HOR_MASK, SPH);
+	regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
+	vert_start = image_win->top;
+
+	if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+		vert_nr_lines = (image_win->height >> 1) - 1;
+		vert_start >>= 1;
+		/* To account for VD since line 0 doesn't have any data */
+		vert_start += 1;
+	} else {
+		/* To account for VD since line 0 doesn't have any data */
+		vert_start += 1;
+		vert_nr_lines = image_win->height - 1;
+		/* configure VDINT0 and VDINT1 */
+		mid_img = vert_start + (image_win->height / 2);
+		regw(mid_img, VDINT1);
+	}
+
+	if (!mode)
+		regw(0, VDINT0);
+	else
+		regw(vert_nr_lines, VDINT0);
+	regw(vert_start & START_VER_ONE_MASK, SLV0);
+	regw(vert_start & START_VER_TWO_MASK, SLV1);
+	regw(vert_nr_lines & NUM_LINES_VER, LNV);
+}
+
+static void ccdc_config_bclamp(struct ccdc_black_clamp *bc)
+{
+	u32 val;
+
+	/**
+	 * DC Offset is always added to image data irrespective of bc enable
+	 * status
+	 */
+	val = bc->dc_offset & CCDC_BC_DCOFFSET_MASK;
+	regw(val, CLDCOFST);
+
+	if (!bc->en)
+		return;
+
+	val = (bc->bc_mode_color & CCDC_BC_MODE_COLOR_MASK) <<
+		CCDC_BC_MODE_COLOR_SHIFT;
+
+	/* Enable BC and horizontal clamp caculation paramaters */
+	val = val | 1 | ((bc->horz.mode & CCDC_HORZ_BC_MODE_MASK) <<
+	CCDC_HORZ_BC_MODE_SHIFT);
+
+	regw(val, CLAMPCFG);
+
+	if (bc->horz.mode != CCDC_HORZ_BC_DISABLE) {
+		/**
+		  * Window count for calculation
+		  * Base window selection
+		  * pixel limit
+		  * Horizontal size of window
+		  * vertical size of the window
+		  * Horizontal start position of the window
+		  * Vertical start position of the window
+		  */
+		val = (bc->horz.win_count_calc & CCDC_HORZ_BC_WIN_COUNT_MASK) |
+			((bc->horz.base_win_sel_calc & 1) <<
+			CCDC_HORZ_BC_WIN_SEL_SHIFT) |
+			((bc->horz.clamp_pix_limit & 1) <<
+			CCDC_HORZ_BC_PIX_LIMIT_SHIFT) |
+			((bc->horz.win_h_sz_calc &
+			CCDC_HORZ_BC_WIN_H_SIZE_MASK) <<
+			CCDC_HORZ_BC_WIN_H_SIZE_SHIFT) |
+			((bc->horz.win_v_sz_calc &
+			CCDC_HORZ_BC_WIN_V_SIZE_MASK) <<
+			CCDC_HORZ_BC_WIN_V_SIZE_SHIFT);
+
+		regw(val, CLHWIN0);
+
+		val = bc->horz.win_start_h_calc & CCDC_HORZ_BC_WIN_START_H_MASK;
+		regw(val, CLHWIN1);
+
+		val = bc->horz.win_start_v_calc & CCDC_HORZ_BC_WIN_START_V_MASK;
+		regw(val, CLHWIN2);
+	}
+
+	/* vertical clamp caculation paramaters */
+
+	/* OB H Valid */
+	val = bc->vert.ob_h_sz_calc & CCDC_VERT_BC_OB_H_SZ_MASK;
+
+	/* Reset clamp value sel for previous line */
+	val |= (bc->vert.reset_val_sel & CCDC_VERT_BC_RST_VAL_SEL_MASK) <<
+				CCDC_VERT_BC_RST_VAL_SEL_SHIFT;
+
+	/* Line average coefficient */
+	val |= bc->vert.line_ave_coef << CCDC_VERT_BC_LINE_AVE_COEF_SHIFT;
+	regw(val, CLVWIN0);
+
+	/* Configured reset value */
+	if (bc->vert.reset_val_sel == CCDC_VERT_BC_USE_CONFIG_CLAMP_VAL) {
+		val = bc->vert.reset_clamp_val & CCDC_VERT_BC_RST_VAL_MASK;
+		regw(val, CLVRV);
+	}
+
+	/* Optical Black horizontal start position */
+	val = bc->vert.ob_start_h & CCDC_VERT_BC_OB_START_HORZ_MASK;
+	regw(val, CLVWIN1);
+
+	/* Optical Black vertical start position */
+	val = bc->vert.ob_start_v & CCDC_VERT_BC_OB_START_VERT_MASK;
+	regw(val, CLVWIN2);
+
+	val = bc->vert.ob_v_sz_calc & CCDC_VERT_BC_OB_VERT_SZ_MASK;
+	regw(val, CLVWIN3);
+
+	/* Vertical start position for BC subtraction */
+	val = bc->vert_start_sub & CCDC_BC_VERT_START_SUB_V_MASK;
+	regw(val, CLSV);
+}
+
+static void ccdc_config_linearization(struct ccdc_linearize *linearize)
+{
+	u32 val;
+	u32 i;
+
+	if (!linearize->en) {
+		regw(0, LINCFG0);
+		return;
+	}
+
+	/* shift value for correction */
+	val = (linearize->corr_shft & CCDC_LIN_CORRSFT_MASK) <<
+					CCDC_LIN_CORRSFT_SHIFT;
+	/* enable */
+	val |= 1;
+	regw(val, LINCFG0);
+
+	/* Scale factor */
+	val = (linearize->scale_fact.integer & 1) <<
+				    CCDC_LIN_SCALE_FACT_INTEG_SHIFT;
+	val |= linearize->scale_fact.decimal & CCDC_LIN_SCALE_FACT_DECIMAL_MASK;
+	regw(val, LINCFG1);
+
+	for (i = 0; i < CCDC_LINEAR_TAB_SIZE; i++) {
+		val = linearize->table[i] & CCDC_LIN_ENTRY_MASK;
+		if (i%2)
+			regw_lin_tbl(val, ((i >> 1) << 2), 1);
+		else
+			regw_lin_tbl(val, ((i >> 1) << 2), 0);
+	}
+}
+
+static void ccdc_config_dfc(struct ccdc_dfc *vdfc)
+{
+#define DFC_WRITE_WAIT_COUNT	1000
+	u32 count = DFC_WRITE_WAIT_COUNT;
+	u32 val;
+	int i;
+
+	if (!vdfc->en)
+		return;
+
+	/* Correction mode */
+	val = (vdfc->corr_mode & CCDC_VDFC_CORR_MOD_MASK) <<
+					CCDC_VDFC_CORR_MOD_SHIFT;
+
+	/* Correct whole line or partial */
+	if (vdfc->corr_whole_line)
+		val |= 1 << CCDC_VDFC_CORR_WHOLE_LN_SHIFT;
+
+	/* level shift value */
+	val |= (vdfc->def_level_shift & CCDC_VDFC_LEVEL_SHFT_MASK) <<
+		CCDC_VDFC_LEVEL_SHFT_SHIFT;
+
+	regw(val, DFCCTL);
+
+	/* Defect saturation level */
+	val = vdfc->def_sat_level & CCDC_VDFC_SAT_LEVEL_MASK;
+	regw(val, VDFSATLV);
+
+	regw(vdfc->table[0].pos_vert & CCDC_VDFC_POS_MASK, DFCMEM0);
+	regw(vdfc->table[0].pos_horz & CCDC_VDFC_POS_MASK, DFCMEM1);
+	if (vdfc->corr_mode == CCDC_VDFC_NORMAL ||
+	    vdfc->corr_mode == CCDC_VDFC_HORZ_INTERPOL_IF_SAT) {
+		regw(vdfc->table[0].level_at_pos, DFCMEM2);
+		regw(vdfc->table[0].level_up_pixels, DFCMEM3);
+		regw(vdfc->table[0].level_low_pixels, DFCMEM4);
+	}
+
+	val = regr(DFCMEMCTL);
+	/* set DFCMARST and set DFCMWR */
+	val |= 1 << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
+	val |= 1;
+	regw(val, DFCMEMCTL);
+
+	while (count && (regr(DFCMEMCTL) & 0x01))
+		count--;
+
+	val = regr(DFCMEMCTL);
+	if (!count) {
+		dev_dbg(dev, "defect table write timeout !!\n");
+		return;
+	}
+
+	for (i = 1; i < vdfc->num_vdefects; i++) {
+		regw(vdfc->table[i].pos_vert & CCDC_VDFC_POS_MASK, DFCMEM0);
+		regw(vdfc->table[i].pos_horz & CCDC_VDFC_POS_MASK, DFCMEM1);
+		if (vdfc->corr_mode == CCDC_VDFC_NORMAL ||
+		    vdfc->corr_mode == CCDC_VDFC_HORZ_INTERPOL_IF_SAT) {
+			regw(vdfc->table[i].level_at_pos, DFCMEM2);
+			regw(vdfc->table[i].level_up_pixels, DFCMEM3);
+			regw(vdfc->table[i].level_low_pixels, DFCMEM4);
+		}
+		val = regr(DFCMEMCTL);
+		/* clear DFCMARST and set DFCMWR */
+		val &= ~(1 << CCDC_DFCMEMCTL_DFCMARST_SHIFT);
+		val |= 1;
+		regw(val, DFCMEMCTL);
+
+		count = DFC_WRITE_WAIT_COUNT;
+		while (count && (regr(DFCMEMCTL) & 0x01))
+			count--;
+
+		val = regr(DFCMEMCTL);
+		if (!count) {
+			dev_err(dev, "defect table write timeout !!\n");
+			return;
+		}
+	}
+	if (vdfc->num_vdefects < CCDC_VDFC_TABLE_SIZE) {
+		/* Extra cycle needed */
+		regw(0, DFCMEM0);
+		regw(0x1FFF, DFCMEM1);
+		val = 1;
+		regw(val, DFCMEMCTL);
+	}
+
+	/* enable VDFC */
+	ccdc_merge((1 << CCDC_VDFC_EN_SHIFT), (1 << CCDC_VDFC_EN_SHIFT),
+		   DFCCTL);
+
+	ccdc_merge((1 << CCDC_VDFC_EN_SHIFT), (0 << CCDC_VDFC_EN_SHIFT),
+		   DFCCTL);
+
+	regw(0x6, DFCMEMCTL);
+	for (i = 0 ; i < vdfc->num_vdefects; i++) {
+		count = DFC_WRITE_WAIT_COUNT;
+		while (count && (regr(DFCMEMCTL) & 0x2))
+			count--;
+
+		val = regr(DFCMEMCTL);
+		if (!count) {
+			dev_err(dev, "defect table write timeout !!\n");
+			return;
+		}
+
+		val = regr(DFCMEM0) | regr(DFCMEM1) | regr(DFCMEM2) |
+			regr(DFCMEM3) | regr(DFCMEM4);
+		regw(0x2, DFCMEMCTL);
+	}
+}
+
+static void ccdc_config_csc(struct ccdc_df_csc *df_csc)
+{
+	u32 val1;
+	u32 val2;
+	u32 i;
+
+	if (!df_csc->csc.en) {
+		regw(0, CSCCTL);
+		return;
+	}
+
+	/* initialize all bits to 0 */
+	val1 = 0;
+
+	for (i = 0; i < CCDC_CSC_NUM_COEFF; i++) {
+		if ((i % 2) == 0) {
+			/* CSCM - LSB */
+			val1 = ((df_csc->csc.coeff[i].integer &
+				CCDC_CSC_COEF_INTEG_MASK) <<
+				CCDC_CSC_COEF_INTEG_SHIFT) |
+				((df_csc->csc.coeff[i].decimal &
+				CCDC_CSC_COEF_DECIMAL_MASK));
+		} else {
+
+			/* CSCM - MSB */
+			val2 = ((df_csc->csc.coeff[i].integer &
+				CCDC_CSC_COEF_INTEG_MASK) <<
+				CCDC_CSC_COEF_INTEG_SHIFT) |
+				((df_csc->csc.coeff[i].decimal &
+				CCDC_CSC_COEF_DECIMAL_MASK));
+			val2 <<= CCDC_CSCM_MSB_SHIFT;
+			val2 |= val1;
+			regw(val2, (CSCM0 + ((i-1) << 1)));
+		}
+	}
+
+	/* program the active area */
+	regw(df_csc->start_pix & CCDC_DF_CSC_SPH_MASK, FMTSPH);
+	/**
+	 * one extra pixel as required for CSC. Actually number of
+	 * pixel - 1 should be configured in this register. So we
+	 * need to subtract 1 before writing to FMTSPH, but we will
+	 * not do this since csc requires one extra pixel
+	 */
+	regw((df_csc->num_pixels) & CCDC_DF_CSC_SPH_MASK, FMTLNH);
+	regw(df_csc->start_line & CCDC_DF_CSC_SPH_MASK, FMTSLV);
+	/**
+	 * one extra line as required for CSC. See reason documented for
+	 * num_pixels
+	 */
+	regw((df_csc->num_lines) & CCDC_DF_CSC_SPH_MASK, FMTLNV);
+
+	/* Enable CSC */
+	regw(1, CSCCTL);
+}
+
+static int ccdc_config_raw(int mode)
+{
+	struct ccdc_params_raw *params = &ccdc_cfg.bayer;
+	struct ccdc_config_params_raw *module_params =
+		&ccdc_cfg.bayer.config_params;
+	struct vpss_pg_frame_size frame_size;
+	struct vpss_sync_pol sync;
+	u32 val;
+
+	dev_dbg(dev, "ccdc_config_raw..\n");
+
+	/* In case of user has set BT656IF earlier, it should be reset
+	   when configuring for raw input.
+	 */
+	regw(0, REC656IF);
+
+	/* Configure CCDCFG register */
+
+	/**
+	 * Set CCD Not to swap input since input is RAW data
+	 * Set FID detection function to Latch at V-Sync
+	 * Set WENLOG - ccdc valid area
+	 * Set TRGSEL
+	 * Set EXTRG
+	 * Packed to 8 or 16 bits
+	 */
+
+	val = CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
+		CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
+		CCDC_CCDCFG_EXTRG_DISABLE | (ccdc_cfg.data_pack &
+		CCDC_DATA_PACK_MASK);
+
+	dev_dbg(dev, "Writing 0x%x to ...CCDCFG\n", val);
+	regw(val, CCDCFG);
+
+	/**
+	 * Configure the vertical sync polarity(MODESET.VDPOL)
+	 * Configure the horizontal sync polarity (MODESET.HDPOL)
+	 * Configure frame id polarity (MODESET.FLDPOL)
+	 * Configure data polarity
+	 * Configure External WEN Selection
+	 * Configure frame format(progressive or interlace)
+	 * Configure pixel format (Input mode)
+	 * Configure the data shift
+	 */
+
+	val = CCDC_VDHDOUT_INPUT | ((params->vd_pol & CCDC_VD_POL_MASK) <<
+	      CCDC_VD_POL_SHIFT) | ((params->hd_pol & CCDC_HD_POL_MASK) <<
+	      CCDC_HD_POL_SHIFT) | ((params->fid_pol & CCDC_FID_POL_MASK) <<
+	      CCDC_FID_POL_SHIFT) | ((CCDC_DATAPOL_NORMAL &
+	      CCDC_DATAPOL_MASK) << CCDC_DATAPOL_SHIFT) | ((CCDC_EXWEN_DISABLE &
+	      CCDC_EXWEN_MASK) << CCDC_EXWEN_SHIFT) | ((params->frm_fmt &
+	      CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | ((params->pix_fmt &
+	      CCDC_INPUT_MASK) << CCDC_INPUT_SHIFT);
+
+	/* currently only V4L2_MBUS_FMT_SGRBG12_1X12 is
+	 * supported. shift appropriately depending on
+	 * different MBUS fmt's added
+	 */
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12)
+		val |= ((CCDC_NO_SHIFT &
+			CCDC_DATASFT_MASK) << CCDC_DATASFT_SHIFT);
+
+	regw(val, MODESET);
+	dev_dbg(dev, "Writing 0x%x to MODESET...\n", val);
+
+	/**
+	 * Configure GAMMAWD register
+	 * CFA pattern setting
+	 */
+	val = (params->cfa_pat & CCDC_GAMMAWD_CFA_MASK) <<
+		CCDC_GAMMAWD_CFA_SHIFT;
+
+	/* Gamma msb */
+	if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10ALAW8)
+		val = val | CCDC_ALAW_ENABLE;
+
+	val = val | ((params->data_msb & CCDC_ALAW_GAMA_WD_MASK) <<
+			CCDC_ALAW_GAMA_WD_SHIFT);
+
+	regw(val, CGAMMAWD);
+
+	/* Configure DPCM compression settings */
+	if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) {
+		val =  1 << CCDC_DPCM_EN_SHIFT;
+		val |= (module_params->pred &
+			CCDC_DPCM_PREDICTOR_MASK) << CCDC_DPCM_PREDICTOR_SHIFT;
+	}
+	regw(val, MISC);
+	/* Configure Gain & Offset */
+	ccdc_config_gain_offset();
+	/* Configure Color pattern */
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12)
+		val = ccdc_sgrbg_pattern;
+	else
+		/* default set to rggb */
+		val = ccdc_srggb_pattern;
+
+	regw(val, CCOLP);
+	dev_dbg(dev, "Writing %x to CCOLP ...\n", val);
+
+	/* Configure HSIZE register  */
+	val = (params->horz_flip_en & CCDC_HSIZE_FLIP_MASK) <<
+			  CCDC_HSIZE_FLIP_SHIFT;
+
+	/* calculate line offset in 32 bytes based on pack value */
+	if (ccdc_cfg.data_pack == CCDC_PACK_8BIT)
+		val |= ((params->win.width + 31) >> 5) & CCDC_LINEOFST_MASK;
+	else if (ccdc_cfg.data_pack == CCDC_PACK_12BIT)
+		val |= ((((params->win.width + (params->win.width >> 2)) +
+			31) >> 5) & CCDC_LINEOFST_MASK);
+	else
+		val |= (((params->win.width * 2) + 31) >> 5) &
+			CCDC_LINEOFST_MASK;
+	regw(val, HSIZE);
+
+	/* Configure SDOFST register  */
+	if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+		if (params->image_invert_en) {
+			/* For interlace inverse mode */
+			regw(0x4B6D, SDOFST);
+			dev_dbg(dev, "Writing 0x4B6D to SDOFST...\n");
+		} else {
+			/* For interlace non inverse mode */
+			regw(0x0B6D, SDOFST);
+			dev_dbg(dev, "Writing 0x0B6D to SDOFST...\n");
+		}
+	} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+		if (params->image_invert_en) {
+			/* For progessive inverse mode */
+			regw(0x4000, SDOFST);
+			dev_dbg(dev, "Writing 0x4000 to SDOFST...\n");
+		} else {
+			/* For progessive non inverse mode */
+			regw(0x0000, SDOFST);
+			dev_dbg(dev, "Writing 0x0000 to SDOFST...\n");
+		}
+	}
+
+	/* Configure video window */
+	ccdc_setwin(&params->win, params->frm_fmt, 1, mode);
+
+	/* Configure Black Clamp */
+	ccdc_config_bclamp(&module_params->bclamp);
+
+	/* Configure Vertical Defection Pixel Correction */
+	ccdc_config_dfc(&module_params->dfc);
+
+	if (!module_params->df_csc.df_or_csc)
+		/* Configure Color Space Conversion */
+		ccdc_config_csc(&module_params->df_csc);
+
+	ccdc_config_linearization(&module_params->linearize);
+
+	/* Configure Culling */
+	ccdc_config_culling(&module_params->culling);
+
+	/* Configure Horizontal and vertical offsets(DFC,LSC,Gain) */
+	val = module_params->horz_offset & CCDC_DATA_H_OFFSET_MASK;
+	regw(val, DATAHOFST);
+
+	val = module_params->vert_offset & CCDC_DATA_V_OFFSET_MASK;
+	regw(val, DATAVOFST);
+
+	/* Setup test pattern if enabled */
+	if (ccdc_test_pat_gen) {
+		/* Use the HD/VD pol settings from user */
+		sync.ccdpg_hdpol = params->hd_pol & CCDC_HD_POL_MASK;
+		sync.ccdpg_vdpol = params->vd_pol & CCDC_VD_POL_MASK;
+
+		vpss_set_sync_pol(sync);
+
+		frame_size.hlpfr = ccdc_cfg.bayer.win.width;
+		frame_size.pplen = ccdc_cfg.bayer.win.height;
+		vpss_set_pg_frame_size(frame_size);
+		vpss_select_ccdc_source(VPSS_PGLPBK);
+	}
+
+	return 0;
+}
+
+static int ccdc_validate_df_csc_params(struct ccdc_df_csc *df_csc)
+{
+	struct ccdc_color_space_conv *csc;
+	int err = -EINVAL;
+	int csc_df_en;
+	int i;
+
+	if (!df_csc->df_or_csc) {
+		/* csc configuration */
+		csc = &df_csc->csc;
+		if (csc->en) {
+			csc_df_en = 1;
+			for (i = 0; i < CCDC_CSC_NUM_COEFF; i++) {
+				if (csc->coeff[i].integer >
+					CCDC_CSC_COEF_INTEG_MASK ||
+				    csc->coeff[i].decimal >
+					CCDC_CSC_COEF_DECIMAL_MASK) {
+					dev_dbg(dev,
+						"invalid CSC coefficients\n");
+					return err;
+				}
+			}
+		}
+	}
+
+	if (df_csc->start_pix > CCDC_DF_CSC_SPH_MASK) {
+		dev_dbg(dev, "invalid df_csc start pix value\n");
+		return err;
+	}
+	if (df_csc->num_pixels > CCDC_DF_NUMPIX) {
+		dev_dbg(dev, "invalid df_csc num pixels value\n");
+		return err;
+	}
+	if (df_csc->start_line > CCDC_DF_CSC_LNH_MASK) {
+		dev_dbg(dev, "invalid df_csc start_line value\n");
+		return err;
+	}
+	if (df_csc->num_lines > CCDC_DF_NUMLINES) {
+		dev_dbg(dev, "invalid df_csc num_lines value\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int ccdc_validate_dfc_params(struct ccdc_dfc *dfc)
+{
+	int err = -EINVAL;
+	int i;
+
+	if (!dfc->en)
+		return 0;
+
+	if (dfc->corr_whole_line > 1) {
+		dev_dbg(dev, "invalid corr_whole_line value\n");
+		return err;
+	}
+
+	if (dfc->def_level_shift > 4) {
+		dev_dbg(dev, "invalid def_level_shift value\n");
+		return err;
+	}
+
+	if (dfc->def_sat_level > 4095) {
+		dev_dbg(dev, "invalid def_sat_level value\n");
+		return err;
+	}
+
+	if (!dfc->num_vdefects || dfc->num_vdefects > 8) {
+		dev_dbg(dev, "invalid num_vdefects value\n");
+		return err;
+	}
+
+	for (i = 0; i < CCDC_VDFC_TABLE_SIZE; i++) {
+		if (dfc->table[i].pos_vert > 0x1fff) {
+			dev_dbg(dev, "invalid pos_vert value\n");
+			return err;
+		}
+
+		if (dfc->table[i].pos_horz > 0x1fff) {
+			dev_dbg(dev, "invalid pos_horz value\n");
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static int ccdc_validate_bclamp_params(struct ccdc_black_clamp *bclamp)
+{
+	int err = -EINVAL;
+
+	if (bclamp->dc_offset > 0x1fff) {
+		dev_dbg(dev, "invalid bclamp dc_offset value\n");
+		return err;
+	}
+
+	if (!bclamp->en)
+		return 0;
+
+	if (bclamp->horz.clamp_pix_limit > 1) {
+		dev_dbg(dev,
+			"invalid bclamp horz clamp_pix_limit value\n");
+		return err;
+	}
+
+	if (bclamp->horz.win_count_calc < 1 ||
+			bclamp->horz.win_count_calc > 32) {
+		dev_dbg(dev, "invalid bclamp horz win_count_calc value\n");
+		return err;
+	}
+
+	if (bclamp->horz.win_start_h_calc > 0x1fff) {
+		dev_dbg(dev, "invalid bclamp win_start_v_calc value\n");
+		return err;
+	}
+
+	if (bclamp->horz.win_start_v_calc > 0x1fff) {
+		dev_dbg(dev, "invalid bclamp win_start_v_calc value\n");
+		return err;
+	}
+
+	if (bclamp->vert.reset_clamp_val > 0xfff) {
+		dev_dbg(dev, "invalid bclamp reset_clamp_val value\n");
+		return err;
+	}
+
+	if (bclamp->vert.ob_v_sz_calc > 0x1fff) {
+		dev_dbg(dev, "invalid bclamp ob_v_sz_calc value\n");
+		return err;
+	}
+
+	if (bclamp->vert.ob_start_h > 0x1fff) {
+		dev_dbg(dev, "invalid bclamp ob_start_h value\n");
+		return err;
+	}
+
+	if (bclamp->vert.ob_start_v > 0x1fff) {
+		dev_dbg(dev, "invalid bclamp ob_start_h value\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int ccdc_validate_gain_ofst_params(struct ccdc_gain_offsets_adj
+					  *gain_offset)
+{
+	int err = -EINVAL;
+
+	if ((gain_offset->offset_sdram_en || gain_offset->offset_ipipe_en ||
+		gain_offset->offset_h3a_en) &&
+		ccdc_gain_params.offset > 0xfff) {
+		dev_dbg(dev, "Invalid  gain b_mg\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int
+validate_ccdc_config_params_raw(struct ccdc_config_params_raw *params)
+{
+	int err;
+
+	err = ccdc_validate_df_csc_params(&params->df_csc);
+	if (err)
+		goto exit;
+	err = ccdc_validate_dfc_params(&params->dfc);
+	if (err)
+		goto exit;
+	err = ccdc_validate_bclamp_params(&params->bclamp);
+	if (err)
+		goto exit;
+	err = ccdc_validate_gain_ofst_params(&params->gain_offset);
+exit:
+	return err;
+}
+
+static int ccdc_set_buftype(enum ccdc_buftype buf_type)
+{
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12)
+		ccdc_cfg.bayer.buf_type = buf_type;
+	else
+		ccdc_cfg.ycbcr.buf_type = buf_type;
+
+	return 0;
+}
+
+static enum ccdc_buftype ccdc_get_buftype(void)
+{
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12)
+		return ccdc_cfg.bayer.buf_type;
+
+	return ccdc_cfg.ycbcr.buf_type;
+}
+
+static int ccdc_enum_pix(u32 *pix, int i)
+{
+	int ret = -EINVAL;
+
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12) {
+		if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
+			*pix = ccdc_raw_bayer_pix_formats[i];
+			ret = 0;
+		}
+	} else {
+		if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
+			*pix = ccdc_raw_yuv_pix_formats[i];
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+static int ccdc_set_pixel_format(unsigned int pixfmt)
+{
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12) {
+		if (pixfmt == V4L2_PIX_FMT_SBGGR16)
+			ccdc_cfg.data_pack = CCDC_PACK_16BIT;
+		else if ((pixfmt == V4L2_PIX_FMT_SGRBG10DPCM8) ||
+				(pixfmt == V4L2_PIX_FMT_SGRBG10ALAW8))
+			ccdc_cfg.data_pack = CCDC_PACK_8BIT;
+		else
+			return -EINVAL;
+
+		ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+		ccdc_cfg.bayer.v4l2_pix_fmt = pixfmt;
+	} else {
+		if (pixfmt == V4L2_PIX_FMT_YUYV)
+			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+		else if (pixfmt == V4L2_PIX_FMT_UYVY)
+			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+		else
+		  return -EINVAL;
+
+		ccdc_cfg.data_pack = CCDC_PACK_8BIT;
+		ccdc_cfg.ycbcr.v4l2_pix_fmt = pixfmt;
+	}
+
+	return 0;
+}
+
+static u32 ccdc_get_pixel_format(void)
+{
+	u32 pixfmt;
+
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12)
+		pixfmt = ccdc_cfg.bayer.v4l2_pix_fmt;
+	else
+		pixfmt = ccdc_cfg.ycbcr.v4l2_pix_fmt;
+
+	return pixfmt;
+}
+
+static int ccdc_set_image_window(struct v4l2_rect *win)
+{
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12) {
+		ccdc_cfg.bayer.win.top = win->top;
+		ccdc_cfg.bayer.win.left = win->left;
+		ccdc_cfg.bayer.win.width = win->width;
+		ccdc_cfg.bayer.win.height = win->height;
+	} else {
+		ccdc_cfg.ycbcr.win.top = win->top;
+		ccdc_cfg.ycbcr.win.left = win->left;
+		ccdc_cfg.ycbcr.win.width = win->width;
+		ccdc_cfg.ycbcr.win.height = win->height;
+	}
+
+	return 0;
+}
+
+static void ccdc_get_image_window(struct v4l2_rect *win)
+{
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12)
+		*win = ccdc_cfg.bayer.win;
+	else
+		*win = ccdc_cfg.ycbcr.win;
+}
+
+static unsigned int ccdc_get_line_length(void)
+{
+	unsigned int len;
+
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12) {
+		if (ccdc_cfg.data_pack == CCDC_PACK_8BIT)
+			len = ((ccdc_cfg.bayer.win.width));
+		else if (ccdc_cfg.data_pack == CCDC_PACK_12BIT)
+			len = (ccdc_cfg.bayer.win.width * 2) +
+				 (ccdc_cfg.bayer.win.width >> 2);
+		else
+			len = ccdc_cfg.bayer.win.width * 2;
+	} else {
+		len = ccdc_cfg.ycbcr.win.width * 2;
+	}
+
+	return ALIGN(len, 32);
+}
+
+static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12)
+		ccdc_cfg.bayer.frm_fmt = frm_fmt;
+	else
+		ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
+
+	return 0;
+}
+
+static enum ccdc_frmfmt ccdc_get_frame_format(void)
+{
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12)
+		return ccdc_cfg.bayer.frm_fmt;
+	else
+		return ccdc_cfg.ycbcr.frm_fmt;
+}
+
+static int ccdc_getfid(void)
+{
+	return (regr(MODESET) >> 15) & 0x1;
+}
+
+static int ccdc_set_ctrl(u32 ctrl_id, s32 val)
+{
+	switch (ctrl_id) {
+	case VPFE_CCDC_CID_CRGAIN:
+		ccdc_gain_params.cr_gain = val;
+		break;
+	case VPFE_CCDC_CID_CGRGAIN:
+		ccdc_gain_params.cgr_gain = val;
+		break;
+	case VPFE_CCDC_CID_CGBGAIN:
+		ccdc_gain_params.cgb_gain = val;
+		break;
+	case VPFE_CCDC_CID_CBGAIN:
+		ccdc_gain_params.cb_gain = val;
+		break;
+	case VPFE_CCDC_CID_GAIN_OFFSET:
+		ccdc_gain_params.offset = val;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* misc operations */
+static void ccdc_setfbaddr(unsigned long addr)
+{
+	regw((addr >> 21) & 0x07ff, CADU);
+	regw((addr >> 5) & 0x0ffff, CADL);
+}
+
+static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+	ccdc_cfg.if_type = params->if_type;
+
+	switch (params->if_type) {
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+	case V4L2_MBUS_FMT_YUYV10_2X10:
+	case V4L2_MBUS_FMT_Y8_1X8:
+		ccdc_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
+		break;
+	case V4L2_MBUS_FMT_YUYV10_1X20:
+	case V4L2_MBUS_FMT_YUYV8_1X16:
+		ccdc_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
+		break;
+	case V4L2_MBUS_FMT_SGRBG12_1X12:
+		ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+		break;
+	default:
+		dev_dbg(dev, "Invalid interface type\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Parameter operations */
+static int ccdc_get_params(void *params)
+{
+	/* only raw module parameters can be set through the IOCTL */
+	if (ccdc_cfg.if_type != V4L2_MBUS_FMT_SGRBG12_1X12)
+		return -EINVAL;
+
+	memcpy(params, &ccdc_cfg.bayer.config_params,
+			sizeof(ccdc_cfg.bayer.config_params));
+
+	return 0;
+}
+
+/* Parameter operations */
+static int ccdc_set_params(void *params)
+{
+	struct ccdc_config_params_raw ccdc_raw_params;
+	int ret = -EINVAL;
+
+	/* only raw module parameters can be set through the IOCTL */
+	if (ccdc_cfg.if_type != V4L2_MBUS_FMT_SGRBG12_1X12)
+		return ret;
+
+	memcpy(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
+
+	if (!validate_ccdc_config_params_raw(&ccdc_raw_params)) {
+		memcpy(&ccdc_cfg.bayer.config_params, &ccdc_raw_params,
+			sizeof(ccdc_raw_params));
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/* This function will configure CCDC for YCbCr parameters. */
+static int ccdc_config_ycbcr(int mode)
+{
+	struct ccdc_ycbcr_config *params = &ccdc_cfg.ycbcr;
+	struct vpss_pg_frame_size frame_size;
+	struct vpss_sync_pol sync;
+	u32 modeset;
+	u32 ccdcfg;
+
+	/**
+	 * first reset the CCDC
+	 * all registers have default values after reset
+	 * This is important since we assume default values to be set in
+	 * a lot of registers that we didn't touch
+	 */
+	dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
+
+	/* start with all bits zero */
+	modeset = 0;
+	ccdcfg = 0;
+
+	/* configure pixel format or input mode */
+	modeset = modeset | ((params->pix_fmt & CCDC_INPUT_MASK) <<
+		  CCDC_INPUT_SHIFT) | ((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
+		  CCDC_FRM_FMT_SHIFT) | (((params->fid_pol &
+		  CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT)) |
+		  (((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT)) |
+		  (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT));
+
+	/* pack the data to 8-bit CCDCCFG */
+	switch (ccdc_cfg.if_type) {
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+			dev_dbg(dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		modeset |= ((VPFE_PINPOL_NEGATIVE & CCDC_VD_POL_MASK) <<
+				CCDC_VD_POL_SHIFT);
+		regw(3, REC656IF);
+		ccdcfg = ccdcfg | CCDC_DATA_PACK8 | CCDC_YCINSWP_YCBCR;
+		break;
+	case V4L2_MBUS_FMT_YUYV10_2X10:
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+			dev_dbg(dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		/* setup BT.656, embedded sync  */
+		regw(3, REC656IF);
+		/* enable 10 bit mode in ccdcfg */
+		ccdcfg = ccdcfg | CCDC_DATA_PACK8 | CCDC_YCINSWP_YCBCR |
+			CCDC_BW656_ENABLE;
+		break;
+	case V4L2_MBUS_FMT_YUYV10_1X20:
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
+			dev_dbg(dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		regw(3, REC656IF);
+		break;
+
+	case V4L2_MBUS_FMT_Y8_1X8:
+		ccdcfg |= CCDC_DATA_PACK8;
+		ccdcfg |= CCDC_YCINSWP_YCBCR;
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+			dev_dbg(dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		break;
+	case V4L2_MBUS_FMT_YUYV8_1X16:
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
+			dev_dbg(dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		/* should never come here */
+		dev_dbg(dev, "Invalid interface type\n");
+		return -EINVAL;
+	}
+
+	regw(modeset, MODESET);
+
+	/* Set up pix order */
+	ccdcfg |= (params->pix_order & CCDC_PIX_ORDER_MASK) <<
+		CCDC_PIX_ORDER_SHIFT;
+
+	regw(ccdcfg, CCDCFG);
+
+	/* configure video window */
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_YUYV10_1X20 ||
+			ccdc_cfg.if_type == V4L2_MBUS_FMT_YUYV8_1X16)
+		ccdc_setwin(&params->win, params->frm_fmt, 1, mode);
+	else
+		ccdc_setwin(&params->win, params->frm_fmt, 2, mode);
+
+	/**
+	 * configure the horizontal line offset
+	 * this is done by rounding up width to a multiple of 16 pixels
+	 * and multiply by two to account for y:cb:cr 4:2:2 data
+	 */
+	regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
+
+	/* configure the memory line offset */
+	if (params->frm_fmt == CCDC_FRMFMT_INTERLACED &&
+	    params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
+		/* two fields are interleaved in memory */
+		regw(0x00000249, SDOFST);
+	}
+
+	/* Setup test pattern if enabled */
+	if (ccdc_test_pat_gen) {
+		sync.ccdpg_hdpol = (params->hd_pol & CCDC_HD_POL_MASK);
+		sync.ccdpg_vdpol = (params->vd_pol & CCDC_VD_POL_MASK);
+		vpss_set_sync_pol(sync);
+		vpss_set_pg_frame_size(frame_size);
+	}
+
+	return 0;
+}
+
+static int ccdc_configure(int mode)
+{
+	if (ccdc_cfg.if_type == V4L2_MBUS_FMT_SGRBG12_1X12)
+		return ccdc_config_raw(mode);
+
+	return ccdc_config_ycbcr(mode);
+}
+
+static int ccdc_close(struct device *device)
+{
+	/* copy defaults to module params */
+	memcpy(&ccdc_cfg.bayer.config_params, &ccdc_config_defaults,
+		sizeof(struct ccdc_config_params_raw));
+
+	return 0;
+}
+
+static struct ccdc_hw_device ccdc_hw_dev = {
+	.name = "dm365_isif",
+	.owner = THIS_MODULE,
+	.hw_ops = {
+		.open = ccdc_open,
+		.close = ccdc_close,
+		.enable = ccdc_enable,
+		.enable_out_to_sdram = ccdc_enable_output_to_sdram,
+		.set_hw_if_params = ccdc_set_hw_if_params,
+		.set_params = ccdc_set_params,
+		.get_params = ccdc_get_params,
+		.configure = ccdc_configure,
+		.set_buftype = ccdc_set_buftype,
+		.get_buftype = ccdc_get_buftype,
+		.enum_pix = ccdc_enum_pix,
+		.set_pixel_format = ccdc_set_pixel_format,
+		.get_pixel_format = ccdc_get_pixel_format,
+		.set_frame_format = ccdc_set_frame_format,
+		.get_frame_format = ccdc_get_frame_format,
+		.set_image_window = ccdc_set_image_window,
+		.get_image_window = ccdc_get_image_window,
+		.get_line_length = ccdc_get_line_length,
+		.setfbaddr = ccdc_setfbaddr,
+		.getfid = ccdc_getfid,
+		.set_ctrl = ccdc_set_ctrl,
+	},
+};
+
+struct ccdc_hw_device *get_ccdc_dev(void)
+{
+	return &ccdc_hw_dev;
+}
+
+int ccdc_init(struct platform_device *pdev)
+{
+	static resource_size_t res_len;
+	struct resource *res;
+	void *__iomem addr;
+	int status;
+	int i;
+
+	i = 0;
+	/* Get the ISIF base address, linearization table0 and table1 addr. */
+	while (i < 3) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res) {
+			status = -ENOENT;
+			goto fail_nobase_res;
+		}
+		res_len = res->end - res->start + 1;
+		res = request_mem_region(res->start, res_len, res->name);
+		if (!res) {
+			status = -EBUSY;
+			goto fail_nobase_res;
+		}
+		addr = ioremap_nocache(res->start, res_len);
+		if (!addr) {
+			status = -EBUSY;
+			goto fail_base_iomap;
+		}
+		switch (i) {
+		case 0:
+			/* ISIF base address */
+			ccdc_cfg.base_addr = addr;
+			break;
+		case 1:
+			/* ISIF linear tbl0 address */
+			ccdc_cfg.linear_tbl0_addr = addr;
+			break;
+		default:
+			/* ISIF linear tbl0 address */
+			ccdc_cfg.linear_tbl1_addr = addr;
+			break;
+		}
+		i++;
+	}
+
+	davinci_cfg_reg(DM365_VIN_CAM_WEN);
+	davinci_cfg_reg(DM365_VIN_CAM_VD);
+	davinci_cfg_reg(DM365_VIN_CAM_HD);
+	davinci_cfg_reg(DM365_VIN_YIN4_7_EN);
+	davinci_cfg_reg(DM365_VIN_YIN0_3_EN);
+
+	return 0;
+fail_base_iomap:
+	release_mem_region(res->start, res_len);
+	i--;
+fail_nobase_res:
+	if (ccdc_cfg.base_addr)
+		iounmap(ccdc_cfg.base_addr);
+	if (ccdc_cfg.linear_tbl0_addr)
+		iounmap(ccdc_cfg.linear_tbl0_addr);
+
+	while (i >= 0) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		release_mem_region(res->start, res_len);
+		i--;
+	}
+
+	return status;
+}
+
+void ccdc_remove(struct platform_device *pdev)
+{
+	struct resource *res;
+	int i;
+
+	iounmap(ccdc_cfg.base_addr);
+	iounmap(ccdc_cfg.linear_tbl0_addr);
+	iounmap(ccdc_cfg.linear_tbl1_addr);
+
+	i = 0;
+	while (i < 3) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (res)
+			release_mem_region(res->start,
+					   res->end - res->start + 1);
+		i++;
+	}
+}
diff --git a/drivers/media/platform/davinci/dm365_ccdc.h b/drivers/media/platform/davinci/dm365_ccdc.h
new file mode 100644
index 0000000..ce9358f
--- /dev/null
+++ b/drivers/media/platform/davinci/dm365_ccdc.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _DM365_CCDC_H
+#define _DM365_CCDC_H
+
+#include <linux/dm365_ccdc.h>
+
+#include <media/davinci/vpfe.h>
+#include <media/davinci/ccdc_types.h>
+
+#define CCDC_COLPTN_R_Ye	0x0
+#define CCDC_COLPTN_Gr_Cy	0x1
+#define CCDC_COLPTN_Gb_G	0x2
+#define CCDC_COLPTN_B_Mg	0x3
+
+#define CCDC_CCOLP_CP01_0	0
+#define CCDC_CCOLP_CP03_2	2
+#define CCDC_CCOLP_CP05_4	4
+#define CCDC_CCOLP_CP07_6	6
+#define CCDC_CCOLP_CP11_0	8
+#define CCDC_CCOLP_CP13_2	10
+#define CCDC_CCOLP_CP15_4	12
+#define CCDC_CCOLP_CP17_6	14
+
+static const u32 ccdc_sgrbg_pattern =
+	CCDC_COLPTN_Gr_Cy <<  CCDC_CCOLP_CP01_0 |
+	CCDC_COLPTN_R_Ye  << CCDC_CCOLP_CP03_2 |
+	CCDC_COLPTN_B_Mg  << CCDC_CCOLP_CP05_4 |
+	CCDC_COLPTN_Gb_G  << CCDC_CCOLP_CP07_6 |
+	CCDC_COLPTN_Gr_Cy << CCDC_CCOLP_CP11_0 |
+	CCDC_COLPTN_R_Ye  << CCDC_CCOLP_CP13_2 |
+	CCDC_COLPTN_B_Mg  << CCDC_CCOLP_CP15_4 |
+	CCDC_COLPTN_Gb_G  << CCDC_CCOLP_CP17_6;
+
+static const u32 ccdc_srggb_pattern =
+	CCDC_COLPTN_R_Ye  << CCDC_CCOLP_CP01_0 |
+	CCDC_COLPTN_Gr_Cy << CCDC_CCOLP_CP03_2 |
+	CCDC_COLPTN_Gb_G  << CCDC_CCOLP_CP05_4 |
+	CCDC_COLPTN_B_Mg  << CCDC_CCOLP_CP07_6 |
+	CCDC_COLPTN_R_Ye  << CCDC_CCOLP_CP11_0 |
+	CCDC_COLPTN_Gr_Cy << CCDC_CCOLP_CP13_2 |
+	CCDC_COLPTN_Gb_G  << CCDC_CCOLP_CP15_4 |
+	CCDC_COLPTN_B_Mg  << CCDC_CCOLP_CP17_6;
+
+struct ccdc_ycbcr_config {
+	/* v4l2 pixel format */
+	unsigned long v4l2_pix_fmt;
+	/* ccdc pixel format */
+	enum ccdc_pixfmt pix_fmt;
+	/* ccdc frame format */
+	enum ccdc_frmfmt frm_fmt;
+	/* CCDC crop window */
+	struct v4l2_rect win;
+	/* field polarity */
+	enum vpfe_pin_pol fid_pol;
+	/* interface VD polarity */
+	enum vpfe_pin_pol vd_pol;
+	/* interface HD polarity */
+	enum vpfe_pin_pol hd_pol;
+	/* ccdc pix order. Only used for ycbcr capture */
+	enum ccdc_pixorder pix_order;
+	/* ccdc buffer type. Only used for ycbcr capture */
+	enum ccdc_buftype buf_type;
+};
+
+struct ccdc_params_raw {
+	/* v4l2 pixel format */
+	unsigned long v4l2_pix_fmt;
+	/* ccdc pixel format */
+	enum ccdc_pixfmt pix_fmt;
+	/* ccdc frame format */
+	enum ccdc_frmfmt frm_fmt;
+	/* video window */
+	struct v4l2_rect win;
+	/* field polarity */
+	enum vpfe_pin_pol fid_pol;
+	/* interface VD polarity */
+	enum vpfe_pin_pol vd_pol;
+	/* interface HD polarity */
+	enum vpfe_pin_pol hd_pol;
+	/* buffer type. Applicable for interlaced mode */
+	enum ccdc_buftype buf_type;
+	/* Gain values */
+	struct ccdc_gain gain;
+	/* cfa pattern */
+	enum ccdc_cfa_pattern cfa_pat;
+	/* Data MSB position */
+	enum ccdc_data_msb data_msb;
+	/* Enable horizontal flip */
+	unsigned char horz_flip_en;
+	/* Enable image invert vertically */
+	unsigned char image_invert_en;
+
+	/*all the userland defined stuff*/
+	struct ccdc_config_params_raw config_params;
+};
+
+enum ccdc_data_pack {
+	CCDC_PACK_16BIT,
+	CCDC_PACK_12BIT,
+	CCDC_PACK_8BIT
+};
+
+struct ccdc_gain_values {
+	unsigned int cr_gain;
+	unsigned int cgr_gain;
+	unsigned int cgb_gain;
+	unsigned int cb_gain;
+	unsigned int offset;
+};
+
+struct ccdc_hw_device *get_ccdc_dev(void);
+
+#define CCDC_WIN_NTSC		{0, 0, 720, 480}
+#define CCDC_WIN_VGA		{0, 0, 640, 480}
+#define ISP5_CCDCMUX		0x20
+
+#endif
diff --git a/drivers/media/platform/davinci/dm365_ccdc_regs.h b/drivers/media/platform/davinci/dm365_ccdc_regs.h
new file mode 100644
index 0000000..fcc82ea
--- /dev/null
+++ b/drivers/media/platform/davinci/dm365_ccdc_regs.h
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _DM365_CCDC_REGS_H
+#define _DM365_CCDC_REGS_H
+
+/* ISIF registers relative offsets */
+#define SYNCEN					0x00
+#define MODESET					0x04
+#define HDW					0x08
+#define VDW					0x0c
+#define PPLN					0x10
+#define LPFR					0x14
+#define SPH					0x18
+#define LNH					0x1c
+#define SLV0					0x20
+#define SLV1					0x24
+#define LNV					0x28
+#define CULH					0x2c
+#define CULV					0x30
+#define HSIZE					0x34
+#define SDOFST					0x38
+#define CADU					0x3c
+#define CADL					0x40
+#define LINCFG0					0x44
+#define LINCFG1					0x48
+#define CCOLP					0x4c
+#define CRGAIN					0x50
+#define CGRGAIN					0x54
+#define CGBGAIN					0x58
+#define CBGAIN					0x5c
+#define COFSTA					0x60
+#define FLSHCFG0				0x64
+#define FLSHCFG1				0x68
+#define FLSHCFG2				0x6c
+#define VDINT0					0x70
+#define VDINT1					0x74
+#define VDINT2					0x78
+#define MISC					0x7c
+#define CGAMMAWD				0x80
+#define REC656IF				0x84
+#define CCDCFG					0x88
+/*****************************************************
+* Defect Correction registers
+*****************************************************/
+#define DFCCTL					0x8c
+#define VDFSATLV				0x90
+#define DFCMEMCTL				0x94
+#define DFCMEM0					0x98
+#define DFCMEM1					0x9c
+#define DFCMEM2					0xa0
+#define DFCMEM3					0xa4
+#define DFCMEM4					0xa8
+/****************************************************
+* Black Clamp registers
+****************************************************/
+#define CLAMPCFG				0xac
+#define CLDCOFST				0xb0
+#define CLSV					0xb4
+#define CLHWIN0					0xb8
+#define CLHWIN1					0xbc
+#define CLHWIN2					0xc0
+#define CLVRV					0xc4
+#define CLVWIN0					0xc8
+#define CLVWIN1					0xcc
+#define CLVWIN2					0xd0
+#define CLVWIN3					0xd4
+/****************************************************
+* Lense Shading Correction
+****************************************************/
+#define DATAHOFST				0xd8
+#define DATAVOFST				0xdc
+#define LSCHVAL					0xe0
+#define LSCVVAL					0xe4
+#define TWODLSCCFG				0xe8
+#define TWODLSCOFST				0xec
+#define TWODLSCINI				0xf0
+#define TWODLSCGRBU				0xf4
+#define TWODLSCGRBL				0xf8
+#define TWODLSCGROF				0xfc
+#define TWODLSCORBU				0x100
+#define TWODLSCORBL				0x104
+#define TWODLSCOROF				0x108
+#define TWODLSCIRQEN				0x10c
+#define TWODLSCIRQST				0x110
+/****************************************************
+* Data formatter
+****************************************************/
+#define FMTCFG					0x114
+#define FMTPLEN					0x118
+#define FMTSPH					0x11c
+#define FMTLNH					0x120
+#define FMTSLV					0x124
+#define FMTLNV					0x128
+#define FMTRLEN					0x12c
+#define FMTHCNT					0x130
+#define FMTAPTR_BASE				0x134
+/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */
+#define FMTAPTR(i)			(FMTAPTR_BASE + (i * 4))
+#define FMTPGMVF0				0x174
+#define FMTPGMVF1				0x178
+#define FMTPGMAPU0				0x17c
+#define FMTPGMAPU1				0x180
+#define FMTPGMAPS0				0x184
+#define FMTPGMAPS1				0x188
+#define FMTPGMAPS2				0x18c
+#define FMTPGMAPS3				0x190
+#define FMTPGMAPS4				0x194
+#define FMTPGMAPS5				0x198
+#define FMTPGMAPS6				0x19c
+#define FMTPGMAPS7				0x1a0
+/************************************************
+* Color Space Converter
+************************************************/
+#define CSCCTL					0x1a4
+#define CSCM0					0x1a8
+#define CSCM1					0x1ac
+#define CSCM2					0x1b0
+#define CSCM3					0x1b4
+#define CSCM4					0x1b8
+#define CSCM5					0x1bc
+#define CSCM6					0x1c0
+#define CSCM7					0x1c4
+#define OBWIN0					0x1c8
+#define OBWIN1					0x1cc
+#define OBWIN2					0x1d0
+#define OBWIN3					0x1d4
+#define OBVAL0					0x1d8
+#define OBVAL1					0x1dc
+#define OBVAL2					0x1e0
+#define OBVAL3					0x1e4
+#define OBVAL4					0x1e8
+#define OBVAL5					0x1ec
+#define OBVAL6					0x1f0
+#define OBVAL7					0x1f4
+#define CLKCTL					0x1f8
+
+#define CCDC_LINEAR_LUT0_ADDR			0x1c7c000
+#define CCDC_LINEAR_LUT1_ADDR			0x1c7c400
+
+/* Masks & Shifts below */
+#define START_PX_HOR_MASK			0x7fff
+#define NUM_PX_HOR_MASK				0x7fff
+#define START_VER_ONE_MASK			0x7fff
+#define START_VER_TWO_MASK			0x7fff
+#define NUM_LINES_VER				0x7fff
+
+/* gain - offset masks */
+#define GAIN_INTEGER_MASK			0x7
+#define GAIN_INTEGER_SHIFT			0x9
+#define GAIN_DECIMAL_MASK			0x1ff
+#define OFFSET_MASK				0xfff
+#define GAIN_SDRAM_EN_SHIFT			12
+#define GAIN_IPIPE_EN_SHIFT			13
+#define GAIN_H3A_EN_SHIFT			14
+#define OFST_SDRAM_EN_SHIFT			8
+#define OFST_IPIPE_EN_SHIFT			9
+#define OFST_H3A_EN_SHIFT			10
+#define GAIN_OFFSET_EN_MASK			0x7700
+
+/* Culling */
+#define CULL_PAT_EVEN_LINE_SHIFT		8
+
+/* CCDCFG register */
+#define CCDC_YCINSWP_RAW			(0x00 << 4)
+#define CCDC_YCINSWP_YCBCR			(0x01 << 4)
+#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC		(0x00 << 6)
+#define CCDC_CCDCFG_WENLOG_AND			(0x00 << 8)
+#define CCDC_CCDCFG_TRGSEL_WEN			(0x00 << 9)
+#define CCDC_CCDCFG_EXTRG_DISABLE		(0x00 << 10)
+#define CCDC_LATCH_ON_VSYNC_DISABLE		(0x01 << 15)
+#define CCDC_LATCH_ON_VSYNC_ENABLE		(0x00 << 15)
+#define CCDC_DATA_PACK_MASK			0x03
+#define CCDC_DATA_PACK16			0x0
+#define CCDC_DATA_PACK12			0x1
+#define CCDC_DATA_PACK8				0x2
+#define CCDC_PIX_ORDER_SHIFT			11
+#define CCDC_PIX_ORDER_MASK			0x01
+#define CCDC_BW656_ENABLE			(0x01 << 5)
+
+/* MODESET registers */
+#define CCDC_VDHDOUT_INPUT			(0x00 << 0)
+#define CCDC_INPUT_MASK				0x03
+#define CCDC_INPUT_SHIFT			12
+#define CCDC_RAW_INPUT_MODE			0x00
+#define CCDC_FID_POL_MASK			0x01
+#define CCDC_FID_POL_SHIFT			4
+#define CCDC_HD_POL_MASK			0x01
+#define CCDC_HD_POL_SHIFT			3
+#define CCDC_VD_POL_MASK			0x01
+#define CCDC_VD_POL_SHIFT			2
+#define CCDC_DATAPOL_NORMAL			0x00
+#define CCDC_DATAPOL_MASK			0x01
+#define CCDC_DATAPOL_SHIFT			6
+#define CCDC_EXWEN_DISABLE			0x00
+#define CCDC_EXWEN_MASK				0x01
+#define CCDC_EXWEN_SHIFT			5
+#define CCDC_FRM_FMT_MASK			0x01
+#define CCDC_FRM_FMT_SHIFT			7
+#define CCDC_DATASFT_MASK			0x07
+#define CCDC_DATASFT_SHIFT			8
+#define CCDC_LPF_SHIFT				14
+#define CCDC_LPF_MASK				0x1
+
+/* GAMMAWD registers */
+#define CCDC_ALAW_GAMA_WD_MASK			0xf
+#define CCDC_ALAW_GAMA_WD_SHIFT			1
+#define CCDC_ALAW_ENABLE			0x01
+#define CCDC_GAMMAWD_CFA_MASK			0x01
+#define CCDC_GAMMAWD_CFA_SHIFT			5
+
+/* HSIZE registers */
+#define CCDC_HSIZE_FLIP_MASK			0x01
+#define CCDC_HSIZE_FLIP_SHIFT			12
+#define CCDC_LINEOFST_MASK			0xfff
+
+/* MISC registers */
+#define CCDC_DPCM_EN_SHIFT			12
+#define CCDC_DPCM_EN_MASK			1
+#define CCDC_DPCM_PREDICTOR_SHIFT		13
+#define CCDC_DPCM_PREDICTOR_MASK		1
+
+/* Black clamp related */
+#define CCDC_BC_DCOFFSET_MASK			0x1fff
+#define CCDC_BC_MODE_COLOR_MASK			1
+#define CCDC_BC_MODE_COLOR_SHIFT		4
+#define CCDC_HORZ_BC_MODE_MASK			3
+#define CCDC_HORZ_BC_MODE_SHIFT			1
+#define CCDC_HORZ_BC_WIN_COUNT_MASK		0x1f
+#define CCDC_HORZ_BC_WIN_SEL_SHIFT		5
+#define CCDC_HORZ_BC_PIX_LIMIT_SHIFT		6
+#define CCDC_HORZ_BC_WIN_H_SIZE_MASK		3
+#define CCDC_HORZ_BC_WIN_H_SIZE_SHIFT		8
+#define CCDC_HORZ_BC_WIN_V_SIZE_MASK		3
+#define CCDC_HORZ_BC_WIN_V_SIZE_SHIFT		12
+#define CCDC_HORZ_BC_WIN_START_H_MASK		0x1fff
+#define CCDC_HORZ_BC_WIN_START_V_MASK		0x1fff
+#define CCDC_VERT_BC_OB_H_SZ_MASK		7
+#define CCDC_VERT_BC_RST_VAL_SEL_MASK		3
+#define CCDC_VERT_BC_RST_VAL_SEL_SHIFT		4
+#define CCDC_VERT_BC_LINE_AVE_COEF_SHIFT	8
+#define CCDC_VERT_BC_OB_START_HORZ_MASK		0x1fff
+#define CCDC_VERT_BC_OB_START_VERT_MASK		0x1fff
+#define CCDC_VERT_BC_OB_VERT_SZ_MASK		0x1fff
+#define CCDC_VERT_BC_RST_VAL_MASK		0xfff
+#define CCDC_BC_VERT_START_SUB_V_MASK		0x1fff
+
+/* VDFC registers */
+#define CCDC_VDFC_EN_SHIFT			4
+#define CCDC_VDFC_CORR_MOD_MASK			3
+#define CCDC_VDFC_CORR_MOD_SHIFT		5
+#define CCDC_VDFC_CORR_WHOLE_LN_SHIFT		7
+#define CCDC_VDFC_LEVEL_SHFT_MASK		7
+#define CCDC_VDFC_LEVEL_SHFT_SHIFT		8
+#define CCDC_VDFC_SAT_LEVEL_MASK		0xfff
+#define CCDC_VDFC_POS_MASK			0x1fff
+#define CCDC_DFCMEMCTL_DFCMARST_SHIFT		2
+
+/* CSC registers */
+#define CCDC_CSC_COEF_INTEG_MASK		7
+#define CCDC_CSC_COEF_DECIMAL_MASK		0x1f
+#define CCDC_CSC_COEF_INTEG_SHIFT		5
+#define CCDC_CSCM_MSB_SHIFT			8
+#define CCDC_DF_CSC_SPH_MASK			0x1fff
+#define CCDC_DF_CSC_LNH_MASK			0x1fff
+#define CCDC_DF_CSC_SLV_MASK			0x1fff
+#define CCDC_DF_CSC_LNV_MASK			0x1fff
+#define CCDC_DF_NUMLINES			0x7fff
+#define CCDC_DF_NUMPIX				0x1fff
+
+/* Offsets for LSC/DFC/Gain */
+#define CCDC_DATA_H_OFFSET_MASK			0x1fff
+#define CCDC_DATA_V_OFFSET_MASK			0x1fff
+
+/* Linearization */
+#define CCDC_LIN_CORRSFT_MASK			7
+#define CCDC_LIN_CORRSFT_SHIFT			4
+#define CCDC_LIN_SCALE_FACT_INTEG_SHIFT		10
+#define CCDC_LIN_SCALE_FACT_DECIMAL_MASK	0x3ff
+#define CCDC_LIN_ENTRY_MASK			0x3ff
+
+#define CCDC_DF_FMTRLEN_MASK			0x1fff
+#define CCDC_DF_FMTHCNT_MASK			0x1fff
+
+/* Pattern registers */
+#define CCDC_PG_EN				(1 << 3)
+#define CCDC_SEL_PG_SRC				(3 << 4)
+#define CCDC_PG_VD_POL_SHIFT			0
+#define CCDC_PG_HD_POL_SHIFT			1
+
+/*masks and shifts*/
+#define CCDC_SYNCEN_VDHDEN_MASK			(1 << 0)
+#define CCDC_SYNCEN_WEN_MASK			(1 << 1)
+#define CCDC_SYNCEN_WEN_SHIFT			1
+
+#endif
diff --git a/include/linux/dm365_ccdc.h b/include/linux/dm365_ccdc.h
new file mode 100644
index 0000000..da37b9b
--- /dev/null
+++ b/include/linux/dm365_ccdc.h
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _DM365_CCDC_INCLUDE_H
+#define _DM365_CCDC_INCLUDE_H
+
+/**
+ * ccdc float type S8Q8/U8Q8
+ */
+struct ccdc_float_8 {
+	/* 8 bit integer part */
+	__u8 integer;
+	/* 8 bit decimal part */
+	__u8 decimal;
+};
+
+/**
+ * brief ccdc float type U16Q16/S16Q16
+ */
+struct ccdc_float_16 {
+	/* 16 bit integer part */
+	__u16 integer;
+	/* 16 bit decimal part */
+	__u16 decimal;
+};
+
+/************************************************************************
+ *   Vertical Defect Correction parameters
+ ***********************************************************************/
+
+/**
+ * vertical defect correction methods
+ */
+enum ccdc_vdfc_corr_mode {
+	/* Defect level subtraction. Just fed through if saturating */
+	CCDC_VDFC_NORMAL,
+	/**
+	 * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2
+	 * if data saturating
+	 */
+	CCDC_VDFC_HORZ_INTERPOL_IF_SAT,
+	/* Horizontal interpolation (((i-2)+(i+2))/2) */
+	CCDC_VDFC_HORZ_INTERPOL
+};
+
+/**
+ * Max Size of the Vertical Defect Correction table
+ */
+#define CCDC_VDFC_TABLE_SIZE 8
+
+/**
+ * Values used for shifting up the vdfc defect level
+ */
+enum ccdc_vdfc_shift {
+	/* No Shift */
+	CCDC_VDFC_NO_SHIFT,
+	/* Shift by 1 bit */
+	CCDC_VDFC_SHIFT_1,
+	/* Shift by 2 bit */
+	CCDC_VDFC_SHIFT_2,
+	/* Shift by 3 bit */
+	CCDC_VDFC_SHIFT_3,
+	/* Shift by 4 bit */
+	CCDC_VDFC_SHIFT_4
+};
+
+/**
+ * Defect Correction (DFC) table entry
+ */
+struct ccdc_vdfc_entry {
+	/* vertical position of defect */
+	unsigned short pos_vert;
+	/* horizontal position of defect */
+	unsigned short pos_horz;
+	/**
+	 * Defect level of Vertical line defect position. This is subtracted
+	 * from the data at the defect position
+	 */
+	unsigned char level_at_pos;
+	/**
+	 * Defect level of the pixels upper than the vertical line defect.
+	 * This is subtracted from the data
+	 */
+	unsigned char level_up_pixels;
+	/**
+	 * Defect level of the pixels lower than the vertical line defect.
+	 * This is subtracted from the data
+	 */
+	unsigned char level_low_pixels;
+};
+
+/**
+ * Structure for Defect Correction (DFC) parameter
+ */
+struct ccdc_dfc {
+	/* enable vertical defect correction */
+	unsigned char en;
+	/* Correction methods */
+	enum ccdc_vdfc_corr_mode corr_mode;
+	/**
+	 * 0 - whole line corrected, 1 - not
+	 * pixels upper than the defect
+	 */
+	unsigned char corr_whole_line;
+	/**
+	 * defect level shift value. level_at_pos, level_upper_pos,
+	 * and level_lower_pos can be shifted up by this value
+	 */
+	enum ccdc_vdfc_shift def_level_shift;
+	/* defect saturation level */
+	unsigned short def_sat_level;
+	/* number of vertical defects. Max is CCDC_VDFC_TABLE_SIZE */
+	short num_vdefects;
+	/* VDFC table ptr */
+	struct ccdc_vdfc_entry table[CCDC_VDFC_TABLE_SIZE];
+};
+
+/************************************************************************
+*   Digital/Black clamp or DC Subtract parameters
+************************************************************************/
+/**
+ * Horizontal Black Clamp modes
+ */
+enum ccdc_horz_bc_mode {
+	/**
+	 * Horizontal clamp disabled. Only vertical clamp
+	 * value is subtracted
+	 */
+	CCDC_HORZ_BC_DISABLE,
+	/**
+	 * Horizontal clamp value is calculated and subtracted
+	 * from image data along with vertical clamp value
+	 */
+	CCDC_HORZ_BC_CLAMP_CALC_ENABLED,
+	/**
+	 * Horizontal clamp value calculated from previous image
+	 * is subtracted from image data along with vertical clamp
+	 * value. How the horizontal clamp value for the first image
+	 * is calculated in this case ???
+	 */
+	CCDC_HORZ_BC_CLAMP_NOT_UPDATED
+};
+
+/**
+ * Base window selection for Horizontal Black Clamp calculations
+ */
+enum ccdc_horz_bc_base_win_sel {
+	/* Select Most left window for bc calculation */
+	CCDC_SEL_MOST_LEFT_WIN,
+
+	/* Select Most right window for bc calculation */
+	CCDC_SEL_MOST_RIGHT_WIN,
+};
+
+/* Size of window in horizontal direction for horizontal bc */
+enum ccdc_horz_bc_sz_h {
+	CCDC_HORZ_BC_SZ_H_2PIXELS,
+	CCDC_HORZ_BC_SZ_H_4PIXELS,
+	CCDC_HORZ_BC_SZ_H_8PIXELS,
+	CCDC_HORZ_BC_SZ_H_16PIXELS
+};
+
+/* Size of window in vertcal direction for vertical bc */
+enum ccdc_horz_bc_sz_v {
+	CCDC_HORZ_BC_SZ_H_32PIXELS,
+	CCDC_HORZ_BC_SZ_H_64PIXELS,
+	CCDC_HORZ_BC_SZ_H_128PIXELS,
+	CCDC_HORZ_BC_SZ_H_256PIXELS
+};
+
+/**
+ * Structure for Horizontal Black Clamp config params
+ */
+struct ccdc_horz_bclamp {
+	/* horizontal clamp mode */
+	enum ccdc_horz_bc_mode mode;
+	/**
+	 * pixel value limit enable.
+	 *  0 - limit disabled
+	 *  1 - pixel value limited to 1023
+	 */
+	unsigned char clamp_pix_limit;
+	/**
+	 * Select most left or right window for clamp val
+	 * calculation
+	 */
+	enum ccdc_horz_bc_base_win_sel base_win_sel_calc;
+	/* Window count per color for calculation. range 1-32 */
+	unsigned char win_count_calc;
+	/* Window start position - horizontal for calculation. 0 - 8191 */
+	unsigned short win_start_h_calc;
+	/* Window start position - vertical for calculation 0 - 8191 */
+	unsigned short win_start_v_calc;
+	/* Width of the sample window in pixels for calculation */
+	enum ccdc_horz_bc_sz_h win_h_sz_calc;
+	/* Height of the sample window in pixels for calculation */
+	enum ccdc_horz_bc_sz_v win_v_sz_calc;
+};
+
+/**
+ * Black Clamp vertical reset values
+ */
+enum ccdc_vert_bc_reset_val_sel {
+	/* Reset value used is the clamp value calculated */
+	CCDC_VERT_BC_USE_HORZ_CLAMP_VAL,
+	/* Reset value used is reset_clamp_val configured */
+	CCDC_VERT_BC_USE_CONFIG_CLAMP_VAL,
+	/* No update, previous image value is used */
+	CCDC_VERT_BC_NO_UPDATE
+};
+
+enum ccdc_vert_bc_sz_h {
+	CCDC_VERT_BC_SZ_H_2PIXELS,
+	CCDC_VERT_BC_SZ_H_4PIXELS,
+	CCDC_VERT_BC_SZ_H_8PIXELS,
+	CCDC_VERT_BC_SZ_H_16PIXELS,
+	CCDC_VERT_BC_SZ_H_32PIXELS,
+	CCDC_VERT_BC_SZ_H_64PIXELS
+};
+
+/**
+ * Structure for Vetical Black Clamp configuration params
+ */
+struct ccdc_vert_bclamp {
+	/* Reset value selection for vertical clamp calculation */
+	enum ccdc_vert_bc_reset_val_sel reset_val_sel;
+	/* U12 value if reset_sel = CCDC_BC_VERT_USE_CONFIG_CLAMP_VAL */
+	unsigned short reset_clamp_val;
+	/**
+	 * U8Q8. Line average coefficient used in vertical clamp
+	 * calculation
+	 */
+	unsigned char line_ave_coef;
+	/* Width in pixels of the optical black region used for calculation. */
+	enum ccdc_vert_bc_sz_h ob_h_sz_calc;
+	/* Height of the optical black region for calculation */
+	unsigned short ob_v_sz_calc;
+	/* Optical black region start position - horizontal. 0 - 8191 */
+	unsigned short ob_start_h;
+	/* Optical black region start position - vertical 0 - 8191 */
+	unsigned short ob_start_v;
+};
+
+/**
+ * Structure for Black Clamp configuration params
+ */
+struct ccdc_black_clamp {
+	/**
+	 * this offset value is added irrespective of the clamp
+	 * enable status. S13
+	 */
+	unsigned short dc_offset;
+	/**
+	 * Enable black/digital clamp value to be subtracted
+	 * from the image data
+	 */
+	unsigned char en;
+	/**
+	 * black clamp mode. same/separate clamp for 4 colors
+	 * 0 - disable - same clamp value for all colors
+	 * 1 - clamp value calculated separately for all colors
+	 */
+	unsigned char bc_mode_color;
+	/* Vrtical start position for bc subtraction */
+	unsigned short vert_start_sub;
+	/* Black clamp for horizontal direction */
+	struct ccdc_horz_bclamp horz;
+	/* Black clamp for vertical direction */
+	struct ccdc_vert_bclamp vert;
+};
+
+/*************************************************************************
+** Color Space Convertion (CSC)
+*************************************************************************/
+/**
+ * Number of Coefficient values used for CSC
+ */
+#define CCDC_CSC_NUM_COEFF 16
+
+/*************************************************************************
+**  Color Space Conversion parameters
+*************************************************************************/
+/**
+ * Structure used for CSC config params
+ */
+struct ccdc_color_space_conv {
+	/* Enable color space conversion */
+	unsigned char en;
+	/**
+	 * csc coeffient table. S8Q5, M00 at index 0, M01 at index 1, and
+	 * so forth
+	 */
+	struct ccdc_float_8 coeff[CCDC_CSC_NUM_COEFF];
+};
+
+enum ccdc_datasft {
+	/* No Shift */
+	CCDC_NO_SHIFT,
+	/* 1 bit Shift */
+	CCDC_1BIT_SHIFT,
+	/* 2 bit Shift */
+	CCDC_2BIT_SHIFT,
+	/* 3 bit Shift */
+	CCDC_3BIT_SHIFT,
+	/* 4 bit Shift */
+	CCDC_4BIT_SHIFT,
+	/* 5 bit Shift */
+	CCDC_5BIT_SHIFT,
+	/* 6 bit Shift */
+	CCDC_6BIT_SHIFT
+};
+
+enum ccdc_data_msb {
+	/* MSB b15 */
+	CCDC_BIT_MSB_15,
+	/* MSB b14 */
+	CCDC_BIT_MSB_14,
+	/* MSB b13 */
+	CCDC_BIT_MSB_13,
+	/* MSB b12 */
+	CCDC_BIT_MSB_12,
+	/* MSB b11 */
+	CCDC_BIT_MSB_11,
+	/* MSB b10 */
+	CCDC_BIT_MSB_10,
+	/* MSB b9 */
+	CCDC_BIT_MSB_9,
+	/* MSB b8 */
+	CCDC_BIT_MSB_8,
+	/* MSB b7 */
+	CCDC_BIT_MSB_7
+};
+
+/*************************************************************************
+**  Gain parameters
+*************************************************************************/
+/**
+ * Structure for Gain parameters
+ */
+struct ccdc_gain {
+	/* Gain for Red or ye */
+	struct ccdc_float_16 r_ye;
+	/* Gain for Gr or cy */
+	struct ccdc_float_16 gr_cy;
+	/* Gain for Gb or g */
+	struct ccdc_float_16 gb_g;
+	/* Gain for Blue or mg */
+	struct ccdc_float_16 b_mg;
+};
+
+/**
+ * Predicator types for DPCM compression
+ */
+enum ccdc_dpcm_predictor {
+	/* Choose Predictor1 for DPCM compression */
+	CCDC_DPCM_PRED1,
+	/* Choose Predictor2 for DPCM compression */
+	CCDC_DPCM_PRED2
+};
+
+#define CCDC_LINEAR_TAB_SIZE 192
+/*************************************************************************
+**  Linearization parameters
+*************************************************************************/
+/**
+ * Structure for Sensor data linearization
+ */
+struct ccdc_linearize {
+	/* Enable or Disable linearization of data */
+	unsigned char en;
+	/* Shift value applied */
+	enum ccdc_datasft corr_shft;
+	/* scale factor applied U11Q10 */
+	struct ccdc_float_16 scale_fact;
+	/* Size of the linear table */
+	unsigned short table[CCDC_LINEAR_TAB_SIZE];
+};
+
+enum ccdc_cfa_pattern {
+	CCDC_CFA_PAT_MOSAIC,
+	CCDC_CFA_PAT_STRIPE
+};
+
+enum ccdc_colpats {
+	CCDC_RED,
+	CCDC_GREEN_RED,
+	CCDC_GREEN_BLUE,
+	CCDC_BLUE
+};
+
+struct ccdc_col_pat {
+	enum ccdc_colpats olop;
+	enum ccdc_colpats olep;
+	enum ccdc_colpats elop;
+	enum ccdc_colpats elep;
+};
+
+/*************************************************************************
+**  CCDC Raw configuration parameters
+*************************************************************************/
+enum ccdc_fmt_mode {
+	CCDC_SPLIT,
+	CCDC_COMBINE
+};
+
+enum ccdc_lnum {
+	CCDC_1LINE,
+	CCDC_2LINES,
+	CCDC_3LINES,
+	CCDC_4LINES
+};
+
+enum ccdc_line {
+	CCDC_1STLINE,
+	CCDC_2NDLINE,
+	CCDC_3RDLINE,
+	CCDC_4THLINE
+};
+
+struct ccdc_fmtplen {
+	/**
+	 * number of program entries for SET0, range 1 - 16
+	 * when fmtmode is CCDC_SPLIT, 1 - 8 when fmtmode is
+	 * CCDC_COMBINE
+	 */
+	unsigned short plen0;
+	/**
+	 * number of program entries for SET1, range 1 - 16
+	 * when fmtmode is CCDC_SPLIT, 1 - 8 when fmtmode is
+	 * CCDC_COMBINE
+	 */
+	unsigned short plen1;
+	/**
+	 * number of program entries for SET2, range 1 - 16
+	 * when fmtmode is CCDC_SPLIT, 1 - 8 when fmtmode is
+	 * CCDC_COMBINE
+	 */
+	unsigned short plen2;
+	/**
+	 * number of program entries for SET3, range 1 - 16
+	 * when fmtmode is CCDC_SPLIT, 1 - 8 when fmtmode is
+	 * CCDC_COMBINE
+	 */
+	unsigned short plen3;
+};
+
+struct ccdc_fmt_cfg {
+	/* Split or combine or line alternate */
+	enum ccdc_fmt_mode fmtmode;
+	/* enable or disable line alternating mode */
+	unsigned char ln_alter_en;
+	/* Split/combine line number */
+	enum ccdc_lnum lnum;
+	/* Address increment Range 1 - 16 */
+	unsigned int addrinc;
+};
+
+struct ccdc_fmt_addr_ptr {
+	/* Initial address */
+	unsigned int init_addr;
+	/* output line number */
+	enum ccdc_line out_line;
+};
+
+struct ccdc_fmtpgm_ap {
+	/* program address pointer */
+	unsigned char pgm_aptr;
+	/* program address increment or decrement */
+	unsigned char pgmupdt;
+};
+
+struct ccdc_data_formatter {
+	/* Enable/Disable data formatter */
+	unsigned char en;
+	/* data formatter configuration */
+	struct ccdc_fmt_cfg cfg;
+	/* Formatter program entries length */
+	struct ccdc_fmtplen plen;
+	/* first pixel in a line fed to formatter */
+	unsigned short fmtrlen;
+	/* HD interval for output line. Only valid when split line */
+	unsigned short fmthcnt;
+	/* formatter address pointers */
+	struct ccdc_fmt_addr_ptr fmtaddr_ptr[16];
+	/* program enable/disable */
+	unsigned char pgm_en[32];
+	/* program address pointers */
+	struct ccdc_fmtpgm_ap fmtpgm_ap[32];
+};
+
+struct ccdc_df_csc {
+	/* Color Space Conversion confguration, 0 - csc, 1 - df */
+	unsigned int df_or_csc;
+	/* csc configuration valid if df_or_csc is 0 */
+	struct ccdc_color_space_conv csc;
+	/* data formatter configuration valid if df_or_csc is 1 */
+	struct ccdc_data_formatter df;
+	/* start pixel in a line at the input */
+	unsigned int start_pix;
+	/* number of pixels in input line */
+	unsigned int num_pixels;
+	/* start line at the input */
+	unsigned int start_line;
+	/* number of lines at the input */
+	unsigned int num_lines;
+};
+
+struct ccdc_gain_offsets_adj {
+	/* Enable or Disable Gain adjustment for SDRAM data */
+	unsigned char gain_sdram_en;
+	/* Enable or Disable Gain adjustment for IPIPE data */
+	unsigned char gain_ipipe_en;
+	/* Enable or Disable Gain adjustment for H3A data */
+	unsigned char gain_h3a_en;
+	/* Enable or Disable Gain adjustment for SDRAM data */
+	unsigned char offset_sdram_en;
+	/* Enable or Disable Gain adjustment for IPIPE data */
+	unsigned char offset_ipipe_en;
+	/* Enable or Disable Gain adjustment for H3A data */
+	unsigned char offset_h3a_en;
+};
+
+struct ccdc_cul {
+	/* Horizontal Cull pattern for odd lines */
+	unsigned char hcpat_odd;
+	/* Horizontal Cull pattern for even lines */
+	unsigned char hcpat_even;
+	/* Vertical Cull pattern */
+	unsigned char vcpat;
+	/* Enable or disable lpf. Apply when cull is enabled */
+	unsigned char en_lpf;
+};
+
+/* all the stuff in this struct will be provided by userland */
+struct ccdc_config_params_raw {
+	/* Linearization parameters for image sensor data input */
+	struct ccdc_linearize linearize;
+	/* Data formatter or CSC */
+	struct ccdc_df_csc df_csc;
+	/* Defect Pixel Correction (DFC) confguration */
+	struct ccdc_dfc dfc;
+	/* Black/Digital Clamp configuration */
+	struct ccdc_black_clamp bclamp;
+	/* Gain, offset adjustments */
+	struct ccdc_gain_offsets_adj gain_offset;
+	/* Culling */
+	struct ccdc_cul culling;
+	/* Predictor for DPCM compression */
+	enum ccdc_dpcm_predictor pred;
+	/* horizontal offset for Gain/LSC/DFC */
+	unsigned short horz_offset;
+	/* vertical offset for Gain/LSC/DFC */
+	unsigned short vert_offset;
+};
+
+#define VPFE_CCDC_CID_CRGAIN           (V4L2_CID_USER_BASE | 0xa001)
+#define VPFE_CCDC_CID_CGRGAIN          (V4L2_CID_USER_BASE | 0xa002)
+#define VPFE_CCDC_CID_CGBGAIN          (V4L2_CID_USER_BASE | 0xa003)
+#define VPFE_CCDC_CID_CBGAIN           (V4L2_CID_USER_BASE | 0xa004)
+#define VPFE_CCDC_CID_GAIN_OFFSET      (V4L2_CID_USER_BASE | 0xa005)
+
+/*
+ * Private IOCTL
+ *
+ * VIDIOC_VPFE_CCDC_S_RAW_PARAMS: Set raw params in CCDC
+ * VIDIOC_VPFE_CCDC_G_RAW_PARAMS: Get raw params from CCDC
+ */
+
+#define VIDIOC_VPFE_CCDC_S_RAW_PARAMS \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 6,  struct ccdc_config_params_raw)
+#define VIDIOC_VPFE_CCDC_G_RAW_PARAMS \
+	_IOR('V', BASE_VIDIOC_PRIVATE + 7, struct ccdc_config_params_raw)
+
+#endif
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 05/14] davinci: vpfe: add ccdc driver with media controller interface
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (3 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 04/14] davinci: vpfe: add support for CCDC hardware for dm365 Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 06/14] davinci: vpfe: add v4l2 video driver support Prabhakar Lad
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

Add the CCDC driver for davinci Dm3XX SoCs. The driver supports
CCDC as a media entity with 2 pads - 1 input and 1 output. The
driver implements streaming support and subdev interface. The
ccdc supports bayer and YUV formats.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/ccdc_hw_device.h |   11 +-
 drivers/media/platform/davinci/dm355_ccdc.c     |    2 +-
 drivers/media/platform/davinci/dm644x_ccdc.c    |    2 +-
 drivers/media/platform/davinci/isif.c           |    2 +-
 drivers/media/platform/davinci/vpfe_capture.c   |    2 +-
 drivers/media/platform/davinci/vpfe_ccdc.c      |  903 +++++++++++++++++++++++
 drivers/media/platform/davinci/vpfe_ccdc.h      |   87 +++
 7 files changed, 997 insertions(+), 12 deletions(-)
 create mode 100644 drivers/media/platform/davinci/vpfe_ccdc.c
 create mode 100644 drivers/media/platform/davinci/vpfe_ccdc.h

diff --git a/drivers/media/platform/davinci/ccdc_hw_device.h b/drivers/media/platform/davinci/ccdc_hw_device.h
index 86b9b35..43615d7 100644
--- a/drivers/media/platform/davinci/ccdc_hw_device.h
+++ b/drivers/media/platform/davinci/ccdc_hw_device.h
@@ -57,7 +57,7 @@ struct ccdc_hw_ops {
 	 */
 	int (*get_params) (void *params);
 	/* Pointer to function to configure ccdc */
-	int (*configure) (void);
+	int (*configure) (int mode);
 
 	/* Pointer to function to set buffer type */
 	int (*set_buftype) (enum ccdc_buftype buf_type);
@@ -80,17 +80,12 @@ struct ccdc_hw_ops {
 	/* Pointer to function to get line length */
 	unsigned int (*get_line_length) (void);
 
-	/* Query CCDC control IDs */
-	int (*queryctrl)(struct v4l2_queryctrl *qctrl);
-	/* Set CCDC control */
-	int (*set_control)(struct v4l2_control *ctrl);
-	/* Get CCDC control */
-	int (*get_control)(struct v4l2_control *ctrl);
-
 	/* Pointer to function to set frame buffer address */
 	void (*setfbaddr) (unsigned long addr);
 	/* Pointer to function to get field id */
 	int (*getfid) (void);
+	/* Pointer to function to set_ctrl */
+	int (*set_ctrl) (u32 ctrl_id, s32 val);
 };
 
 struct ccdc_hw_device {
diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c
index ce0e413..c5563fd 100644
--- a/drivers/media/platform/davinci/dm355_ccdc.c
+++ b/drivers/media/platform/davinci/dm355_ccdc.c
@@ -779,7 +779,7 @@ static int ccdc_config_raw(void)
 	return 0;
 }
 
-static int ccdc_configure(void)
+static int ccdc_configure(int mode)
 {
 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 		return ccdc_config_raw();
diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c
index ee7942b..e51776a 100644
--- a/drivers/media/platform/davinci/dm644x_ccdc.c
+++ b/drivers/media/platform/davinci/dm644x_ccdc.c
@@ -689,7 +689,7 @@ void ccdc_config_raw(void)
 	ccdc_readregs();
 }
 
-static int ccdc_configure(void)
+static int ccdc_configure(int mode)
 {
 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 		ccdc_config_raw();
diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c
index b99d542..3e4fe87 100644
--- a/drivers/media/platform/davinci/isif.c
+++ b/drivers/media/platform/davinci/isif.c
@@ -993,7 +993,7 @@ static int isif_config_ycbcr(void)
 	return 0;
 }
 
-static int isif_configure(void)
+static int isif_configure(int mode)
 {
 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
 		return isif_config_raw();
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index 843b138..59cafa8 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -1572,7 +1572,7 @@ static int vpfe_streamon(struct file *file, void *priv,
 		ret = -EFAULT;
 		goto unlock_out;
 	}
-	if (ccdc_dev->hw_ops.configure() < 0) {
+	if (ccdc_dev->hw_ops.configure(0) < 0) {
 		v4l2_err(&vpfe_dev->v4l2_dev,
 			 "Error in configuring ccdc\n");
 		ret = -EINVAL;
diff --git a/drivers/media/platform/davinci/vpfe_ccdc.c b/drivers/media/platform/davinci/vpfe_ccdc.c
new file mode 100644
index 0000000..fdc0aa4
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_ccdc.c
@@ -0,0 +1,903 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-device.h>
+#include <media/media-entity.h>
+#include <media/davinci/vpfe_types.h>
+
+#include "vpfe_mc_capture.h"
+#include "ccdc_hw_device.h"
+
+#define MAX_WIDTH	4096
+#define MAX_HEIGHT	4096
+
+static const unsigned int ccdc_fmts[] = {
+	V4L2_MBUS_FMT_YUYV8_2X8,
+	V4L2_MBUS_FMT_UYVY8_2X8,
+	V4L2_MBUS_FMT_YUYV8_1X16,
+	V4L2_MBUS_FMT_YUYV10_1X20,
+	V4L2_MBUS_FMT_SGRBG12_1X12,
+	V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8,
+#ifdef CONFIG_ARCH_DAVINCI_DM365
+	V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+#endif
+};
+
+/*
+ * CCDC helper functions
+ */
+
+/* get field id in ccdc hardware */
+enum v4l2_field ccdc_get_fid(struct vpfe_device *vpfe_dev)
+{
+	struct vpfe_ccdc_device *ccdc = &vpfe_dev->vpfe_ccdc;
+	struct ccdc_hw_device *ccdc_dev = ccdc->ccdc_dev;
+
+	return ccdc_dev->hw_ops.getfid();
+}
+
+/* Retrieve active or try pad format based on query */
+static struct v4l2_mbus_framefmt *
+__ccdc_get_format(struct vpfe_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+		  unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY) {
+		struct v4l2_subdev_format fmt;
+
+		fmt.pad = pad;
+		fmt.which = which;
+
+		return v4l2_subdev_get_try_format(fh, pad);
+	}
+	return &ccdc->formats[pad];
+}
+
+/* configure format in ccdc hardware */
+static int
+vpfe_config_ccdc_format(struct vpfe_device *vpfe_dev, unsigned int pad)
+{
+	struct ccdc_hw_device *ccdc_dev = vpfe_dev->vpfe_ccdc.ccdc_dev;
+	struct vpfe_ccdc_device *vpfe_ccdc = &vpfe_dev->vpfe_ccdc;
+	enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
+	struct v4l2_pix_format format;
+	int ret = 0;
+
+	v4l2_fill_pix_format(&format, &vpfe_dev->vpfe_ccdc.formats[pad]);
+	mbus_to_pix(&vpfe_dev->vpfe_ccdc.formats[pad], &format);
+
+	if (ccdc_dev->hw_ops.set_pixel_format(
+			format.pixelformat) < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"Failed to set pix format in ccdc\n");
+		return -EINVAL;
+	}
+
+	/* call for s_crop will override these values */
+	vpfe_ccdc->crop.left = 0;
+	vpfe_ccdc->crop.top = 0;
+	vpfe_ccdc->crop.width = format.width;
+	vpfe_ccdc->crop.height = format.height;
+
+	/* configure the image window */
+	ccdc_dev->hw_ops.set_image_window(&vpfe_ccdc->crop);
+
+	switch (vpfe_dev->vpfe_ccdc.formats[pad].field) {
+	case V4L2_FIELD_INTERLACED:
+		/* do nothing, since it is default */
+		ret = ccdc_dev->hw_ops.set_buftype(
+				CCDC_BUFTYPE_FLD_INTERLEAVED);
+		break;
+	case V4L2_FIELD_NONE:
+		frm_fmt = CCDC_FRMFMT_PROGRESSIVE;
+		/* buffer type only applicable for interlaced scan */
+		break;
+	case V4L2_FIELD_SEQ_TB:
+		ret = ccdc_dev->hw_ops.set_buftype(
+				CCDC_BUFTYPE_FLD_SEPARATED);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set the frame format */
+	if (!ret)
+		ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt);
+
+	return ret;
+}
+
+/*
+ * ccdc_try_format() - Try video format on a pad
+ * @ccdc: VPFE CCDC device
+ * @fh : V4L2 subdev file handle
+ * @pad: Pad number
+ * @fmt: Format
+ */
+static void
+ccdc_try_format(struct vpfe_ccdc_device *vpfe_ccdc, struct v4l2_subdev_fh *fh,
+		struct v4l2_subdev_format *fmt)
+{
+	unsigned int width = fmt->format.width;
+	unsigned int height = fmt->format.height;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) {
+		if (fmt->format.code == ccdc_fmts[i])
+			break;
+	}
+
+	/* If not found, use YUYV8_2x8 as default */
+	if (i >= ARRAY_SIZE(ccdc_fmts))
+		fmt->format.code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+	/* Clamp the size. */
+	fmt->format.width = clamp_t(u32, width, 32, MAX_WIDTH);
+	fmt->format.height = clamp_t(u32, height, 32, MAX_HEIGHT);
+
+	/* The data formatter truncates the number of horizontal output
+	* pixels to a multiple of 16. To avoid clipping data, allow
+	* callers to request an output size bigger than the input size
+	* up to the nearest multiple of 16.
+	*/
+	if (fmt->pad == CCDC_PAD_SOURCE)
+		fmt->format.width &= ~15;
+}
+
+/*
+ * ccdc_buffer_isr() - CCDC module non-progressive buffer scheduling isr
+ * @ccdc: CCDC device pointer
+ *
+ */
+void ccdc_buffer_isr(struct vpfe_ccdc_device *ccdc)
+{
+	struct vpfe_video_device *video = &ccdc->video_out;
+	struct ccdc_hw_device *ccdc_dev = ccdc->ccdc_dev;
+	enum v4l2_field field;
+	int fid;
+
+	if (!video->started)
+		return;
+
+	field = video->fmt.fmt.pix.field;
+
+	/* reset sbl overblow bit */
+	if (ccdc_dev->hw_ops.reset != NULL)
+		ccdc_dev->hw_ops.reset();
+
+	if (field == V4L2_FIELD_NONE) {
+		/* handle progressive frame capture */
+		if (video->cur_frm != video->next_frm)
+			vpfe_process_buffer_complete(video);
+		return;
+	}
+
+	/* interlaced or TB capture check which field we
+	  * are in hardware
+	  */
+	fid = ccdc_dev->hw_ops.getfid();
+
+	/* switch the software maintained field id */
+	video->field_id ^= 1;
+	if (fid == video->field_id) {
+		/* we are in-sync here,continue */
+		if (fid == 0) {
+			/*
+			  * One frame is just being captured. If the
+			  * next frame is available, release the current
+			  * frame and move on
+			  */
+			if (video->cur_frm != video->next_frm)
+				vpfe_process_buffer_complete(video);
+			/*
+			  * based on whether the two fields are stored
+			  * interleavely or separately in memory,
+			  * reconfigure the CCDC memory address
+			  */
+			if (field == V4L2_FIELD_SEQ_TB)
+				vpfe_schedule_bottom_field(video);
+
+			return;
+		}
+		/*
+		  * if one field is just being captured configure
+		  * the next frame get the next frame from the
+		  * empty queue if no frame is available hold on
+		  * to the current buffer
+		  */
+		spin_lock(&video->dma_queue_lock);
+		if (!list_empty(&video->dma_queue) &&
+		video->cur_frm == video->next_frm)
+			vpfe_schedule_next_buffer(video);
+		spin_unlock(&video->dma_queue_lock);
+	} else if (fid == 0) {
+		/*
+		  * out of sync. Recover from any hardware out-of-sync.
+		  * May loose one frame
+		  */
+		video->field_id = fid;
+	}
+}
+
+/*
+ * ccdc_vidint1_isr() - CCDC module progressive buffer scheduling isr
+ * @ccdc: CCDC device pointer
+ *
+ */
+void ccdc_vidint1_isr(struct vpfe_ccdc_device *ccdc)
+{
+	struct vpfe_video_device *video = &ccdc->video_out;
+
+	if (!video->started)
+		return;
+
+	spin_lock(&video->dma_queue_lock);
+	if (video->fmt.fmt.pix.field == V4L2_FIELD_NONE &&
+	    !list_empty(&video->dma_queue) && video->cur_frm == video->next_frm)
+		vpfe_schedule_next_buffer(video);
+
+	spin_unlock(&video->dma_queue_lock);
+}
+
+/*
+ * VPFE video operations
+ */
+
+static void ccdc_video_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
+{
+	struct vpfe_ccdc_device *vpfe_ccdc = &vpfe_dev->vpfe_ccdc;
+	struct ccdc_hw_device *ccdc_dev = vpfe_ccdc->ccdc_dev;
+
+	ccdc_dev->hw_ops.setfbaddr(addr);
+}
+
+static const struct vpfe_video_operations ccdc_video_ops = {
+	.queue = ccdc_video_queue,
+};
+
+
+/*
+ * V4L2 subdev operations
+ */
+
+/*
+ * ccdc_ioctl() - CCDC module private ioctl's
+ * @sd: VPFE CCDC V4L2 subdevice
+ * @cmd: ioctl command
+ * @arg: ioctl argument
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct vpfe_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct ccdc_hw_device *ccdc_dev = ccdc->ccdc_dev;
+	int ret;
+
+	switch (cmd) {
+	case VIDIOC_VPFE_CCDC_S_RAW_PARAMS:
+		ret = ccdc_dev->hw_ops.set_params(arg);
+		break;
+	case VIDIOC_VPFE_CCDC_G_RAW_PARAMS:
+		ret = ccdc_dev->hw_ops.get_params(arg);
+		break;
+
+	default:
+		ret = -ENOIOCTLCMD;
+	}
+
+	return ret;
+}
+
+/*
+ * ccdc_set_stream() - Enable/Disable streaming on the CCDC module
+ * @sd: VPFE CCDC V4L2 subdevice
+ * @enable: Enable/disable stream
+ */
+static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct vpfe_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct ccdc_hw_device *ccdc_dev = ccdc->ccdc_dev;
+	int ret;
+
+	if (enable) {
+		ret = ccdc_dev->hw_ops.configure(
+		(ccdc->output == CCDC_OUTPUT_MEMORY) ? 0 : 1);
+		if (ret)
+			return ret;
+
+		if ((ccdc_dev->hw_ops.enable_out_to_sdram) &&
+			(ccdc->output == CCDC_OUTPUT_MEMORY))
+			ccdc_dev->hw_ops.enable_out_to_sdram(1);
+
+		ccdc_dev->hw_ops.enable(1);
+	} else {
+
+		ccdc_dev->hw_ops.enable(0);
+
+		if (ccdc_dev->hw_ops.enable_out_to_sdram)
+			ccdc_dev->hw_ops.enable_out_to_sdram(0);
+	}
+
+	return 0;
+}
+
+/*
+* ccdc_set_format() - set format on pad
+* @sd    : VPFE ccdc device
+* @fh    : V4L2 subdev file handle
+* @fmt   : pointer to v4l2 subdev format structure
+*
+* Return 0 on success or -EINVAL if format or pad is invalid
+*/
+static int
+ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+		struct v4l2_subdev_format *fmt)
+{
+	struct vpfe_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct vpfe_device *vpfe_dev = to_vpfe_device(ccdc);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	ccdc_try_format(ccdc, fh, fmt);
+	memcpy(format, &fmt->format, sizeof(*format));
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	if (fmt->pad == CCDC_PAD_SOURCE)
+		return vpfe_config_ccdc_format(vpfe_dev, fmt->pad);
+
+	return 0;
+}
+
+/*
+ * ccdc_get_format() - Retrieve the video format on a pad
+ * @sd : VPFE CCDC V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int
+ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+		struct v4l2_subdev_format *fmt)
+{
+	struct vpfe_ccdc_device *vpfe_ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __ccdc_get_format(vpfe_ccdc, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	memcpy(&fmt->format, format, sizeof(fmt->format));
+
+	return 0;
+}
+
+/*
+ * ccdc_enum_frame_size() - enum frame sizes on pads
+ * @sd: VPFE ccdc V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @code: pointer to v4l2_subdev_frame_size_enum structure
+ */
+static int
+ccdc_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+		     struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct vpfe_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_subdev_format format;
+
+	if (fse->index != 0)
+		return -EINVAL;
+
+	format.pad = fse->pad;
+	format.format.code = fse->code;
+	format.format.width = 1;
+	format.format.height = 1;
+	format.which = V4L2_SUBDEV_FORMAT_TRY;
+	ccdc_try_format(ccdc, fh, &format);
+	fse->min_width = format.format.width;
+	fse->min_height = format.format.height;
+
+	if (format.format.code != fse->code)
+		return -EINVAL;
+
+	format.pad = fse->pad;
+	format.format.code = fse->code;
+	format.format.width = -1;
+	format.format.height = -1;
+	format.which = V4L2_SUBDEV_FORMAT_TRY;
+	ccdc_try_format(ccdc, fh, &format);
+	fse->max_width = format.format.width;
+	fse->max_height = format.format.height;
+
+	return 0;
+}
+
+/*
+ * ccdc_enum_mbus_code() - enum mbus codes for pads
+ * @sd: VPFE ccdc V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @code: pointer to v4l2_subdev_mbus_code_enum structure
+ */
+static int
+ccdc_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+		    struct v4l2_subdev_mbus_code_enum *code)
+{
+	switch (code->pad) {
+	case CCDC_PAD_SINK:
+	case CCDC_PAD_SOURCE:
+		if (code->index >= ARRAY_SIZE(ccdc_fmts))
+			return -EINVAL;
+
+		code->code = ccdc_fmts[code->index];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * ccdc_pad_set_crop() - set crop rectangle on pad
+ * @sd: VPFE ccdc V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @code: pointer to v4l2_subdev_mbus_code_enum structure
+ *
+ * Return 0 on success, -EINVAL if pad is invalid
+ */
+static int
+ccdc_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+		  struct v4l2_subdev_crop *crop)
+{
+	struct vpfe_ccdc_device *vpfe_ccdc = v4l2_get_subdevdata(sd);
+	struct ccdc_hw_device *ccdc_dev = vpfe_ccdc->ccdc_dev;
+	struct v4l2_mbus_framefmt *format;
+
+	/* check wether its a valid pad */
+	if (crop->pad != CCDC_PAD_SINK)
+		return -EINVAL;
+
+	format = __ccdc_get_format(vpfe_ccdc, fh, crop->pad, crop->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	/* check wether crop rect is within limits */
+	if (crop->rect.top < 0 || crop->rect.left < 0 ||
+		(crop->rect.left + crop->rect.width >
+		vpfe_ccdc->formats[CCDC_PAD_SINK].width) ||
+		(crop->rect.top + crop->rect.height >
+			vpfe_ccdc->formats[CCDC_PAD_SINK].height)) {
+		crop->rect.left = 0;
+		crop->rect.top = 0;
+		crop->rect.width = format->width;
+		crop->rect.height = format->height;
+	}
+
+	/* adjust the width to 16 pixel boundry */
+	crop->rect.width = ((crop->rect.width + 15) & ~0xf);
+
+	vpfe_ccdc->crop = crop->rect;
+
+	if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		ccdc_dev->hw_ops.set_image_window(&vpfe_ccdc->crop);
+	} else {
+		struct v4l2_rect *rect;
+
+		rect = v4l2_subdev_get_try_crop(fh, CCDC_PAD_SINK);
+		memcpy(rect, &vpfe_ccdc->crop, sizeof(*rect));
+	}
+
+	return 0;
+}
+
+/*
+ * ccdc_pad_get_crop() - get crop rectangle on pad
+ * @sd: VPFE ccdc V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @code: pointer to v4l2_subdev_mbus_code_enum structure
+ *
+ * Return 0 on success, -EINVAL if pad is invalid
+ */
+static int
+ccdc_pad_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+		  struct v4l2_subdev_crop *crop)
+{
+	struct vpfe_ccdc_device *vpfe_ccdc = v4l2_get_subdevdata(sd);
+
+	/* check wether its a valid pad */
+	if (crop->pad != CCDC_PAD_SINK)
+		return -EINVAL;
+
+	if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
+		struct v4l2_rect *rect;
+		rect = v4l2_subdev_get_try_crop(fh, CCDC_PAD_SINK);
+		memcpy(&crop->rect, rect, sizeof(*rect));
+	} else {
+		crop->rect = vpfe_ccdc->crop;
+	}
+
+	return 0;
+}
+
+/*
+ * ccdc_init_formats() - Initialize formats on all pads
+ * @sd: VPFE ccdc V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int
+ccdc_init_formats(struct v4l2_subdev *sd,
+		  struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_subdev_format format;
+	struct v4l2_subdev_crop crop;
+
+	memset(&format, 0, sizeof(format));
+	format.pad = CCDC_PAD_SINK;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+	format.format.width = MAX_WIDTH;
+	format.format.height = MAX_HEIGHT;
+	ccdc_set_format(sd, fh, &format);
+
+	memset(&format, 0, sizeof(format));
+	format.pad = CCDC_PAD_SOURCE;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+	format.format.width = MAX_WIDTH;
+	format.format.height = MAX_HEIGHT;
+	ccdc_set_format(sd, fh, &format);
+
+	memset(&crop, 0, sizeof(crop));
+	crop.pad = CCDC_PAD_SINK;
+	crop.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	crop.rect.width = MAX_WIDTH;
+	crop.rect.height = MAX_HEIGHT;
+	ccdc_pad_set_crop(sd, fh, &crop);
+
+	return 0;
+}
+
+/* subdev core operations */
+static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = {
+	.ioctl = ccdc_ioctl,
+};
+
+/* subdev file operations */
+static const struct v4l2_subdev_internal_ops ccdc_v4l2_internal_ops = {
+	.open = ccdc_init_formats,
+};
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = {
+	.s_stream = ccdc_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
+	.enum_mbus_code = ccdc_enum_mbus_code,
+	.enum_frame_size = ccdc_enum_frame_size,
+	.get_fmt = ccdc_get_format,
+	.set_fmt = ccdc_set_format,
+	.set_crop = ccdc_pad_set_crop,
+	.get_crop = ccdc_pad_get_crop,
+};
+
+/* v4l2 subdev operations */
+static const struct v4l2_subdev_ops ccdc_v4l2_ops = {
+	.core = &ccdc_v4l2_core_ops,
+	.video = &ccdc_v4l2_video_ops,
+	.pad = &ccdc_v4l2_pad_ops,
+};
+
+/*
+ * Media entity operations
+ */
+
+/*
+ * ccdc_link_setup() - Setup CCDC connections
+ * @entity: CCDC media entity
+ * @local: Pad at the local end of the link
+ * @remote: Pad at the remote end of the link
+ * @flags: Link flags
+ *
+ * return -EINVAL or zero on success
+ */
+static int
+ccdc_link_setup(struct media_entity *entity, const struct media_pad *local,
+		const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct vpfe_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+
+	switch (local->index | media_entity_type(remote->entity)) {
+	case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* read from decoder/sensor */
+		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+			ccdc->input = CCDC_INPUT_NONE;
+			break;
+		}
+
+		if (ccdc->input != CCDC_INPUT_NONE)
+			return -EBUSY;
+
+		ccdc->input = CCDC_INPUT_PARALLEL;
+
+		break;
+
+	case CCDC_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+		/* write to memory */
+		if (flags & MEDIA_LNK_FL_ENABLED)
+			ccdc->output = CCDC_OUTPUT_MEMORY;
+		else
+			ccdc->output = CCDC_OUTPUT_NONE;
+		break;
+
+	case CCDC_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+		if (flags & MEDIA_LNK_FL_ENABLED)
+			ccdc->output = CCDC_OUTPUT_PREVIEWER;
+		else
+			ccdc->output = CCDC_OUTPUT_NONE;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+static const struct media_entity_operations ccdc_media_ops = {
+	.link_setup = ccdc_link_setup,
+};
+
+/*
+ * vpfe_ccdc_unregister_entities() - CCDC subdevs/video
+ * driver unregistrations.
+ * @ccdc - pointer to ccdc subdevice structure.
+ */
+void vpfe_ccdc_unregister_entities(struct vpfe_ccdc_device *ccdc)
+{
+	struct ccdc_hw_device *ccdc_dev = ccdc->ccdc_dev;
+	struct device *dev = ccdc->subdev.v4l2_dev->dev;
+
+	vpfe_video_unregister(&ccdc->video_out);
+
+	if (ccdc_dev->hw_ops.close)
+		ccdc_dev->hw_ops.close(dev);
+
+	/* cleanup entity */
+	media_entity_cleanup(&ccdc->subdev.entity);
+	/* unregister subdev */
+	v4l2_device_unregister_subdev(&ccdc->subdev);
+}
+
+/*
+ * vpfe_ccdc_register_entities() - CCDC subdevs/video
+ * driver registrations.
+ * @ccdc - pointer to ccdc subdevice structure.
+ * @vdev: pointer to v4l2 device structure.
+ */
+int vpfe_ccdc_register_entities(struct vpfe_ccdc_device *ccdc,
+			    struct v4l2_device *vdev)
+{
+	struct ccdc_hw_device *ccdc_dev = NULL;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(ccdc);
+	struct device *dev = vdev->dev;
+	unsigned int flags;
+	int ret;
+
+	/* Register the subdev */
+	ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
+	if (ret < 0)
+		return ret;
+
+	ccdc_dev = ccdc->ccdc_dev;
+
+	ret = ccdc_dev->hw_ops.open(dev);
+	if (ret)
+		goto out_ccdc_open;
+
+	ret = vpfe_video_register(&ccdc->video_out, vdev);
+	if (ret) {
+		pr_err("Failed to register ccdc video out device\n");
+		goto out_video_register;
+	}
+
+	ccdc->video_out.vpfe_dev = vpfe_dev;
+
+	flags = 0;
+	/* connect ccdc to video node */
+	ret = media_entity_create_link(&ccdc->subdev.entity, 1,
+				       &ccdc->video_out.video_dev.entity,
+				       0, flags);
+	if (ret < 0)
+		goto out_create_link;
+
+	return 0;
+out_create_link:
+	vpfe_video_unregister(&ccdc->video_out);
+out_video_register:
+	if (ccdc_dev->hw_ops.close)
+		ccdc_dev->hw_ops.close(dev);
+
+out_ccdc_open:
+	v4l2_device_unregister_subdev(&ccdc->subdev);
+
+	return ret;
+}
+
+/* -------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+static int vpfe_ccdc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vpfe_ccdc_device *ccdc =
+		container_of(ctrl->handler, struct vpfe_ccdc_device, ctrls);
+	struct ccdc_hw_device *ccdc_dev = ccdc->ccdc_dev;
+
+	return ccdc_dev->hw_ops.set_ctrl(ctrl->id, ctrl->val);
+
+}
+
+static struct v4l2_ctrl_ops vpfe_ccdc_ctrl_ops = {
+	.s_ctrl = vpfe_ccdc_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vpfe_ccdc_crgain = {
+	.ops = &vpfe_ccdc_ctrl_ops,
+	.id = VPFE_CCDC_CID_CRGAIN,
+	.name = "CRGAIN",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = (1 << 12) - 1,
+	.step = 1,
+	.def = 0,
+};
+
+static const struct v4l2_ctrl_config vpfe_ccdc_cgrgain = {
+	.ops = &vpfe_ccdc_ctrl_ops,
+	.id = VPFE_CCDC_CID_CGRGAIN,
+	.name = "CGRGAIN",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = (1 << 12) - 1,
+	.step = 1,
+	.def = 0,
+};
+
+static const struct v4l2_ctrl_config vpfe_ccdc_cgbgain = {
+	.ops = &vpfe_ccdc_ctrl_ops,
+	.id = VPFE_CCDC_CID_CGBGAIN,
+	.name = "CGBGAIN",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = (1 << 12) - 1,
+	.step = 1,
+	.def = 0,
+};
+
+static const struct v4l2_ctrl_config vpfe_ccdc_cbgain = {
+	.ops = &vpfe_ccdc_ctrl_ops,
+	.id = VPFE_CCDC_CID_CBGAIN,
+	.name = "CBGAIN",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = (1 << 12) - 1,
+	.step = 1,
+	.def = 0,
+};
+
+static const struct v4l2_ctrl_config vpfe_ccdc_gain_offset = {
+	.ops = &vpfe_ccdc_ctrl_ops,
+	.id = VPFE_CCDC_CID_GAIN_OFFSET,
+	.name = "Gain Offset",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = (1 << 12) - 1,
+	.step = 1,
+	.def = 0,
+};
+
+/*
+ * vpfe_ccdc_init() - Initialize V4L2 subdev and media entity
+ * @ccdc: VPFE CCDC module
+ *
+ * Return 0 on success and a negative error code on failure.
+ */
+int vpfe_ccdc_init(struct vpfe_ccdc_device *ccdc, struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = &ccdc->subdev;
+	struct media_pad *pads = &ccdc->pads[0];
+	struct media_entity *me = &sd->entity;
+	int ret;
+
+	if (ccdc_init(pdev)) {
+		pr_err("vpfe_ccdc_init: Init failed\n");
+		return -EINVAL;
+	}
+
+	/* queue ops */
+	ccdc->video_out.ops = &ccdc_video_ops;
+
+	v4l2_subdev_init(sd, &ccdc_v4l2_ops);
+	sd->internal_ops = &ccdc_v4l2_internal_ops;
+	strlcpy(sd->name, "DAVINCI CCDC", sizeof(sd->name));
+	sd->grp_id = 1 << 16;	/* group ID for davinci subdevs */
+	v4l2_set_subdevdata(sd, ccdc);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+	pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	pads[CCDC_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	ccdc->input = CCDC_INPUT_NONE;
+	ccdc->output = CCDC_OUTPUT_NONE;
+
+	me->ops = &ccdc_media_ops;
+	ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0);
+	if (ret)
+		goto out_davanci_init;
+	ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	ret = vpfe_video_init(&ccdc->video_out, "CCDC");
+	if (ret) {
+		pr_err("Failed to init ccdc-out video device\n");
+		goto out_davanci_init;
+	}
+
+	ccdc->ccdc_dev = get_ccdc_dev();
+	v4l2_ctrl_handler_init(&ccdc->ctrls, 5);
+	v4l2_ctrl_new_custom(&ccdc->ctrls, &vpfe_ccdc_crgain, NULL);
+	v4l2_ctrl_new_custom(&ccdc->ctrls, &vpfe_ccdc_cgrgain, NULL);
+	v4l2_ctrl_new_custom(&ccdc->ctrls, &vpfe_ccdc_cgbgain, NULL);
+	v4l2_ctrl_new_custom(&ccdc->ctrls, &vpfe_ccdc_cbgain, NULL);
+	v4l2_ctrl_new_custom(&ccdc->ctrls, &vpfe_ccdc_gain_offset, NULL);
+
+	v4l2_ctrl_handler_setup(&ccdc->ctrls);
+	sd->ctrl_handler = &ccdc->ctrls;
+
+	return 0;
+
+out_davanci_init:
+	v4l2_ctrl_handler_free(&ccdc->ctrls);
+	ccdc_remove(pdev);
+	return ret;
+}
+
+/*
+ * vpfe_ccdc_cleanup - CCDC module cleanup.
+ * @dev: Device pointer specific to the VPFE.
+ */
+void vpfe_ccdc_cleanup(struct platform_device *pdev)
+{
+	ccdc_remove(pdev);
+}
diff --git a/drivers/media/platform/davinci/vpfe_ccdc.h b/drivers/media/platform/davinci/vpfe_ccdc.h
new file mode 100644
index 0000000..23f78d0
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_ccdc.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _VPFE_CCDC_H
+#define _VPFE_CCDC_H
+
+#include <media/v4l2-ctrls.h>
+
+#ifdef CONFIG_ARCH_DAVINCI_DM365
+#include "dm365_ccdc.h"
+#endif
+
+#ifdef CONFIG_ARCH_DAVINCI_DM355
+#include "dm355_ccdc.h"
+#endif
+
+#ifdef CONFIG_ARCH_DAVINCI_DM644x
+#include "dm644x_ccdc.h"
+#endif
+
+#define CCDC_PAD_SINK      0
+#define CCDC_PAD_SOURCE    1
+
+#define CCDC_PADS_NUM      2
+
+#define DAVINCI_CCDC_NEVENTS 0
+
+enum ccdc_input_entity {
+	CCDC_INPUT_NONE,
+	CCDC_INPUT_PARALLEL,
+};
+
+#define CCDC_OUTPUT_NONE	(0)
+#define CCDC_OUTPUT_MEMORY	(1 << 0)
+#define CCDC_OUTPUT_RESIZER	(1 << 1)
+#define CCDC_OUTPUT_PREVIEWER	(1 << 2)
+
+#define CCDC_NOT_CHAINED	0
+#define CCDC_CHAINED		1
+
+struct vpfe_ccdc_device {
+	struct v4l2_subdev		subdev;
+	struct media_pad		pads[CCDC_PADS_NUM];
+	struct v4l2_mbus_framefmt	formats[CCDC_PADS_NUM];
+	enum ccdc_input_entity		input;
+	unsigned int			output;
+	struct v4l2_ctrl_handler        ctrls;
+	struct ccdc_hw_device		*ccdc_dev;
+	struct v4l2_rect		crop;
+
+	/* independent video device */
+	struct vpfe_video_device	video_out;
+};
+
+enum v4l2_field ccdc_get_fid(struct vpfe_device *vpfe_dev);
+void ccdc_remove(struct platform_device *pdev);
+int ccdc_init(struct platform_device *pdev);
+struct ccdc_hw_device *get_ccdc_dev(void);
+
+void vpfe_ccdc_unregister_entities(struct vpfe_ccdc_device *ccdc);
+int vpfe_ccdc_register_entities(struct vpfe_ccdc_device *ccdc,
+				struct v4l2_device *v4l2_dev);
+int vpfe_ccdc_init(struct vpfe_ccdc_device *vpfe_ccdc,
+			struct platform_device *pdev);
+void vpfe_ccdc_cleanup(struct platform_device *pdev);
+void ccdc_vidint1_isr(struct vpfe_ccdc_device *ccdc);
+void ccdc_buffer_isr(struct vpfe_ccdc_device *ccdc);
+
+#endif
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 06/14] davinci: vpfe: add v4l2 video driver support
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (4 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 05/14] davinci: vpfe: add ccdc driver with media controller interface Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 13:30   ` Hans Verkuil
  2012-09-14 12:46 ` [PATCH 07/14] davinci: vpfe: v4l2 capture driver with media interface Prabhakar Lad
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

add a generic video driver functionality to be used by all the vpfe
drivers for davinci SoCs. The functionality includes all the
standard v4l2 interfaces including streaming. The video node
interface can be used both as an input and output node for both
continuous and single shot modes.Also supports dv_presets to include
HD modes, wth support for both user pointer IO and mmap.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/vpfe_video.c | 1725 +++++++++++++++++++++++++++
 drivers/media/platform/davinci/vpfe_video.h |  150 +++
 2 files changed, 1875 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/platform/davinci/vpfe_video.c
 create mode 100644 drivers/media/platform/davinci/vpfe_video.h

diff --git a/drivers/media/platform/davinci/vpfe_video.c b/drivers/media/platform/davinci/vpfe_video.c
new file mode 100644
index 0000000..2e696a0
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_video.c
@@ -0,0 +1,1725 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-mediabus.h>
+#include <media/media-entity.h>
+#include <media/media-device.h>
+#include <media/davinci/vpfe_types.h>
+
+#include <mach/cputype.h>
+
+#include "vpfe_mc_capture.h"
+#include "ccdc_hw_device.h"
+
+/* minimum number of buffers needed in cont-mode */
+#define CONT_MIN_NUM_BUFFERS	3
+
+static int debug;
+
+/* get v4l2 subdev pointer to external subdev which is active */
+static struct media_entity *vpfe_get_input_entity
+			(struct vpfe_video_device *video)
+{
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct media_pad *remote;
+
+	remote = media_entity_remote_source(&vpfe_dev->vpfe_ccdc.pads[0]);
+	if (remote == NULL) {
+		pr_err("Invalid media connection to ccdc\n");
+		return NULL;
+	}
+
+	return remote->entity;
+}
+
+/* updates external subdev(sensor/decoder) which is active */
+static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video)
+{
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_config *vpfe_cfg;
+	struct v4l2_subdev *subdev;
+	struct media_pad *remote;
+	int i;
+
+	remote = media_entity_remote_source(&vpfe_dev->vpfe_ccdc.pads[0]);
+	if (remote == NULL) {
+		pr_err("Invalid media connection to ccdc\n");
+		return -EINVAL;
+	}
+
+	subdev = media_entity_to_v4l2_subdev(remote->entity);
+
+	vpfe_cfg = vpfe_dev->pdev->platform_data;
+
+	for (i = 0; i < vpfe_cfg->num_subdevs; i++) {
+		if (!strcmp(vpfe_cfg->sub_devs[i].module_name, subdev->name)) {
+			video->current_ext_subdev = &vpfe_cfg->sub_devs[i];
+			break;
+		}
+	}
+
+	/* if user not linked decoder/sensor to ccdc */
+	if (i == vpfe_cfg->num_subdevs) {
+		pr_err("Invalid media chain connection to ccdc\n");
+		return -EINVAL;
+	}
+
+	/* find the v4l2 subdev pointer */
+	for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) {
+		if (!strcmp(video->current_ext_subdev->module_name,
+			vpfe_dev->sd[i]->name))
+			video->current_ext_subdev->subdev = vpfe_dev->sd[i];
+	}
+
+	return 0;
+}
+
+/* get the subdev which is connected to the output video node */
+static struct v4l2_subdev *
+vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad)
+{
+	struct media_pad *remote;
+
+	remote = media_entity_remote_source(&video->pad);
+
+	if (remote == NULL || remote->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
+		return NULL;
+
+	if (pad)
+		*pad = remote->index;
+
+	return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+/* get the format set at ouput pad of the adjacent subdev */
+static int
+__vpfe_video_get_format(struct vpfe_video_device *video,
+			struct v4l2_format *format)
+{
+	struct v4l2_subdev_format fmt;
+	struct v4l2_subdev *subdev;
+	struct media_pad *remote;
+	u32 pad;
+	int ret;
+
+	subdev = vpfe_video_remote_subdev(video, &pad);
+	if (subdev == NULL)
+		return -EINVAL;
+
+	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	remote = media_entity_remote_source(&video->pad);
+	fmt.pad = remote->index;
+
+	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+	if (ret == -ENOIOCTLCMD)
+		return -EINVAL;
+
+	format->type = video->type;
+	/* convert mbus_format to v4l2_format */
+	v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
+	mbus_to_pix(&fmt.format, &format->fmt.pix);
+
+	return 0;
+}
+
+/* make a note of pipeline details */
+static void vpfe_prepare_pipeline(struct vpfe_video_device *video)
+{
+	struct media_entity *entity = &video->video_dev.entity;
+	struct media_device *mdev = entity->parent;
+	struct vpfe_pipeline *pipe = &video->pipe;
+	struct vpfe_video_device *far_end = NULL;
+	struct media_entity_graph graph;
+
+	pipe->input_num = 0;
+	pipe->output_num = 0;
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		pipe->inputs[pipe->input_num++] = video;
+	else
+		pipe->outputs[pipe->output_num++] = video;
+
+	mutex_lock(&mdev->graph_mutex);
+	media_entity_graph_walk_start(&graph, entity);
+
+	while ((entity = media_entity_graph_walk_next(&graph))) {
+		if (entity == &video->video_dev.entity)
+			continue;
+
+		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+			continue;
+
+		far_end = to_vpfe_video(media_entity_to_video_device(entity));
+
+		if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			pipe->inputs[pipe->input_num++] = far_end;
+		else
+			pipe->outputs[pipe->output_num++] = far_end;
+	}
+
+	mutex_unlock(&mdev->graph_mutex);
+}
+
+/* update pipe state selected by user */
+static int vpfe_update_pipe_state(struct vpfe_video_device *video)
+{
+	struct vpfe_pipeline *pipe = &video->pipe;
+	int ret;
+
+	vpfe_prepare_pipeline(video);
+
+	/* Find out if there is any input video
+	  if yes, it is single shot.
+	*/
+	if (pipe->input_num == 0) {
+		pipe->state = VPFE_PIPELINE_STREAM_CONTINUOUS;
+		ret = vpfe_update_current_ext_subdev(video);
+		if (ret) {
+			pr_err("Invalid external subdev\n");
+			return ret;
+		}
+	} else {
+		pipe->state = VPFE_PIPELINE_STREAM_SINGLESHOT;
+	}
+
+	video->initialized = 1;
+	video->skip_frame_count = 1;
+	video->skip_frame_count_init = 1;
+
+	return 0;
+}
+
+/* checks wether pipeline is ready for enabling */
+int is_pipe_ready(struct vpfe_pipeline *pipe)
+{
+	int i;
+
+	for (i = 0; i < pipe->input_num; i++)
+		if (!pipe->inputs[i]->started ||
+			pipe->inputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED)
+			return 0;
+
+	for (i = 0; i < pipe->output_num; i++)
+		if (!pipe->outputs[i]->started ||
+			pipe->outputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED)
+			return 0;
+
+	return 1;
+}
+
+/**
+ * Validate a pipeline by checking both ends of all links for format
+ * discrepancies.
+ *
+ * Return 0 if all formats match, or -EPIPE if at least one link is found with
+ * different formats on its two ends.
+ */
+static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
+{
+	struct v4l2_subdev_format fmt_source;
+	struct v4l2_subdev_format fmt_sink;
+	struct v4l2_subdev *subdev;
+	struct media_pad *pad;
+	int ret;
+
+	/* Should not matter if it is output[0] or 1 as
+	   the general ideas is to traverse backwards and
+	   the fact that the out video node always has the
+	   format of the connected pad.
+	*/
+	subdev = vpfe_video_remote_subdev(pipe->outputs[0], NULL);
+	if (subdev == NULL)
+		return -EPIPE;
+
+	while (1) {
+		/* Retrieve the sink format */
+		pad = &subdev->entity.pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+
+		fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		fmt_sink.pad = pad->index;
+		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL,
+				       &fmt_sink);
+
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			return -EPIPE;
+
+		/* Retrieve the source format */
+		pad = media_entity_remote_source(pad);
+		if (pad == NULL ||
+			pad->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
+			break;
+
+		subdev = media_entity_to_v4l2_subdev(pad->entity);
+
+		fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		fmt_source.pad = pad->index;
+		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			return -EPIPE;
+
+		/* Check if the two ends match */
+		if (fmt_source.format.code != fmt_sink.format.code ||
+		    fmt_source.format.width != fmt_sink.format.width ||
+		    fmt_source.format.height != fmt_sink.format.height)
+			return -EPIPE;
+	}
+
+	return 0;
+}
+
+/**
+ * vpfe_pipeline_enable() - Enable streaming on a pipeline
+ * @vpfe_dev: vpfe device
+ * @pipe: vpfe pipeline
+ *
+ * Walk the entities chain starting at the pipeline output video node and start
+ * all modules in the chain in the given mode.
+ *
+ * Return 0 if successfull, or the return value of the failed video::s_stream
+ * operation otherwise.
+ */
+static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
+{
+	struct media_entity_graph graph;
+	struct media_entity *entity;
+	struct v4l2_subdev *subdev;
+	struct media_device *mdev;
+	int ret = 0;
+
+	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
+		entity = vpfe_get_input_entity(pipe->outputs[0]);
+	else
+		entity = &pipe->inputs[0]->video_dev.entity;
+
+	mdev = entity->parent;
+
+	mutex_lock(&mdev->graph_mutex);
+	media_entity_graph_walk_start(&graph, entity);
+
+	while ((entity = media_entity_graph_walk_next(&graph))) {
+
+		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+			continue;
+
+		subdev = media_entity_to_v4l2_subdev(entity);
+
+		ret = v4l2_subdev_call(subdev, video, s_stream, 1);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			break;
+	}
+	mutex_unlock(&mdev->graph_mutex);
+
+	return ret;
+}
+
+/**
+ * vpfe_pipeline_disable() - Disable streaming on a pipeline
+ * @vpfe_dev: vpfe device
+ * @pipe: VPFE pipeline
+ *
+ * Walk the entities chain starting at the pipeline output video node and stop
+ * all modules in the chain.
+ *
+ * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
+ * can't be stopped.
+ */
+static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
+{
+	struct media_entity_graph graph;
+	struct media_entity *entity;
+	struct v4l2_subdev *subdev;
+	struct media_device *mdev;
+	int ret = 0;
+
+	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
+		entity = vpfe_get_input_entity(pipe->outputs[0]);
+	else
+		entity = &pipe->inputs[0]->video_dev.entity;
+
+	mdev = entity->parent;
+
+	mutex_lock(&mdev->graph_mutex);
+	media_entity_graph_walk_start(&graph, entity);
+
+	while ((entity = media_entity_graph_walk_next(&graph))) {
+
+		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+			continue;
+
+		subdev = media_entity_to_v4l2_subdev(entity);
+
+		ret = v4l2_subdev_call(subdev, video, s_stream, 0);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			break;
+	}
+
+	mutex_unlock(&mdev->graph_mutex);
+
+	return (ret == 0) ? ret : -ETIMEDOUT ;
+}
+
+/**
+ * vpfe_pipeline_set_stream() - Enable/disable streaming on a pipeline
+ * @vpfe_dev: VPFE device
+ * @pipe: VPFE pipeline
+ * @state: Stream state (stopped or active)
+ *
+ * Set the pipeline to the given stream state.
+ *
+ * Return 0 if successfull, or the return value of the failed video::s_stream
+ * operation otherwise.
+ */
+static int vpfe_pipeline_set_stream(struct vpfe_pipeline *pipe,
+			    enum vpfe_pipeline_stream_state state)
+{
+	if (state == VPFE_PIPELINE_STREAM_STOPPED)
+		return vpfe_pipeline_disable(pipe);
+
+	return vpfe_pipeline_enable(pipe);
+}
+
+static int all_videos_stopped(struct vpfe_video_device *video)
+{
+	struct vpfe_pipeline *pipe = &video->pipe;
+	int i;
+
+	for (i = 0; i < pipe->input_num; i++)
+		if (pipe->inputs[i]->started)
+			return 0;
+
+	for (i = 0; i < pipe->output_num; i++)
+		if (pipe->outputs[i]->started)
+			return 0;
+
+	return 1;
+}
+
+/*
+ * vpfe_open() - open video device
+ * @file: file pointer
+ *
+ * initialize media pipeline state, allocate memory for file hadle
+ *
+ * Return 0 if successfull, or the return -ENODEV otherwise.
+ */
+static int vpfe_open(struct file *file)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_fh *fh;
+
+	/* Allocate memory for the file handle object */
+	fh = kzalloc(sizeof(struct vpfe_fh), GFP_KERNEL);
+
+	if (fh == NULL)
+		return -ENOMEM;
+	/* store pointer to fh in private_data member of file */
+	file->private_data = fh;
+	fh->video = video;
+	mutex_lock(&video->lock);
+	/* If decoder is not initialized. initialize it */
+	if (!video->initialized && vpfe_update_pipe_state(video)) {
+		mutex_unlock(&video->lock);
+		return -ENODEV;
+	}
+	/* Increment device usrs counter */
+	video->usrs++;
+	/* Set io_allowed member to false */
+	fh->io_allowed = 0;
+	/* Initialize priority of this instance to default priority */
+	fh->prio = V4L2_PRIORITY_UNSET;
+	v4l2_prio_open(&video->prio, &fh->prio);
+	mutex_unlock(&video->lock);
+
+	return 0;
+}
+
+/* get the next buffer available from dma queue */
+unsigned long vpfe_get_next_buffer(struct vpfe_video_device *video)
+{
+	/* mark next buffer as active */
+	video->next_frm = list_entry(video->dma_queue.next,
+					struct videobuf_buffer, queue);
+
+	/* in single shot mode both curr_frm
+	   and next_frm point to same buffer */
+	video->cur_frm = video->next_frm;
+	list_del(&video->next_frm->queue);
+	video->next_frm->state = VIDEOBUF_ACTIVE;
+
+	return videobuf_to_dma_contig(video->next_frm);
+}
+
+/* schedule the next buffer which is available on dma queue */
+void vpfe_schedule_next_buffer(struct vpfe_video_device *video)
+{
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	unsigned long addr;
+
+	if (list_empty(&video->dma_queue))
+		return;
+
+	video->next_frm = list_entry(video->dma_queue.next,
+					struct videobuf_buffer, queue);
+
+	if (VPFE_PIPELINE_STREAM_SINGLESHOT == video->pipe.state)
+		video->cur_frm = video->next_frm;
+
+	list_del(&video->next_frm->queue);
+	video->next_frm->state = VIDEOBUF_ACTIVE;
+	addr = videobuf_to_dma_contig(video->next_frm);
+
+	video->ops->queue(vpfe_dev, addr);
+
+	video->state = VPFE_VIDEO_BUFFER_QUEUED;
+}
+
+/* schedule the buffer for capturing bottom field */
+void vpfe_schedule_bottom_field(struct vpfe_video_device *video)
+{
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	unsigned long addr;
+
+	addr = videobuf_to_dma_contig(video->cur_frm);
+	addr += video->field_off;
+
+	video->ops->queue(vpfe_dev, addr);
+}
+
+/* make buffer available for dequeue */
+void vpfe_process_buffer_complete(struct vpfe_video_device *video)
+{
+	struct vpfe_pipeline *pipe = &video->pipe;
+	struct timespec timespec;
+	s64 nsec;
+
+	ktime_get_ts(&timespec);
+	nsec = timespec_to_ns(&timespec);
+
+	video->cur_frm->ts = ns_to_timeval(nsec);
+	video->cur_frm->state = VIDEOBUF_DONE;
+	video->cur_frm->size = video->fmt.fmt.pix.sizeimage;
+	wake_up_interruptible(&video->cur_frm->done);
+	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
+		video->cur_frm = video->next_frm;
+}
+
+/* vpfe_stop_capture() - stop streaming */
+static void vpfe_stop_capture(struct vpfe_video_device *video)
+{
+	struct vpfe_pipeline *pipe = &video->pipe;
+
+	video->started = 0;
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return;
+
+	if (all_videos_stopped(video))
+		vpfe_pipeline_set_stream(pipe,
+					 VPFE_PIPELINE_STREAM_STOPPED);
+}
+
+/*
+ * vpfe_release() - release video device
+ * @file: file pointer
+ *
+ * deletes buffer queue, frees the buffers and the vpfe file handle
+ *
+ * Return 0
+ */
+static int vpfe_release(struct file *file)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_fh *fh = file->private_data;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n");
+
+	/* Get the device lock */
+	mutex_lock(&video->lock);
+	/* if this instance is doing IO */
+	if (fh->io_allowed) {
+		if (video->started) {
+			vpfe_stop_capture(video);
+			/* mark pipe state as stopped in vpfe_release(),
+			   as app might call streamon() after streamoff()
+			   in which case driver has to start streaming.
+			*/
+			video->pipe.state = VPFE_PIPELINE_STREAM_STOPPED;
+			videobuf_streamoff(&video->buffer_queue);
+		}
+		video->io_usrs = 0;
+	}
+
+	/* Decrement device usrs counter */
+	video->usrs--;
+	/* Close the priority */
+	v4l2_prio_close(&video->prio, fh->prio);
+
+	/* If this is the last file handle */
+	if (!video->usrs)
+		video->initialized = 0;
+
+	mutex_unlock(&video->lock);
+	file->private_data = NULL;
+	/* Free memory allocated to file handle object */
+	kzfree(fh);
+
+	return 0;
+}
+
+/*
+ * vpfe_mmap() - It is used to map kernel space buffers
+ * into user spaces
+ */
+static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n");
+
+	return videobuf_mmap_mapper(&video->buffer_queue, vma);
+}
+
+/*
+ * vpfe_poll() - It is used for select/poll system call
+ */
+static unsigned int vpfe_poll(struct file *file, poll_table *wait)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n");
+
+	if (video->started)
+		return videobuf_poll_stream(file,
+					    &video->buffer_queue, wait);
+
+	return 0;
+}
+
+/* vpfe capture driver file operations */
+static const struct v4l2_file_operations vpfe_fops = {
+	.owner = THIS_MODULE,
+	.open = vpfe_open,
+	.release = vpfe_release,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = vpfe_mmap,
+	.poll = vpfe_poll
+};
+
+/*
+ * vpfe_querycap() - query capabilities of video device
+ * @file: file pointer
+ * @priv: void pointer
+ * @cap: pointer to v4l2_capability structure
+ *
+ * fills v4l2 capabilities structure
+ *
+ * Return 0
+ */
+static int vpfe_querycap(struct file *file, void  *priv,
+			       struct v4l2_capability *cap)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	else
+		cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+
+	cap->version = VPFE_CAPTURE_VERSION_CODE;
+	strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
+	strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
+
+	return 0;
+}
+
+/*
+ * vpfe_g_fmt() - get the format which is active on video device
+ * @file: file pointer
+ * @priv: void pointer
+ * @fmt: pointer to v4l2_format structure
+ *
+ * fills v4l2 format structure with active format
+ *
+ * Return 0
+ */
+static int vpfe_g_fmt(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt\n");
+	/* Fill in the information about format */
+	*fmt = video->fmt;
+
+	return 0;
+}
+
+/*
+ * vpfe_enum_fmt() - enum formats supported on media chain
+ * @file: file pointer
+ * @priv: void pointer
+ * @fmt: pointer to v4l2_fmtdesc structure
+ *
+ * fills v4l2_fmtdesc structure with output format set on adjacent subdev,
+ * only one format is enumearted as subdevs are already configured
+ *
+ * Return 0 if successfull, error code otherwise
+ */
+static int vpfe_enum_fmt(struct file *file, void  *priv,
+				   struct v4l2_fmtdesc *fmt)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct v4l2_subdev_format sd_fmt;
+	struct v4l2_mbus_framefmt mbus;
+	struct v4l2_subdev *subdev;
+	struct v4l2_format format;
+	struct media_pad *remote;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt\n");
+
+	/* since already subdev pad format is set,
+	only one pixel format is available */
+	if (fmt->index > 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid index\n");
+		return -EINVAL;
+	}
+
+	/* get the remote pad */
+	remote = media_entity_remote_source(&video->pad);
+	if (remote == NULL) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			 "invalid remote pad for video node\n");
+		return -EINVAL;
+	}
+
+	/* get the remote subdev */
+	subdev = vpfe_video_remote_subdev(video, NULL);
+	if (subdev == NULL) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			 "invalid remote subdev for video node\n");
+		return -EINVAL;
+	}
+
+	sd_fmt.pad = remote->index;
+	sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	/* get output format of remote subdev */
+	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &sd_fmt);
+	if (ret) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			 "invalid remote subdev for video node\n");
+		return ret;
+	}
+	/* convert to pix format */
+	mbus.code = sd_fmt.format.code;
+	mbus_to_pix(&mbus, &format.fmt.pix);
+
+	/* copy the result */
+	fmt->pixelformat = format.fmt.pix.pixelformat;
+
+	return 0;
+}
+
+/*
+ * vpfe_s_fmt() - set the format on video device
+ * @file: file pointer
+ * @priv: void pointer
+ * @fmt: pointer to v4l2_format structure
+ *
+ * validate and set the format on video device
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_s_fmt(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct v4l2_format format;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt\n");
+
+	/* If streaming is started, return error */
+	if (video->started) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n");
+		return -EBUSY;
+	}
+
+	/* get adjacent subdev's output pad format */
+	ret = __vpfe_video_get_format(video, &format);
+	if (ret)
+		return ret;
+
+	*fmt = format;
+
+	video->fmt = *fmt;
+
+	return 0;
+}
+
+/*
+ * vpfe_try_fmt() - try the format on video device
+ * @file: file pointer
+ * @priv: void pointer
+ * @fmt: pointer to v4l2_format structure
+ *
+ * validate the format, update with correct format
+ * based on output format set on adjacent subdev
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_try_fmt(struct file *file, void *priv,
+				  struct v4l2_format *fmt)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct v4l2_format format;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt\n");
+
+	/* get adjacent subdev's output pad format */
+	ret = __vpfe_video_get_format(video, &format);
+	if (ret)
+		return ret;
+
+	*fmt = format;
+
+	return 0;
+}
+
+/*
+ * vpfe_enum_input() - enum inputs supported on media chain
+ * @file: file pointer
+ * @priv: void pointer
+ * @fmt: pointer to v4l2_fmtdesc structure
+ *
+ * fills v4l2_input structure with input available on media chain,
+ * only one input is enumearted as media chain is setup by this time
+ *
+ * Return 0 if successfull, -EINVAL is media chain is invalid
+ */
+static int vpfe_enum_input(struct file *file, void *priv,
+				 struct v4l2_input *inp)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_ext_subdev_info *sdinfo = video->current_ext_subdev;
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
+
+	/* enumerate from the subdev user has choosen through mc */
+	if (inp->index < sdinfo->num_inputs) {
+		memcpy(inp, &sdinfo->inputs[inp->index],
+		       sizeof(struct v4l2_input));
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * vpfe_g_input() - get index of the input which is active
+ * @file: file pointer
+ * @priv: void pointer
+ * @index: pointer to unsigned int
+ *
+ * set index with input index which is active
+ *
+ * Return 0
+ */
+static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n");
+
+	*index = video->current_input;
+
+	return 0;
+}
+
+/*
+ * vpfe_s_input() - set input which is pointed by input index
+ * @file: file pointer
+ * @priv: void pointer
+ * @index: pointer to unsigned int
+ *
+ * set input on external subdev
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct ccdc_hw_device *ccdc_dev = vpfe_dev->vpfe_ccdc.ccdc_dev;
+	struct imp_hw_interface *imp_hw_if = vpfe_dev->vpfe_previewer.imp_hw_if;
+	struct vpfe_ext_subdev_info *sdinfo;
+	struct vpfe_route *route;
+	struct v4l2_input *inps;
+	u32 output;
+	u32 input;
+	int ret;
+	int i;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n");
+
+	ret = mutex_lock_interruptible(&video->lock);
+	if (ret)
+		return ret;
+
+	/*
+	 * If streaming is started return device busy
+	 * error
+	 */
+	if (video->started) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n");
+		ret = -EBUSY;
+		goto unlock_out;
+	}
+
+	sdinfo = video->current_ext_subdev;
+
+	if (!sdinfo->registered) {
+		ret = -EINVAL;
+		goto unlock_out;
+	}
+
+	if (vpfe_dev->cfg->setup_input &&
+		vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) {
+		ret = -EFAULT;
+		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+			  "couldn't setup input for %s\n",
+			  sdinfo->module_name);
+		goto unlock_out;
+	}
+
+	route = &sdinfo->routes[index];
+	if (route && sdinfo->can_route) {
+		input = route->input;
+		output = route->output;
+		ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+						 sdinfo->grp_id, video,
+						 s_routing, input, output, 0);
+
+		if (ret) {
+			v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+				"s_input:error in setting input in decoder\n");
+			ret = -EINVAL;
+			goto unlock_out;
+		}
+	}
+
+	/* set standards set by subdev in video device */
+	for (i = 0; i < sdinfo->num_inputs; i++) {
+		inps = &sdinfo->inputs[i];
+		video->video_dev.tvnorms |= inps->std;
+	}
+
+	/* set the bus/interface parameter for the sub device in ccdc */
+	ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
+	if (ret)
+		goto unlock_out;
+
+	/* update the if parameters to imp hw interface */
+	if (imp_hw_if && imp_hw_if->set_hw_if_param)
+		ret = imp_hw_if->set_hw_if_param(vpfe_dev->ipipe,
+						 &sdinfo->ccdc_if_params);
+	if (ret)
+		goto unlock_out;
+
+	video->current_input = index;
+
+unlock_out:
+	mutex_unlock(&video->lock);
+	return ret;
+}
+
+/*
+ * vpfe_querystd() - query std which is being input on external subdev
+ * @file: file pointer
+ * @priv: void pointer
+ * @std_id: pointer to v4l2_std_id structure
+ *
+ * call external subdev through v4l2_device_call_until_err to
+ * get the std that is being active.
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_ext_subdev_info *sdinfo;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n");
+
+	ret = mutex_lock_interruptible(&video->lock);
+	sdinfo = video->current_ext_subdev;
+	if (ret)
+		return ret;
+
+	/* Call querystd function of decoder device */
+	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 video, querystd, std_id);
+	mutex_unlock(&video->lock);
+
+	return ret;
+}
+
+/*
+ * vpfe_s_std() - set std on external subdev
+ * @file: file pointer
+ * @priv: void pointer
+ * @std_id: pointer to v4l2_std_id structure
+ *
+ * set std pointed by std_id on external subdev by calling it using
+ * v4l2_device_call_until_err
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_ext_subdev_info *sdinfo;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n");
+
+	/* Call decoder driver function to set the standard */
+	ret = mutex_lock_interruptible(&video->lock);
+	if (ret)
+		return ret;
+
+	sdinfo = video->current_ext_subdev;
+	/* If streaming is started, return device busy error */
+	if (video->started) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n");
+		ret = -EBUSY;
+		goto unlock_out;
+	}
+
+	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 core, s_std, *std_id);
+	if (ret < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
+		goto unlock_out;
+	}
+
+unlock_out:
+	mutex_unlock(&video->lock);
+	return ret;
+}
+
+/*
+ * vpfe_enum_preset() - enumerate dv_preset which are supported by
+ * to external subdev
+ *
+ * @file: file pointer
+ * @priv: void pointer
+ * @preset: pointer to v4l2_dv_enum_preset structure
+ *
+ * enum dv_preset's which are supported by external subdev through
+ * v4l2_subdev_call
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_enum_preset(struct file *file, void *fh,
+			    struct v4l2_dv_enum_preset *preset)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_preset\n");
+
+	return v4l2_subdev_call(subdev, video, enum_dv_presets, preset);
+}
+
+/*
+ * vpfe_query_preset() - query the dv_preset which is being input
+ * to external subdev
+ *
+ * @file: file pointer
+ * @priv: void pointer
+ * @preset: pointer to v4l2_preset structure
+ *
+ * get dv_preset which is being input on external subdev through
+ * v4l2_subdev_call
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_query_preset(struct file *file, void *fh,
+			     struct v4l2_dv_preset *preset)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_query_preset\n");
+
+	return v4l2_subdev_call(subdev, video, query_dv_preset, preset);
+}
+
+/*
+ * vpfe_s_preset() - set dv_preset on external subdev
+ * @file: file pointer
+ * @priv: void pointer
+ * @preset: pointer to v4l2_preset structure
+ *
+ * set dv_preset pointed by preset on external subdev through
+ * v4l2_device_call_until_err, this configures amplifier also
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_s_preset(struct file *file, void *fh,
+			 struct v4l2_dv_preset *preset)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_preset\n");
+
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+					  video->current_ext_subdev->grp_id,
+					  video, s_dv_preset, preset);
+}
+
+/*
+ * vpfe_g_preset() - get dv_preset which is set on external subdev
+ * @file: file pointer
+ * @priv: void pointer
+ * @preset: pointer to v4l2_preset structure
+ *
+ * get dv_preset which is set on external subdev through
+ * v4l2_subdev_call
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_g_preset(struct file *file, void *fh,
+			 struct v4l2_dv_preset *preset)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_preset\n");
+
+	return v4l2_subdev_call(subdev, video, query_dv_preset, preset);
+}
+
+/*
+ *  Videobuf operations
+ */
+static int vpfe_videobuf_setup(struct videobuf_queue *vq,
+				unsigned int *count,
+				unsigned int *size)
+{
+	struct vpfe_fh *fh = vq->priv_data;
+	struct vpfe_video_device *video = fh->video;
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_pipeline *pipe = &video->pipe;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
+
+	*size = video->fmt.fmt.pix.sizeimage;
+
+	if (vpfe_dev->video_limit) {
+		while (*size * *count > vpfe_dev->video_limit)
+			(*count)--;
+	}
+
+	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) {
+		if (*count < CONT_MIN_NUM_BUFFERS)
+			*count = CONT_MIN_NUM_BUFFERS;
+	}
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+		"count=%d, size=%d\n", *count, *size);
+
+	return 0;
+}
+
+static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb,
+				enum v4l2_field field)
+{
+	struct vpfe_fh *fh = vq->priv_data;
+	struct vpfe_video_device *video = fh->video;
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	unsigned long addr;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_prepare\n");
+
+	if (VIDEOBUF_NEEDS_INIT != vb->state)
+		return 0;
+
+	/* Initialize buffer */
+	vb->width = video->fmt.fmt.pix.width;
+	vb->height = video->fmt.fmt.pix.height;
+	vb->size = video->fmt.fmt.pix.sizeimage;
+	vb->field = field;
+
+	ret = videobuf_iolock(vq, vb, NULL);
+	if (ret < 0)
+		return ret;
+
+	addr = videobuf_to_dma_contig(vb);
+	/* Make sure user addresses are aligned to 32 bytes */
+	if (!ALIGN(addr, 32))
+		return -EINVAL;
+
+	vb->state = VIDEOBUF_PREPARED;
+
+	return 0;
+}
+
+static void vpfe_videobuf_queue(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	/* Get the file handle object and device object */
+	struct vpfe_fh *fh = vq->priv_data;
+	struct vpfe_video_device *video = fh->video;
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_pipeline *pipe = &video->pipe;
+	unsigned long flags;
+	unsigned long empty;
+	unsigned long addr;
+
+	spin_lock_irqsave(&video->dma_queue_lock, flags);
+	empty = list_empty(&video->dma_queue);
+
+	/* add the buffer to the DMA queue */
+	list_add_tail(&vb->queue, &video->dma_queue);
+	spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+
+	/* Change state of the buffer */
+	vb->state = VIDEOBUF_QUEUED;
+
+	/* this case happens in case of single shot */
+	if (empty && video->started && pipe->state ==
+		VPFE_PIPELINE_STREAM_SINGLESHOT &&
+		video->state == VPFE_VIDEO_BUFFER_NOT_QUEUED) {
+		spin_lock(&video->dma_queue_lock);
+		addr = vpfe_get_next_buffer(video);
+		video->ops->queue(vpfe_dev, addr);
+
+		video->state = VPFE_VIDEO_BUFFER_QUEUED;
+		spin_unlock(&video->dma_queue_lock);
+
+		/* enable h/w each time in single shot */
+		if (is_pipe_ready(pipe))
+			vpfe_pipeline_set_stream(pipe,
+					VPFE_PIPELINE_STREAM_SINGLESHOT);
+	}
+}
+
+static void vpfe_videobuf_release(struct videobuf_queue *vq,
+				  struct videobuf_buffer *vb)
+{
+	struct vpfe_fh *fh = vq->priv_data;
+	struct vpfe_video_device *video = fh->video;
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n");
+
+	if (video->memory == V4L2_MEMORY_MMAP)
+		videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops vpfe_videobuf_qops = {
+	.buf_setup      = vpfe_videobuf_setup,
+	.buf_prepare    = vpfe_videobuf_prepare,
+	.buf_queue      = vpfe_videobuf_queue,
+	.buf_release    = vpfe_videobuf_release,
+};
+
+/*
+ * vpfe_reqbufs() - supported REQBUF only once opening
+ * the device.
+ */
+static int vpfe_reqbufs(struct file *file, void *priv,
+			struct v4l2_requestbuffers *req_buf)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_fh *fh = file->private_data;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type &&
+		V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n");
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&video->lock);
+	if (ret)
+		return ret;
+
+	if (video->io_usrs != 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n");
+		ret = -EBUSY;
+		goto unlock_out;
+	}
+
+	video->memory = req_buf->memory;
+	videobuf_queue_dma_contig_init(&video->buffer_queue,
+				&vpfe_videobuf_qops, vpfe_dev->pdev,
+				&video->irqlock, req_buf->type,
+				video->fmt.fmt.pix.field,
+				sizeof(struct videobuf_buffer),
+				fh, NULL);
+
+	fh->io_allowed = 1;
+	video->io_usrs = 1;
+	INIT_LIST_HEAD(&video->dma_queue);
+	ret = videobuf_reqbufs(&video->buffer_queue, req_buf);
+
+unlock_out:
+	mutex_unlock(&video->lock);
+	return ret;
+}
+
+/*
+ * vpfe_querybuf() - query buffers for exchange
+ */
+static int vpfe_querybuf(struct file *file, void *priv,
+			 struct v4l2_buffer *buf)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type &&
+		V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return  -EINVAL;
+	}
+
+	if (video->memory != V4L2_MEMORY_MMAP) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n");
+		return -EINVAL;
+	}
+
+	/* Call videobuf_querybuf to get information */
+	return videobuf_querybuf(&video->buffer_queue, buf);
+}
+
+/*
+ * vpfe_qbuf() - queue buffers for capture or processing
+ */
+static int vpfe_qbuf(struct file *file, void *priv,
+		     struct v4l2_buffer *p)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_fh *fh = file->private_data;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type &&
+		V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * If this file handle is not allowed to do IO,
+	 * return error
+	 */
+	if (!fh->io_allowed) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+		return -EACCES;
+	}
+
+	return videobuf_qbuf(&video->buffer_queue, p);
+}
+
+/*
+ * vpfe_dqbuf() - deque buffer which is done with processing
+ */
+static int vpfe_dqbuf(struct file *file, void *priv,
+		      struct v4l2_buffer *buf)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type &&
+		V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return -EINVAL;
+	}
+
+	return videobuf_dqbuf(&video->buffer_queue,
+				      buf, file->f_flags & O_NONBLOCK);
+}
+
+/* vpfe_start_capture() - start streaming on all the subdevs */
+static int vpfe_start_capture(struct vpfe_video_device *video)
+{
+	struct vpfe_pipeline *pipe = &video->pipe;
+	int ret = 0;
+
+	video->started = 1;
+
+	if (is_pipe_ready(pipe))
+		ret = vpfe_pipeline_set_stream(pipe, pipe->state);
+
+	return ret;
+}
+
+/*
+ * vpfe_streamon() - get dv_preset which is set on external subdev
+ * @file: file pointer
+ * @priv: void pointer
+ * @buf_type: enum v4l2_buf_type
+ *
+ * queue buffer onto hardware for capture/processing and
+ * start all the subdevs which are in media chain
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_streamon(struct file *file, void *priv,
+			 enum v4l2_buf_type buf_type)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_pipeline *pipe = &video->pipe;
+	struct vpfe_fh *fh = file->private_data;
+	struct vpfe_ext_subdev_info *sdinfo;
+	unsigned long addr;
+	int ret = -EINVAL;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type &&
+		V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return ret;
+	}
+
+	/* If file handle is not allowed IO, return error */
+	if (!fh->io_allowed) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+		return -EACCES;
+	}
+	sdinfo = video->current_ext_subdev;
+	/* If buffer queue is empty, return error */
+	if (list_empty(&video->buffer_queue.stream)) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n");
+		return -EIO;
+	}
+	/* Validate the pipeline */
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE == buf_type) {
+		ret = vpfe_video_validate_pipeline(pipe);
+		if (ret < 0)
+			return ret;
+	}
+	/* Call videobuf_streamon to start streaming * in videobuf */
+	ret = videobuf_streamon(&video->buffer_queue);
+	if (ret)
+		return ret;
+
+	ret = mutex_lock_interruptible(&video->lock);
+	if (ret)
+		goto streamoff;
+
+	/* Get the next frame from the buffer queue */
+	video->next_frm = list_entry(video->dma_queue.next,
+					struct videobuf_buffer, queue);
+	video->cur_frm = video->next_frm;
+	/* Remove buffer from the buffer queue */
+	list_del(&video->cur_frm->queue);
+	/* Mark state of the current frame to active */
+	video->cur_frm->state = VIDEOBUF_ACTIVE;
+	/* Initialize field_id and started member */
+	video->field_id = 0;
+	addr = videobuf_to_dma_contig(video->cur_frm);
+	video->ops->queue(vpfe_dev, addr);
+	video->state = VPFE_VIDEO_BUFFER_QUEUED;
+	ret = vpfe_start_capture(video);
+	if (ret)
+		goto unlock_out;
+
+	mutex_unlock(&video->lock);
+	return ret;
+unlock_out:
+	mutex_unlock(&video->lock);
+streamoff:
+	ret = videobuf_streamoff(&video->buffer_queue);
+	return ret;
+}
+
+/*
+ * vpfe_streamoff() - get dv_preset which is set on external subdev
+ * @file: file pointer
+ * @priv: void pointer
+ * @buf_type: enum v4l2_buf_type
+ *
+ * stop all the subdevs which are in media chain
+ *
+ * Return 0 on success, error code otherwise
+ */
+static int vpfe_streamoff(struct file *file, void *priv,
+			  enum v4l2_buf_type buf_type)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_fh *fh = file->private_data;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n");
+
+	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+		buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return -EINVAL;
+	}
+
+	/* If io is allowed for this file handle, return error */
+	if (!fh->io_allowed) {
+		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+		return -EACCES;
+	}
+
+	/* If streaming is not started, return error */
+	if (!video->started) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "device is not started\n");
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&video->lock);
+	if (ret)
+		return ret;
+
+	vpfe_stop_capture(video);
+
+	ret = videobuf_streamoff(&video->buffer_queue);
+	mutex_unlock(&video->lock);
+
+	return ret;
+}
+
+/*
+ * vpfe_queryctrl() - query for v4l2 controls which is set on external subdev
+ * @file: file pointer
+ * @priv: void pointer
+ * @ctrl: pointer to v4l2_control structure
+ *
+ * get the v4l2 controls active on external subdev through
+ * v4l2_device_call_until_err
+ *
+ * Return return value returned by v4l2_device_call_until_err
+ */
+static int vpfe_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_ext_subdev_info *sub_dev = video->current_ext_subdev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_queryctrl\n");
+
+	/* pass it to sub device */
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sub_dev->grp_id,
+					  core, queryctrl, qc);
+}
+
+/*
+ * vpfe_g_ctrl() - get the v4l2 controls which is set on external subdev
+ * @file: file pointer
+ * @priv: void pointer
+ * @ctrl: pointer to v4l2_control structure
+ *
+ * get the v4l2 controls set on external subdev through
+ * v4l2_device_call_until_err
+ *
+ * Return return value returned by v4l2_device_call_until_err
+ */
+static int vpfe_g_ctrl(struct file *file, void *priv,
+			struct v4l2_control *ctrl)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_ext_subdev_info *sub_dev = video->current_ext_subdev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_ctrl\n");
+
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sub_dev->grp_id,
+					  core, g_ctrl, ctrl);
+}
+
+/*
+ * vpfe_s_ctrl() - set the v4l2 controls on external subdev
+ * @file: file pointer
+ * @priv: void pointer
+ * @ctrl: pointer to v4l2_control structure
+ *
+ * call external subdev through v4l2_device_call_until_err to
+ * set v4l2 controls
+ *
+ * Return return value returned by v4l2_device_call_until_err
+ */
+static int vpfe_s_ctrl(struct file *file, void *priv,
+			     struct v4l2_control *ctrl)
+{
+	struct vpfe_video_device *video = video_drvdata(file);
+	struct vpfe_device *vpfe_dev = video->vpfe_dev;
+	struct vpfe_ext_subdev_info *sub_dev = video->current_ext_subdev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_ctrl\n");
+
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sub_dev->grp_id,
+					  core, s_ctrl, ctrl);
+}
+
+/* vpfe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
+	.vidioc_querycap	 = vpfe_querycap,
+	.vidioc_g_fmt_vid_cap    = vpfe_g_fmt,
+	.vidioc_s_fmt_vid_cap    = vpfe_s_fmt,
+	.vidioc_try_fmt_vid_cap  = vpfe_try_fmt,
+	.vidioc_enum_fmt_vid_cap = vpfe_enum_fmt,
+	.vidioc_g_fmt_vid_out    = vpfe_g_fmt,
+	.vidioc_s_fmt_vid_out    = vpfe_s_fmt,
+	.vidioc_try_fmt_vid_out  = vpfe_try_fmt,
+	.vidioc_enum_fmt_vid_out = vpfe_enum_fmt,
+	.vidioc_enum_input	 = vpfe_enum_input,
+	.vidioc_g_input		 = vpfe_g_input,
+	.vidioc_s_input		 = vpfe_s_input,
+	.vidioc_querystd	 = vpfe_querystd,
+	.vidioc_s_std		 = vpfe_s_std,
+	.vidioc_enum_dv_presets	 = vpfe_enum_preset,
+	.vidioc_query_dv_preset	 = vpfe_query_preset,
+	.vidioc_s_dv_preset	 = vpfe_s_preset,
+	.vidioc_g_dv_preset	 = vpfe_g_preset,
+	.vidioc_reqbufs		 = vpfe_reqbufs,
+	.vidioc_querybuf	 = vpfe_querybuf,
+	.vidioc_qbuf		 = vpfe_qbuf,
+	.vidioc_dqbuf		 = vpfe_dqbuf,
+	.vidioc_streamon	 = vpfe_streamon,
+	.vidioc_streamoff	 = vpfe_streamoff,
+	.vidioc_queryctrl	 = vpfe_queryctrl,
+	.vidioc_g_ctrl		 = vpfe_g_ctrl,
+	.vidioc_s_ctrl		 = vpfe_s_ctrl,
+};
+
+/* VPFE video init function */
+int vpfe_video_init(struct vpfe_video_device *video, const char *name)
+{
+	const char *direction;
+	int ret;
+
+	switch (video->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		direction = "output";
+		video->pad.flags = MEDIA_PAD_FL_SINK;
+		video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		direction = "input";
+		video->pad.flags = MEDIA_PAD_FL_SOURCE;
+		video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Initialize field of video device */
+	video->video_dev.release = video_device_release;
+	video->video_dev.fops = &vpfe_fops;
+	video->video_dev.ioctl_ops = &vpfe_ioctl_ops;
+	video->video_dev.minor = -1;
+	video->video_dev.tvnorms = 0;
+	video->video_dev.current_norm = V4L2_STD_NTSC;
+
+	snprintf(video->video_dev.name, sizeof(video->video_dev.name),
+		 "DAVINCI VIDEO %s %s", name, direction);
+
+	/* Initialize prio member of device object */
+	v4l2_prio_init(&video->prio);
+
+	spin_lock_init(&video->irqlock);
+	spin_lock_init(&video->dma_queue_lock);
+	mutex_init(&video->lock);
+
+	ret = media_entity_init(&video->video_dev.entity,
+				1, &video->pad, 0);
+	if (ret < 0)
+		return ret;
+
+	video_set_drvdata(&video->video_dev, video);
+
+	return 0;
+}
+
+/* vpfe video device register function */
+int vpfe_video_register(struct vpfe_video_device *video,
+			struct v4l2_device *vdev)
+{
+	int ret;
+
+	video->video_dev.v4l2_dev = vdev;
+
+	ret = video_register_device(&video->video_dev, VFL_TYPE_GRABBER, -1);
+	if (ret < 0)
+		pr_err("%s: could not register video device (%d)\n",
+		       __func__, ret);
+
+	return ret;
+}
+
+/* vpfe video device unregister function */
+void vpfe_video_unregister(struct vpfe_video_device *video)
+{
+	if (video_is_registered(&video->video_dev)) {
+		media_entity_cleanup(&video->video_dev.entity);
+		video_unregister_device(&video->video_dev);
+	}
+}
diff --git a/drivers/media/platform/davinci/vpfe_video.h b/drivers/media/platform/davinci/vpfe_video.h
new file mode 100644
index 0000000..af68caf
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_video.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+/* All video device related structures will go here */
+#ifndef _VPFE_VIDEO_H
+#define _VPFE_VIDEO_H
+
+#include <media/media-entity.h>
+#include <media/videobuf-dma-contig.h>
+
+struct vpfe_device;
+
+/*
+ * struct vpfe_video_operations - VPFE video operations
+ * @queue:	Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
+ *		if there was no buffer previously queued.
+ */
+struct vpfe_video_operations {
+	void(*queue)(struct vpfe_device *vpfe_dev, unsigned long addr);
+};
+
+enum vpfe_pipeline_stream_state {
+	VPFE_PIPELINE_STREAM_STOPPED,
+	VPFE_PIPELINE_STREAM_CONTINUOUS,
+	VPFE_PIPELINE_STREAM_SINGLESHOT
+};
+
+enum vpfe_video_state {
+	/* indicates that buffer is not queued */
+	VPFE_VIDEO_BUFFER_NOT_QUEUED = 0,
+	/* indicates that buffer is queued */
+	VPFE_VIDEO_BUFFER_QUEUED = 1,
+};
+
+struct vpfe_pipeline {
+	/* media pipeline */
+	struct media_pipeline		*pipe;
+	/* state of the pipeline, continous,
+	single-shot or stopped */
+	enum vpfe_pipeline_stream_state	state;
+	/* number of active input video entities */
+	unsigned int			input_num;
+	/* number of active output video entities */
+	unsigned int			output_num;
+	/* input video nodes in case of single-shot mode */
+	struct vpfe_video_device	*inputs[10];
+	/* capturing video nodes */
+	struct vpfe_video_device	*outputs[10];
+};
+
+#define to_vpfe_pipeline(__e) \
+	container_of((__e)->pipe, struct vpfe_pipeline, pipe)
+
+#define to_vpfe_video(vdev) \
+	container_of(vdev, struct vpfe_video_device, video_dev)
+
+struct vpfe_video_device {
+	/* vpfe device */
+	struct vpfe_device			*vpfe_dev;
+	/* video dev */
+	struct video_device			video_dev;
+	/* media pad of video entity */
+	struct media_pad			pad;
+	/* video operations supported by video device */
+	const struct vpfe_video_operations	*ops;
+	/* type of the video buffers used by user */
+	enum v4l2_buf_type			type;
+	/* Indicates id of the field which is being captured */
+	u32					field_id;
+	/* pipiline for which video device is part of */
+	struct vpfe_pipeline			pipe;
+	/* Indicates whether streaming started */
+	u8					started;
+	/* Indicates state of the stream */
+	unsigned int				state;
+	/* current input at the sub device */
+	int					current_input;
+	/*
+	 * This field keeps track of type of buffer exchange mechanism
+	 * user has selected
+	 */
+	enum v4l2_memory			memory;
+	/* Used to keep track of state of the priority */
+	struct v4l2_prio_state			prio;
+	/* number of open instances of the channel */
+	u32					usrs;
+	/* flag to indicate whether decoder is initialized */
+	u8					initialized;
+	/* skip frame count */
+	u8					skip_frame_count;
+	/* skip frame count init value */
+	u8					skip_frame_count_init;
+	/* time per frame for skipping */
+	struct v4l2_fract			timeperframe;
+	/* ptr to currently selected sub device */
+	struct vpfe_ext_subdev_info		*current_ext_subdev;
+	/* Pointer pointing to current v4l2_buffer */
+	struct videobuf_buffer			*cur_frm;
+	/* Pointer pointing to next v4l2_buffer */
+	struct videobuf_buffer			*next_frm;
+	/* Used to store pixel format */
+	struct v4l2_format			fmt;
+	/* Buffer queue used in video-buf */
+	struct videobuf_queue			buffer_queue;
+	/* Queue of filled frames */
+	struct list_head			dma_queue;
+	/* Used in video-buf */
+	spinlock_t				irqlock;
+	/* IRQ lock for DMA queue */
+	spinlock_t				dma_queue_lock;
+	/* lock used to access this structure */
+	struct mutex				lock;
+	/* number of users performing IO */
+	u32					io_usrs;
+	/*
+	 * offset where second field starts from the starting of the
+	 * buffer for field seperated YCbCr formats
+	 */
+	u32					field_off;
+};
+
+int is_pipe_ready(struct vpfe_pipeline *pipe);
+void vpfe_video_unregister(struct vpfe_video_device *video);
+int vpfe_video_register(struct vpfe_video_device *video,
+			struct v4l2_device *vdev);
+int vpfe_video_init(struct vpfe_video_device *video, const char *name);
+
+void vpfe_process_buffer_complete(struct vpfe_video_device *video);
+void vpfe_schedule_bottom_field(struct vpfe_video_device *video);
+void vpfe_schedule_next_buffer(struct vpfe_video_device *video);
+unsigned long vpfe_get_next_buffer(struct vpfe_video_device *video);
+#endif
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 07/14] davinci: vpfe: v4l2 capture driver with media interface
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (5 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 06/14] davinci: vpfe: add v4l2 video driver support Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 08/14] davinci: vpfe: previewer driver based on v4l2 media controller framework Prabhakar Lad
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

Add the vpfe capture driver which implements media controller
interface. The driver suports all the setup functionality for
all all units nnamely- ccdc, previewer, resizer, h3a, aew.
The driver supports both dm365 and Dm355. The driver does isr
registration, v4l2 device registration, media registration and
platform driver registrations. It calls the appropriate subdevs
from here to cerate the appropriate subdevices and media entities.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/vpfe_mc_capture.c |  764 ++++++++++++++++++++++
 drivers/media/platform/davinci/vpfe_mc_capture.h |  104 +++
 include/media/davinci/vpfe.h                     |   84 +++
 3 files changed, 952 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/platform/davinci/vpfe_mc_capture.c
 create mode 100644 drivers/media/platform/davinci/vpfe_mc_capture.h
 create mode 100644 include/media/davinci/vpfe.h

diff --git a/drivers/media/platform/davinci/vpfe_mc_capture.c b/drivers/media/platform/davinci/vpfe_mc_capture.c
new file mode 100644
index 0000000..306d45f
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_mc_capture.c
@@ -0,0 +1,764 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ *
+ *
+ * Driver name : VPFE Capture driver
+ *    VPFE Capture driver allows applications to capture and stream video
+ *    frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as
+ *    TVP5146 or  Raw Bayer RGB image data from an image sensor
+ *    such as Microns' MT9T001, MT9T031 etc.
+ *
+ *    These SoCs have, in common, a Video Processing Subsystem (VPSS) that
+ *    consists of a Video Processing Front End (VPFE) for capturing
+ *    video/raw image data and Video Processing Back End (VPBE) for displaying
+ *    YUV data through an in-built analog encoder or Digital LCD port. This
+ *    driver is for capture through VPFE. A typical EVM using these SoCs have
+ *    following high level configuration.
+ *
+ *    decoder(TVP5146/		YUV/
+ *	MT9T001)   -->  Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF)
+ *			data input              |      |
+ *							V      |
+ *						      SDRAM    |
+ *							       V
+ *							   Image Processor
+ *							       |
+ *							       V
+ *							     SDRAM
+ *    The data flow happens from a decoder connected to the VPFE over a
+ *    YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface
+ *    and to the input of VPFE through an optional MUX (if more inputs are
+ *    to be interfaced on the EVM). The input data is first passed through
+ *    CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC
+ *    does very little or no processing on YUV data and does pre-process Raw
+ *    Bayer RGB data through modules such as Defect Pixel Correction (DFC)
+ *    Color Space Conversion (CSC), data gain/offset etc. After this, data
+ *    can be written to SDRAM or can be connected to the image processing
+ *    block such as IPIPE (on DM355/DM365 only).
+ *
+ *    Features supported
+ *		- MMAP IO
+ *		- USERPTR IO
+ *		- Capture using TVP5146 over BT.656
+ *		- Support for interfacing decoders using sub device model
+ *		- Work with DM365 or DM355 or DM6446 CCDC to do Raw Bayer
+ *		  RGB/YUV data capture to SDRAM.
+ *		- Chaining of Image Processor
+ *		- SINGLE-SHOT mode
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-common.h>
+#include <media/media-entity.h>
+#include <media/media-device.h>
+#include <media/davinci/vpfe_types.h>
+
+#include "vpfe_mc_capture.h"
+
+static bool debug;
+static bool interface;
+static u32 cont_bufoffset;
+static u32 cont_bufsize;
+static u32 en_serializer;
+
+module_param(interface, bool, S_IRUGO);
+module_param(debug, bool, 0644);
+module_param(cont_bufoffset, uint, S_IRUGO);
+module_param(cont_bufsize, uint, S_IRUGO);
+module_param(en_serializer, uint, S_IRUGO);
+
+/**
+ * VPFE capture can be used for capturing video such as from TVP5146 or TVP7002
+ * and for capture raw bayer data from camera sensors such as mt9p031. At this
+ * point there is problem in co-existence of mt9p031 and tvp5146 due to i2c
+ * address collision. So set the variable below from bootargs to do either video
+ * capture or camera capture.
+ * interface = 0 - video capture (from TVP514x or such),
+ * interface = 1 - Camera capture (from mt9p031 or such)
+ * Re-visit this when we fix the co-existence issue
+ */
+MODULE_PARM_DESC(interface, "interface 0-1 (default:0)");
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+MODULE_PARM_DESC(cont_bufoffset, "Capture buffer offset (default 0)");
+MODULE_PARM_DESC(cont_bufsize, "Capture buffer size (default 0)");
+MODULE_PARM_DESC(en_serializer, "enable IPIPE serializer (default:0)");
+
+MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
+
+/* map mbus_fmt to pixelformat */
+void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus,
+			   struct v4l2_pix_format *pix)
+{
+	switch (mbus->code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		pix->pixelformat = V4L2_PIX_FMT_UYVY;
+		pix->bytesperline = pix->width * 2;
+		break;
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		pix->pixelformat = V4L2_PIX_FMT_YUYV;
+		pix->bytesperline = pix->width * 2;
+		break;
+	case V4L2_MBUS_FMT_YUYV10_1X20:
+		pix->pixelformat = V4L2_PIX_FMT_UYVY;
+		pix->bytesperline = pix->width * 2;
+		break;
+	case V4L2_MBUS_FMT_SGRBG12_1X12:
+		pix->pixelformat = V4L2_PIX_FMT_SBGGR16;
+		pix->bytesperline = pix->width * 2;
+		break;
+	case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+		pix->pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8;
+		pix->bytesperline = pix->width;
+		break;
+	case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
+		pix->pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8;
+		pix->bytesperline = pix->width;
+		break;
+	case V4L2_MBUS_FMT_YDYUYDYV8_1X16:
+		pix->pixelformat = V4L2_PIX_FMT_NV12;
+		pix->bytesperline = pix->width;
+		break;
+	case V4L2_MBUS_FMT_Y8_1X8:
+		pix->pixelformat = V4L2_PIX_FMT_GREY;
+		pix->bytesperline = pix->width;
+		break;
+	case V4L2_MBUS_FMT_UV8_1X8:
+		pix->pixelformat = V4L2_PIX_FMT_UV8;
+		pix->bytesperline = pix->width;
+		break;
+	default:
+		pr_err("Invalid mbus code set\n");
+	}
+
+	/* pitch should be 32 bytes aligned */
+	pix->bytesperline = ALIGN(pix->bytesperline, 32);
+
+	if (pix->pixelformat == V4L2_PIX_FMT_NV12)
+		pix->sizeimage = pix->bytesperline * pix->height +
+				((pix->bytesperline * pix->height) >> 1);
+	else
+		pix->sizeimage = pix->bytesperline * pix->height;
+}
+
+/* ISR for VINT0*/
+static irqreturn_t vpfe_isr(int irq, void *dev_id)
+{
+	struct vpfe_device *vpfe_dev = dev_id;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_isr\n");
+	ccdc_buffer_isr(&vpfe_dev->vpfe_ccdc);
+	prv_buffer_isr(&vpfe_dev->vpfe_previewer);
+	rsz_buffer_isr(&vpfe_dev->vpfe_resizer);
+
+	return IRQ_HANDLED;
+}
+
+/* vpfe_vdint1_isr() - isr handler for VINT1 interrupt */
+static irqreturn_t vpfe_vdint1_isr(int irq, void *dev_id)
+{
+	struct vpfe_device *vpfe_dev = dev_id;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_vdint1_isr\n");
+	ccdc_vidint1_isr(&vpfe_dev->vpfe_ccdc);
+
+	return IRQ_HANDLED;
+}
+
+/* vpfe_imp_dma_isr() - ISR for ipipe dma completion */
+static irqreturn_t vpfe_imp_dma_isr(int irq, void *dev_id)
+{
+	struct vpfe_device *vpfe_dev = dev_id;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_imp_dma_isr\n");
+	prv_dma_isr(&vpfe_dev->vpfe_previewer);
+	rsz_dma_isr(&vpfe_dev->vpfe_resizer);
+
+	return IRQ_HANDLED;
+}
+
+/* set user setting of serializer in ipipe */
+static void vpfe_initialize(struct vpfe_device *vpfe_dev)
+{
+	/* inform user choice on serializer to ipipe */
+	enable_serializer(vpfe_dev->ipipe, en_serializer);
+}
+
+/**
+ * vpfe_disable_clock() - Disable clocks for vpfe capture driver
+ * @vpfe_dev - ptr to vpfe capture device
+ *
+ * Disables clocks defined in vpfe configuration. The function
+ * assumes that at least one clock is to be defined which is
+ * true as of now.
+ */
+static void vpfe_disable_clock(struct vpfe_device *vpfe_dev)
+{
+	struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
+	int i;
+
+	for (i = 0; i < vpfe_cfg->num_clocks; i++) {
+		clk_disable(vpfe_dev->clks[i]);
+		clk_put(vpfe_dev->clks[i]);
+	}
+
+	kzfree(vpfe_dev->clks);
+	v4l2_info(vpfe_dev->pdev->driver, "vpfe capture clocks disabled\n");
+}
+
+/**
+ * vpfe_enable_clock() - Enable clocks for vpfe capture driver
+ * @vpfe_dev - ptr to vpfe capture device
+ *
+ * Enables clocks defined in vpfe configuration. The function
+ * assumes that at least one clock is to be defined which is
+ * true as of now.
+ */
+static int vpfe_enable_clock(struct vpfe_device *vpfe_dev)
+{
+	struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
+	int ret = -EFAULT;
+	int i;
+
+	if (!vpfe_cfg->num_clocks)
+		return 0;
+
+	vpfe_dev->clks = kzalloc(vpfe_cfg->num_clocks *
+				   sizeof(struct clock *), GFP_KERNEL);
+
+	if (vpfe_dev->clks == NULL) {
+		v4l2_err(vpfe_dev->pdev->driver, "Memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < vpfe_cfg->num_clocks; i++) {
+		if (vpfe_cfg->clocks[i] == NULL) {
+			v4l2_err(vpfe_dev->pdev->driver,
+				"clock %s is not defined in vpfe config\n",
+				vpfe_cfg->clocks[i]);
+			goto out;
+		}
+
+		vpfe_dev->clks[i] = clk_get(vpfe_dev->pdev,
+					      vpfe_cfg->clocks[i]);
+		if (vpfe_dev->clks[i] == NULL) {
+			v4l2_err(vpfe_dev->pdev->driver,
+				"Failed to get clock %s\n",
+				vpfe_cfg->clocks[i]);
+			goto out;
+		}
+
+		if (clk_enable(vpfe_dev->clks[i])) {
+			v4l2_err(vpfe_dev->pdev->driver,
+				"vpfe clock %s not enabled\n",
+				vpfe_cfg->clocks[i]);
+			goto out;
+		}
+
+		v4l2_info(vpfe_dev->pdev->driver, "vpss clock %s enabled",
+			  vpfe_cfg->clocks[i]);
+	}
+
+	return 0;
+out:
+	for (i = 0; i < vpfe_cfg->num_clocks; i++) {
+		if (vpfe_dev->clks[i])
+			clk_put(vpfe_dev->clks[i]);
+	}
+
+	v4l2_err(vpfe_dev->pdev->driver, "Failed to enable clocks\n");
+
+	kzfree(vpfe_dev->clks);
+	return ret;
+}
+
+/**
+ * vpfe_detach_irq() - Detach IRQs for vpfe capture driver
+ * @vpfe_dev - ptr to vpfe capture device
+ *
+ * Detach all IRQs defined in vpfe configuration.
+ */
+static void vpfe_detach_irq(struct vpfe_device *vpfe_dev)
+{
+	free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+	free_irq(vpfe_dev->ccdc_irq1, vpfe_dev);
+	free_irq(vpfe_dev->imp_dma_irq, vpfe_dev);
+}
+
+/**
+ * vpfe_attach_irq() - Attach IRQs for vpfe capture driver
+ * @vpfe_dev - ptr to vpfe capture device
+ *
+ * Attach all IRQs defined in vpfe configuration.
+ */
+static int vpfe_attach_irq(struct vpfe_device *vpfe_dev)
+{
+	int ret = 0;
+
+	ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED,
+			"vpfe_capture0", vpfe_dev);
+	if (ret < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"Error: requesting VINT0 interrupt\n");
+		return ret;
+	}
+
+	ret = request_irq(vpfe_dev->ccdc_irq1, vpfe_vdint1_isr, IRQF_DISABLED,
+					"vpfe_capture1", vpfe_dev);
+	if (ret < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"Error: requesting VINT1 interrupt\n");
+		free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+		return ret;
+	}
+
+	ret = request_irq(vpfe_dev->imp_dma_irq, vpfe_imp_dma_isr,
+			  IRQF_DISABLED, "Imp_Sdram_Irq", vpfe_dev);
+	if (ret < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			 "Error: requesting IMP IRQ interrupt\n");
+		free_irq(vpfe_dev->ccdc_irq1, vpfe_dev);
+		free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * register_i2c_devices() - register all i2c v4l2 subdevs
+ * @vpfe_dev - ptr to vpfe capture device
+ *
+ * register all i2c v4l2 subdevs
+ */
+static int register_i2c_devices(struct vpfe_device *vpfe_dev)
+{
+	struct vpfe_ext_subdev_info *sdinfo;
+	struct vpfe_config *vpfe_cfg;
+	struct i2c_adapter *i2c_adap;
+	unsigned int num_subdevs;
+	int ret;
+	int i;
+	int k;
+
+	vpfe_cfg = vpfe_dev->cfg;
+
+	i2c_adap = i2c_get_adapter(1);
+	num_subdevs = vpfe_cfg->num_subdevs;
+
+	vpfe_dev->sd = kzalloc(sizeof(struct v4l2_subdev *)*num_subdevs,
+			       GFP_KERNEL);
+
+	if (vpfe_dev->sd == NULL) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"unable to allocate memory for subdevice\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0, k = 0; i < num_subdevs; i++) {
+		sdinfo = &vpfe_cfg->sub_devs[i];
+		/**
+		 * register subdevices based on interface setting. Currently
+		 * tvp5146 and mt9p031 cannot co-exists due to i2c address
+		 * conflicts. So only one of them is registered. Re-visit this
+		 * once we have support for i2c switch handling in i2c driver
+		 * framework
+		 */
+
+		if (interface == sdinfo->is_camera) {
+			/* setup input path */
+			if (vpfe_cfg->setup_input &&
+				vpfe_cfg->setup_input(sdinfo->grp_id) < 0) {
+				ret = -EFAULT;
+				v4l2_info(&vpfe_dev->v4l2_dev,
+					  "could not setup input for %s\n",
+						sdinfo->module_name);
+				goto probe_sd_out;
+			}
+			/* Load up the subdevice */
+			vpfe_dev->sd[k] =
+				v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
+						  i2c_adap, &sdinfo->board_info,
+						  NULL);
+			if (vpfe_dev->sd[k]) {
+				v4l2_info(&vpfe_dev->v4l2_dev,
+						"v4l2 sub device %s registered\n",
+						sdinfo->module_name);
+
+				vpfe_dev->sd[k]->grp_id = sdinfo->grp_id;
+				k++;
+
+				sdinfo->registered = 1;
+			}
+		} else {
+			v4l2_info(&vpfe_dev->v4l2_dev,
+				  "v4l2 sub device %s is not registered\n",
+				  sdinfo->module_name);
+		}
+	}
+
+	vpfe_dev->num_ext_subdevs = k;
+
+	return 0;
+
+probe_sd_out:
+	kzfree(vpfe_dev->sd);
+
+	return ret;
+}
+
+/**
+ * vpfe_register_entities() - register all v4l2 subdevs and media entities
+ * @vpfe_dev - ptr to vpfe capture device
+ *
+ * register all v4l2 subdevs, media entities, and creates links
+ * between entities
+ */
+static int vpfe_register_entities(struct vpfe_device *vpfe_dev)
+{
+	unsigned int flags = 0;
+	int ret;
+	int i;
+
+	/* register i2c devices first */
+	ret = register_i2c_devices(vpfe_dev);
+	if (ret)
+		return ret;
+
+	/* register rest of the sub-devs */
+	ret = vpfe_ccdc_register_entities(&vpfe_dev->vpfe_ccdc,
+					  &vpfe_dev->v4l2_dev);
+	if (ret)
+		return ret;
+
+	ret = vpfe_previewer_register_entities(&vpfe_dev->vpfe_previewer,
+					       &vpfe_dev->v4l2_dev);
+	if (ret)
+		goto out_ccdc_register;
+
+	ret = vpfe_resizer_register_entities(&vpfe_dev->vpfe_resizer,
+					     &vpfe_dev->v4l2_dev);
+	if (ret)
+		goto out_previewer_register;
+	/* create links now, starting with external(i2c) entities */
+	for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) {
+		/* if entity has no pads (ex: amplifier),
+		   cant establish link */
+		if (vpfe_dev->sd[i]->entity.num_pads) {
+			ret = media_entity_create_link(&vpfe_dev->sd[i]->entity,
+				0, &vpfe_dev->vpfe_ccdc.subdev.entity,
+				0, flags);
+			if (ret < 0)
+				goto out_resizer_register;
+		}
+	}
+	ret = media_entity_create_link(&vpfe_dev->vpfe_ccdc.subdev.entity, 1,
+				       &vpfe_dev->vpfe_previewer.subdev.entity,
+				       0, flags);
+	if (ret < 0)
+		goto out_resizer_register;
+
+	ret = media_entity_create_link(&vpfe_dev->vpfe_previewer.subdev.entity,
+				       1, &vpfe_dev->vpfe_resizer.subdev.entity,
+				       0, flags);
+	if (ret < 0)
+		goto out_resizer_register;
+
+	ret = v4l2_device_register_subdev_nodes(&vpfe_dev->v4l2_dev);
+	if (ret < 0)
+		goto out_resizer_register;
+
+	return 0;
+
+out_resizer_register:
+	vpfe_resizer_unregister_entities(&vpfe_dev->vpfe_resizer);
+out_previewer_register:
+	vpfe_previewer_unregister_entities(&vpfe_dev->vpfe_previewer);
+out_ccdc_register:
+	vpfe_ccdc_unregister_entities(&vpfe_dev->vpfe_ccdc);
+	return ret;
+}
+
+/**
+ * vpfe_unregister_entities() - unregister all v4l2 subdevs and media entities
+ * @vpfe_dev - ptr to vpfe capture device
+ *
+ * unregister all v4l2 subdevs and media entities
+ */
+static void vpfe_unregister_entities(struct vpfe_device *vpfe_dev)
+{
+	vpfe_ccdc_unregister_entities(&vpfe_dev->vpfe_ccdc);
+	vpfe_previewer_unregister_entities(&vpfe_dev->vpfe_previewer);
+	vpfe_resizer_unregister_entities(&vpfe_dev->vpfe_resizer);
+}
+
+/**
+ * vpfe_cleanup_modules() - cleanup all non-i2c v4l2 subdevs
+ * @vpfe_dev - ptr to vpfe capture device
+ * @pdev - pointer to platform device
+ *
+ * cleanup all v4l2 subdevs
+ */
+static void vpfe_cleanup_modules(struct vpfe_device *vpfe_dev,
+				 struct platform_device *pdev)
+{
+	vpfe_ccdc_cleanup(pdev);
+	vpfe_previewer_cleanup(pdev, vpfe_dev->ipipe);
+}
+
+/**
+ * vpfe_initialize_modules() - initialize all non-i2c v4l2 subdevs
+ * @vpfe_dev - ptr to vpfe capture device
+ * @pdev - pointer to platform device
+ *
+ * intialize all v4l2 subdevs and media entities
+ */
+static int vpfe_initialize_modules(struct vpfe_device *vpfe_dev,
+				   struct platform_device *pdev)
+{
+	int ret;
+
+	ret = vpfe_ccdc_init(&vpfe_dev->vpfe_ccdc, pdev);
+	if (ret)
+		return ret;
+
+	ret = vpfe_previewer_init(&vpfe_dev->vpfe_previewer, pdev);
+	if (ret)
+		goto out_ccdc_init;
+
+	ret = vpfe_resizer_init(&vpfe_dev->vpfe_resizer, pdev);
+	if (ret)
+		goto out_previewer_init;
+
+	return 0;
+
+out_previewer_init:
+	vpfe_previewer_cleanup(pdev, vpfe_dev->ipipe);
+out_ccdc_init:
+	vpfe_ccdc_cleanup(pdev);
+
+	return ret;
+}
+
+/**
+ * vpfe_probe() : vpfe probe function
+ * @pdev: platform device pointer
+ *
+ * This function creates device entries by register itself to the V4L2 driver
+ * and initializes fields of each device objects
+ */
+static __devinit int vpfe_probe(struct platform_device *pdev)
+{
+	struct vpfe_device *vpfe_dev;
+	struct resource *res1;
+	unsigned long phys_end_kernel;
+	int ret = -ENOMEM;
+	int err;
+	size_t size;
+
+	vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL);
+	if (!vpfe_dev) {
+		v4l2_err(pdev->dev.driver,
+			"Failed to allocate memory for vpfe_dev\n");
+		return ret;
+	}
+
+	if (pdev->dev.platform_data == NULL) {
+		v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n");
+		ret = -ENOENT;
+		goto probe_free_dev_mem;
+	}
+
+	vpfe_dev->cfg = pdev->dev.platform_data;
+
+	if (vpfe_dev->cfg->card_name == NULL ||
+			vpfe_dev->cfg->sub_devs == NULL) {
+		v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n");
+		ret = -ENOENT;
+		goto probe_free_dev_mem;
+	}
+
+	/* Get VINT0 irq resource */
+	res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res1) {
+		v4l2_err(pdev->dev.driver,
+			 "Unable to get interrupt for VINT0\n");
+		ret = -ENOENT;
+		goto probe_free_dev_mem;
+	}
+	vpfe_dev->ccdc_irq0 = res1->start;
+
+	/* Get VINT1 irq resource */
+	res1 = platform_get_resource(pdev,
+				IORESOURCE_IRQ, 1);
+	if (!res1) {
+		v4l2_err(pdev->dev.driver,
+			 "Unable to get interrupt for VINT1\n");
+		ret = -ENOENT;
+		goto probe_free_dev_mem;
+	}
+	vpfe_dev->ccdc_irq1 = res1->start;
+
+	/* Get DMA irq resource */
+	res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+	if (!res1) {
+		v4l2_err(pdev->dev.driver,
+			 "Unable to get interrupt for DMA\n");
+		ret = -ENOENT;
+		goto probe_free_dev_mem;
+	}
+	vpfe_dev->imp_dma_irq = res1->start;
+
+	vpfe_dev->pdev = &pdev->dev;
+
+	/* enable vpss clocks */
+	ret = vpfe_enable_clock(vpfe_dev);
+	if (ret)
+		goto probe_free_dev_mem;
+
+	if (vpfe_initialize_modules(vpfe_dev, pdev))
+		goto probe_disable_clock;
+
+	vpfe_initialize(vpfe_dev);
+
+	vpfe_dev->media_dev.dev = vpfe_dev->pdev;
+	strcpy((char *)&vpfe_dev->media_dev.model, "davinci-media");
+	ret = media_device_register(&vpfe_dev->media_dev);
+	if (ret) {
+		v4l2_err(pdev->dev.driver,
+			"Unable to register media device.\n");
+		goto probe_out_entities_cleanup;
+	}
+
+	vpfe_dev->v4l2_dev.mdev = &vpfe_dev->media_dev;
+
+	ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev);
+	if (ret) {
+		v4l2_err(pdev->dev.driver, "Unable to register v4l2 device.\n");
+		goto probe_out_media_unregister;
+	}
+	v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n");
+
+	/* set the driver data in platform device */
+	platform_set_drvdata(pdev, vpfe_dev);
+
+	/* register subdevs/entities */
+	if (vpfe_register_entities(vpfe_dev))
+		goto probe_out_v4l2_unregister;
+
+	ret = vpfe_attach_irq(vpfe_dev);
+	if (ret)
+		goto probe_out_entities_unregister;
+
+	if (cont_bufsize) {
+		/* attempt to determine the end of Linux kernel memory */
+		phys_end_kernel = virt_to_phys((void *)PAGE_OFFSET) +
+			(num_physpages << PAGE_SHIFT);
+		size = cont_bufsize;
+		phys_end_kernel += cont_bufoffset;
+		err = dma_declare_coherent_memory(&pdev->dev, phys_end_kernel,
+				phys_end_kernel, size,
+				DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+		if (!err) {
+			dev_err(&pdev->dev, "Unable to declare MMAP memory.\n");
+			ret = -ENOENT;
+			goto probe_detach_irq;
+		}
+		vpfe_dev->video_limit = size;
+	}
+
+	return 0;
+
+probe_detach_irq:
+	vpfe_detach_irq(vpfe_dev);
+probe_out_entities_unregister:
+	vpfe_unregister_entities(vpfe_dev);
+	kzfree(vpfe_dev->sd);
+probe_out_v4l2_unregister:
+	v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+probe_out_media_unregister:
+	media_device_unregister(&vpfe_dev->media_dev);
+probe_out_entities_cleanup:
+	vpfe_cleanup_modules(vpfe_dev, pdev);
+probe_disable_clock:
+	vpfe_disable_clock(vpfe_dev);
+probe_free_dev_mem:
+	kzfree(vpfe_dev);
+
+	return ret;
+}
+
+/*
+ * vpfe_remove : This function un-registers device from V4L2 driver
+ */
+static int vpfe_remove(struct platform_device *pdev)
+{
+	struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
+
+	v4l2_info(pdev->dev.driver, "vpfe_remove\n");
+
+	kzfree(vpfe_dev->sd);
+	vpfe_detach_irq(vpfe_dev);
+	vpfe_unregister_entities(vpfe_dev);
+	vpfe_cleanup_modules(vpfe_dev, pdev);
+	v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+	media_device_unregister(&vpfe_dev->media_dev);
+	vpfe_disable_clock(vpfe_dev);
+	kzfree(vpfe_dev);
+
+	return 0;
+}
+
+static struct platform_driver vpfe_driver = {
+	.driver = {
+		.name = CAPTURE_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = vpfe_probe,
+	.remove = __devexit_p(vpfe_remove),
+};
+
+/**
+ * vpfe_init : This function registers device driver
+ */
+static __init int vpfe_init(void)
+{
+	/* Register driver to the kernel */
+	return platform_driver_register(&vpfe_driver);
+}
+
+/**
+ * vpfe_cleanup : This function un-registers device driver
+ */
+static void vpfe_cleanup(void)
+{
+	platform_driver_unregister(&vpfe_driver);
+}
+
+module_init(vpfe_init);
+module_exit(vpfe_cleanup);
diff --git a/drivers/media/platform/davinci/vpfe_mc_capture.h b/drivers/media/platform/davinci/vpfe_mc_capture.h
new file mode 100644
index 0000000..aba0a00
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_mc_capture.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _VPFE_MC_CAPTURE_H
+#define _VPFE_MC_CAPTURE_H
+
+/* Header files */
+#include <linux/i2c.h>
+#include <linux/v4l2-subdev.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "vpfe_video.h"
+#include "vpfe_af.h"
+#include "vpfe_aew.h"
+#include "vpfe_ccdc.h"
+#include "imp_hw_if.h"
+#include "vpfe_resizer.h"
+#include "vpfe_previewer.h"
+#include "vpfe_imp_common.h"
+
+/* Macros */
+#define VPFE_MAJOR_RELEASE		0
+#define VPFE_MINOR_RELEASE		0
+#define VPFE_BUILD			1
+#define VPFE_CAPTURE_VERSION_CODE       ((VPFE_MAJOR_RELEASE << 16) | \
+					(VPFE_MINOR_RELEASE << 8)  | \
+					VPFE_BUILD)
+
+#define to_vpfe_device(ptr_module)				\
+	container_of(ptr_module, struct vpfe_device, vpfe_##ptr_module)
+#define to_device(ptr_module)						\
+	(to_vpfe_device(ptr_module)->dev)
+
+struct vpfe_device {
+	/* external registered sub devices */
+	struct v4l2_subdev		**sd;
+	/* number of registered external subdevs */
+	unsigned int			num_ext_subdevs;
+	/* vpfe cfg */
+	struct vpfe_config		*cfg;
+	/* clock ptrs for vpfe capture */
+	struct clk			**clks;
+	/* V4l2 device */
+	struct v4l2_device		v4l2_dev;
+	/* parent device */
+	struct device			*pdev;
+	/* IRQ number for DMA transfer completion at the image processor */
+	unsigned int			imp_dma_irq;
+	/* CCDC IRQs used when CCDC/ISIF output to SDRAM */
+	unsigned int			ccdc_irq0;
+	unsigned int			ccdc_irq1;
+	/* maximum video memory that is available*/
+	unsigned int			video_limit;
+	/* media device */
+	struct media_device		media_dev;
+	/* ccdc subdevice */
+	struct vpfe_ccdc_device		vpfe_ccdc;
+	/* resizer subdevice */
+	struct vpfe_resizer_device	vpfe_resizer;
+	/* previewer subdevice */
+	struct vpfe_previewer_device	vpfe_previewer;
+	/* aew subdevice */
+	struct vpfe_aew_device		vpfe_aew;
+	/* af subdevice */
+	struct vpfe_af_device		vpfe_af;
+	void				*ipipe;
+};
+
+/* File handle structure */
+struct vpfe_fh {
+	struct vpfe_video_device *video;
+	/* Indicates whether this file handle is doing IO */
+	u8 io_allowed;
+	/* Used to keep track priority of this instance */
+	enum v4l2_priority prio;
+};
+
+void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus,
+			   struct v4l2_pix_format *pix);
+
+#endif	/* _VPFE_MC_CAPTURE_H */
diff --git a/include/media/davinci/vpfe.h b/include/media/davinci/vpfe.h
new file mode 100644
index 0000000..15bca28
--- /dev/null
+++ b/include/media/davinci/vpfe.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _VPFE_H
+#define _VPFE_H
+
+#ifdef __KERNEL__
+#include <linux/v4l2-subdev.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+
+#define CAPTURE_DRV_NAME	"vpfe-capture"
+
+struct vpfe_route {
+	__u32 input;
+	__u32 output;
+};
+
+enum vpfe_subdev_id {
+	VPFE_SUBDEV_TVP5146 = 1,
+	VPFE_SUBDEV_MT9T031 = 2,
+	VPFE_SUBDEV_TVP7002 = 3,
+	VPFE_SUBDEV_MT9P031 = 4,
+};
+
+struct vpfe_ext_subdev_info {
+	/* v4l2 subdev */
+	struct v4l2_subdev *subdev;
+	/* Sub device module name */
+	char module_name[32];
+	/* Sub device group id */
+	int grp_id;
+	/* Number of inputs supported */
+	int num_inputs;
+	/* inputs available at the sub device */
+	struct v4l2_input *inputs;
+	/* Sub dev routing information for each input */
+	struct vpfe_route *routes;
+	/* ccdc bus/interface configuration */
+	struct vpfe_hw_if_param ccdc_if_params;
+	/* i2c subdevice board info */
+	struct i2c_board_info board_info;
+	/* Is this a camera sub device ? */
+	unsigned is_camera:1;
+	/* check if sub dev supports routing */
+	unsigned can_route:1;
+	/* registered ? */
+	unsigned registered:1;
+};
+
+struct vpfe_config {
+	/* Number of sub devices connected to vpfe */
+	int num_subdevs;
+	/* information about each subdev */
+	struct vpfe_ext_subdev_info *sub_devs;
+	/* evm card info */
+	char *card_name;
+	/* setup function for the input path */
+	int (*setup_input)(enum vpfe_subdev_id id);
+	/* number of clocks */
+	int num_clocks;
+	/* clocks used for vpfe capture */
+	char *clocks[];
+};
+#endif
+#endif
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 08/14] davinci: vpfe: previewer driver based on v4l2 media controller framework
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (6 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 07/14] davinci: vpfe: v4l2 capture driver with media interface Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 09/14] davinci: vpfe: resizer driver based on media framework Prabhakar Lad
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

Add the video previewer driver with the v4l2 media controller framework
which takes care of converting the video frames from bayer to YUV or RGB.
The driver supports both continuous mode where it works in tandem with
the CCDC and single shot mode where it can be used in isolation. The
driver underneath uses the dm365 IPIPE module for programming the
hardware. The driver supports previewer as a subdevice and a media entity,
and the enumerable pads are 2(1 input and 1 output). The driver supports
streaing and all the pad and link related operations. Specific functions
like defect pixel correction, LUT are supported through private ioctls.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/vpfe_previewer.c | 1041 +++++++++++++++++++++++
 drivers/media/platform/davinci/vpfe_previewer.h |   71 ++
 2 files changed, 1112 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/platform/davinci/vpfe_previewer.c
 create mode 100644 drivers/media/platform/davinci/vpfe_previewer.h

diff --git a/drivers/media/platform/davinci/vpfe_previewer.c b/drivers/media/platform/davinci/vpfe_previewer.c
new file mode 100644
index 0000000..4a0fc8e
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_previewer.c
@@ -0,0 +1,1041 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/platform_device.h>
+#include <linux/davinci_vpfe.h>
+
+#include <media/v4l2-device.h>
+#include <media/davinci/vpss.h>
+#include <media/media-entity.h>
+#include <media/davinci/vpfe_types.h>
+
+#include "vpfe_mc_capture.h"
+#include "imp_hw_if.h"
+
+#define MIN_OUT_WIDTH	32
+#define MIN_OUT_HEIGHT	32
+
+static int serializer_initialized;
+static struct imp_serializer imp_serializer_info;
+
+/* previewer input format descriptions */
+static const unsigned int prev_input_fmts[] = {
+	V4L2_MBUS_FMT_UYVY8_2X8,
+	V4L2_MBUS_FMT_SGRBG12_1X12,
+};
+
+/* previewer ouput format descriptions */
+static const unsigned int prev_output_fmts[] = {
+	V4L2_MBUS_FMT_UYVY8_2X8,
+};
+
+/*
+ * imp_set_preview_config() - set previewer config
+ * @sd: Pointer previewer subdevice
+ * @chan_config: previewer channel configuration
+ */
+static int
+imp_set_preview_config(struct v4l2_subdev *sd,
+		       struct vpfe_prev_config *chan_config)
+{
+	struct vpfe_previewer_device *previewer = v4l2_get_subdevdata(sd);
+	struct imp_logical_channel *channel = &previewer->channel;
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	struct device *dev = previewer->subdev.v4l2_dev->dev;
+	int ret;
+
+	if (channel->config_state == STATE_NOT_CONFIGURED) {
+		channel->config = imp_hw_if->alloc_config_block(dev,
+							vpfe_dev->ipipe);
+		/* allocate buffer for holding user configuration */
+		channel->user_config = imp_hw_if->alloc_user_config_block(dev,
+						vpfe_dev->ipipe, IMP_PREVIEWER);
+		if (!channel->user_config) {
+			dev_err(dev,
+				"Failed to allocate memory for user config\n");
+			return -EFAULT;
+		}
+	}
+
+	if (!chan_config->ipipeif_config) {
+		dev_dbg(dev, "imp_set_preview_config: default configuration set\n");
+		/* put defaults for user configuration */
+		imp_hw_if->set_user_config_defaults(dev, vpfe_dev->ipipe,
+					IMP_PREVIEWER, channel->user_config);
+	} else {
+		dev_dbg(dev, "imp_set_preview_config: user configuration set\n");
+		if (copy_from_user(channel->user_config,
+			chan_config->ipipeif_config,
+				sizeof(struct prev_ipipeif_config)))
+			return -EFAULT;
+	}
+
+	/* Update the user configuration in the hw config block */
+	ret = imp_hw_if->set_preview_config(dev, vpfe_dev->ipipe,
+				channel->user_config, channel->config);
+
+	if (ret < 0)
+		dev_err(dev, "Failed to set previewer config\n");
+
+	channel->config_state = STATE_CONFIGURED;
+
+	return ret;
+}
+
+/*
+ * imp_get_preview_config() - get current previewer config
+ * @previewer: vpfe previewer device pointer
+ * @channel: image processor logical channel
+ * @chan_config: previewer channel configuration
+ */
+static int
+imp_get_preview_config(struct v4l2_subdev *sd,
+		       struct vpfe_prev_config *chan_config)
+{
+	struct vpfe_previewer_device *previewer = v4l2_get_subdevdata(sd);
+	struct imp_logical_channel *channel = &previewer->channel;
+	struct device *dev = previewer->subdev.v4l2_dev->dev;
+
+	if (channel->config_state != STATE_CONFIGURED) {
+		dev_err(dev, "previewer channel not configured\n");
+		return -EINVAL;
+	}
+
+	if (!chan_config->ipipeif_config) {
+		dev_err(dev, "Invalid channel configuration pointer\n");
+		return -EINVAL;
+	}
+
+	if (copy_to_user((void *)chan_config->ipipeif_config,
+			 (void *)channel->user_config,
+			 sizeof(struct prev_ipipeif_config))) {
+		dev_err(dev, "imp_get_preview_config: Error in copy to user\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*
+ * imp_init_serializer - intilaize serializer
+ */
+static int imp_init_serializer(void)
+{
+	if (serializer_initialized)
+		return 0;
+
+	memset((void *)&imp_serializer_info, (char)0,
+		sizeof(struct imp_serializer));
+	init_completion(&imp_serializer_info.sem_isr);
+	imp_serializer_info.sem_isr.done = 0;
+	imp_serializer_info.array_count = 0;
+	mutex_init(&imp_serializer_info.array_sem);
+	serializer_initialized = 1;
+
+	return 0;
+}
+
+/*
+ * set_channel_prv_cont_mode() - Set continous channel mode
+ * @previewer: vpfe previewer device pointer
+ */
+static int set_channel_prv_cont_mode(struct vpfe_previewer_device *previewer)
+{
+	struct imp_logical_channel *channel = &previewer->channel;
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+
+	channel->type = IMP_PREVIEWER;
+	channel->config_state = STATE_NOT_CONFIGURED;
+
+	return imp_hw_if->set_oper_mode(vpfe_dev->ipipe, IMP_MODE_CONTINUOUS);
+}
+
+/*
+ * set_channel_prv_ss_mode() - Set single-shot channel mode
+ * @previewer: vpfe previewer device pointer
+ */
+static int set_channel_prv_ss_mode(struct vpfe_previewer_device *previewer)
+{
+	struct imp_logical_channel *channel = &previewer->channel;
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+
+	channel->type = IMP_PREVIEWER;
+	channel->config_state = STATE_NOT_CONFIGURED;
+
+	return imp_hw_if->set_oper_mode(vpfe_dev->ipipe, IMP_MODE_SINGLE_SHOT);
+}
+
+/*
+ * reset_channel_prv_mode() - Reset channel mode
+ * @previewer: vpfe previewer device pointer
+ */
+static void reset_channel_prv_mode(struct vpfe_previewer_device *previewer)
+{
+	struct imp_logical_channel *channel = &previewer->channel;
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+
+	imp_hw_if->reset_oper_mode(vpfe_dev->ipipe);
+
+	if (channel->config_state == STATE_CONFIGURED) {
+		kfree(channel->user_config);
+		memset(channel, 0, sizeof(struct imp_logical_channel));
+	}
+}
+
+/*
+ * prv_video_in_queue() - PREVIEWER video in queue
+ * @vpfe_dev: vpfe device pointer
+ * @addr: buffer address
+ */
+static void
+prv_video_in_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
+{
+	struct vpfe_previewer_device *previewer = &vpfe_dev->vpfe_previewer;
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct imp_logical_channel *chan = &previewer->channel;
+
+	if (previewer->input == PREVIEWER_INPUT_MEMORY)
+		imp_hw_if->update_inbuf_address(chan->config, addr);
+	else
+		imp_hw_if->update_inbuf_address(NULL, addr);
+}
+
+/*
+ * prv_video_out_queue() - PREVIEWER video out queue
+ * @vpfe_dev: vpfe device pointer
+ * @addr: buffer address
+ */
+static void
+prv_video_out_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
+{
+	struct vpfe_previewer_device *previewer = &vpfe_dev->vpfe_previewer;
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct imp_logical_channel *chan = &previewer->channel;
+
+	if (previewer->input == PREVIEWER_INPUT_MEMORY)
+		imp_hw_if->update_outbuf1_address(vpfe_dev->ipipe,
+						  chan->config, addr);
+	else
+		imp_hw_if->update_outbuf1_address(vpfe_dev->ipipe, NULL, addr);
+}
+
+static const struct vpfe_video_operations video_in_ops = {
+	.queue = prv_video_in_queue,
+};
+
+static const struct vpfe_video_operations video_out_ops = {
+	.queue = prv_video_out_queue,
+};
+
+/*
+ * prv_ss_buffer_isr() - PREVIEWER module single-shot buffer scheduling isr
+ * @previewer: PREVIEWER device pointer
+ *
+ */
+static void prv_ss_buffer_isr(struct vpfe_previewer_device *previewer)
+{
+	struct vpfe_video_device *video_out = &previewer->video_out;
+	struct vpfe_video_device *video_in = &previewer->video_in;
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	struct imp_logical_channel *chan = &previewer->channel;
+	struct vpfe_pipeline *pipe = &video_out->pipe;
+	u32 val;
+
+	if (!video_in->started)
+		return;
+
+	if (previewer->output == PREVIEWER_OUTPUT_MEMORY) {
+		val = vpss_dma_complete_interrupt();
+		if (val != 0 && val != 2)
+			return;
+	}
+
+	if (previewer->input == PREVIEWER_INPUT_MEMORY) {
+		spin_lock(&video_in->dma_queue_lock);
+		vpfe_process_buffer_complete(video_in);
+		video_in->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
+		vpfe_schedule_next_buffer(video_in);
+		spin_unlock(&video_in->dma_queue_lock);
+	}
+
+	if (previewer->output == PREVIEWER_OUTPUT_MEMORY) {
+		spin_lock(&video_out->dma_queue_lock);
+		vpfe_process_buffer_complete(video_out);
+		video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
+		vpfe_schedule_next_buffer(video_out);
+		spin_unlock(&video_out->dma_queue_lock);
+
+		/* start HW if buffers are queued */
+		if (is_pipe_ready(pipe))
+			imp_hw_if->enable(vpfe_dev->ipipe, 1, chan->config);
+	}
+}
+
+/*
+ * prv_buffer_isr() - PREVIEWER module buffer scheduling isr
+ * @previewer: PREVIEWER device pointer
+ *
+ */
+void prv_buffer_isr(struct vpfe_previewer_device *previewer)
+{
+	struct vpfe_video_device *video_out = &previewer->video_out;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	enum v4l2_field field;
+	int fid;
+
+	if (!video_out->started)
+		return;
+
+	if (previewer->input != PREVIEWER_INPUT_CCDC)
+		return;
+
+	field = video_out->fmt.fmt.pix.field;
+
+	if (field == V4L2_FIELD_NONE) {
+		/* handle progressive frame capture */
+		if (video_out->cur_frm != video_out->next_frm)
+			vpfe_process_buffer_complete(video_out);
+		return;
+	}
+	/* handle interlaced frame capture */
+	fid = ccdc_get_fid(vpfe_dev);
+
+	/* switch the software maintained field id */
+	video_out->field_id ^= 1;
+	if (fid == video_out->field_id) {
+		/*
+		 * we are in-sync here,continue.
+		 * One frame is just being captured. If the
+		 * next frame is available, release the current
+		 * frame and move on
+		 */
+		if (fid == 0 && video_out->cur_frm != video_out->next_frm)
+			vpfe_process_buffer_complete(video_out);
+	} else if (fid == 0) {
+		/*
+		  * out of sync. Recover from any hardware out-of-sync.
+		  * May loose one frame
+		  */
+		video_out->field_id = fid;
+	}
+}
+
+/*
+ * prv_dma_isr() - PREVIEWER module dma isr
+ * @previewer: PREVIEWER device pointer
+ *
+ */
+void prv_dma_isr(struct vpfe_previewer_device *previewer)
+{
+	struct vpfe_video_device *video_out = &previewer->video_out;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	enum v4l2_field field;
+	int schedule_capture = 0;
+	int fid;
+
+	if (previewer->input == PREVIEWER_INPUT_MEMORY) {
+		prv_ss_buffer_isr(previewer);
+		return;
+	}
+
+	if (!video_out->started)
+		return;
+
+	field = video_out->fmt.fmt.pix.field;
+
+	if (field == V4L2_FIELD_NONE) {
+		if (!list_empty(&video_out->dma_queue) &&
+				video_out->cur_frm == video_out->next_frm)
+			schedule_capture = 1;
+	} else {
+		fid = ccdc_get_fid(vpfe_dev);
+		if (fid == video_out->field_id) {
+			/* we are in-sync here,continue */
+			if (fid == 1 && !list_empty(&video_out->dma_queue) &&
+				  video_out->cur_frm == video_out->next_frm)
+				schedule_capture = 1;
+		}
+	}
+	if (!schedule_capture)
+		return;
+	spin_lock(&video_out->dma_queue_lock);
+
+	vpfe_schedule_next_buffer(video_out);
+	spin_unlock(&video_out->dma_queue_lock);
+
+	return;
+}
+
+static int
+preview_s_config(struct v4l2_subdev *sd, struct vpfe_prev_config *cfg)
+{
+	struct vpfe_previewer_device *previewer = v4l2_get_subdevdata(sd);
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	struct device *dev = previewer->subdev.v4l2_dev->dev;
+	unsigned int bit = 1 << 0;
+	int ret;
+
+	/* if ipipeif params are set */
+	if (cfg->flag & bit) {
+		ret =  imp_set_preview_config(sd, cfg);
+		if (ret)
+			return ret;
+	}
+	return imp_hw_if->set_preview_module_params(dev, vpfe_dev->ipipe, cfg);
+
+}
+
+static int
+preview_g_config(struct v4l2_subdev *sd, struct vpfe_prev_config *cfg)
+{
+	struct vpfe_previewer_device *previewer = v4l2_get_subdevdata(sd);
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	struct device *dev = previewer->subdev.v4l2_dev->dev;
+	unsigned int bit = 1 << 0;
+	int ret;
+
+	/* get ipipeif params */
+	if (cfg->flag & bit) {
+		ret =  imp_get_preview_config(sd, cfg);
+		if (ret)
+			return ret;
+	}
+	return imp_hw_if->get_preview_module_params(dev, vpfe_dev->ipipe, cfg);
+}
+
+/*
+ * previewer_ioctl() - PREVIEWER module private ioctl's
+ * @sd: VPFE PREVIEWER V4L2 subdevice
+ * @cmd: ioctl command
+ * @arg: ioctl argument
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static long previewer_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	case VIDIOC_VPFE_PRV_S_CONFIG:
+		ret = preview_s_config(sd, arg);
+		break;
+	case VIDIOC_VPFE_PRV_G_CONFIG:
+		ret = preview_g_config(sd, arg);
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+	}
+
+	return ret;
+}
+
+/*
+ * previewer_set_stream() - Enable/Disable streaming on the PREVIEWER module
+ * @sd: VPFE PREVIEWER V4L2 subdevice
+ * @enable: Enable/disable stream
+ */
+static int previewer_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct vpfe_previewer_device *previewer = v4l2_get_subdevdata(sd);
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	struct imp_logical_channel *chan = &previewer->channel;
+	struct device *dev = previewer->subdev.v4l2_dev->dev;
+
+	/* in case of single shot, send config to ipipe */
+	void *config = (previewer->input == PREVIEWER_INPUT_MEMORY) ?
+				chan->config : NULL;
+
+	if (previewer->output != PREVIEWER_OUTPUT_MEMORY)
+		return 0;
+
+	switch (enable) {
+	case 1:
+		if (previewer->input == PREVIEWER_INPUT_MEMORY &&
+				imp_hw_if->serialize(vpfe_dev->ipipe)) {
+			if (imp_hw_if->hw_setup(dev, vpfe_dev->ipipe,
+							config) < 0)
+				return -EINVAL;
+		} else if (previewer->input == PREVIEWER_INPUT_CCDC) {
+			imp_hw_if->lock_chain(vpfe_dev->ipipe);
+			if (imp_hw_if->hw_setup(dev, vpfe_dev->ipipe, NULL))
+				return -EINVAL;
+		}
+		imp_hw_if->enable(vpfe_dev->ipipe, 1, config);
+		break;
+	case 0:
+		imp_hw_if->enable(vpfe_dev->ipipe, 0, config);
+		if (previewer->input == PREVIEWER_INPUT_CCDC)
+			imp_hw_if->unlock_chain(vpfe_dev->ipipe);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Retrieve active or try format based on the request
+ */
+static struct v4l2_mbus_framefmt *
+__previewer_get_format(struct vpfe_previewer_device *prev,
+		       struct v4l2_subdev_fh *fh, unsigned int pad,
+		       enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(fh, pad);
+	return &prev->formats[pad];
+}
+
+/*
+ * preview_try_format() - Handle try format by pad subdev method
+ * @prev: VPFE preview device
+ * @fh : V4L2 subdev file handle
+ * @pad: pad num
+ * @fmt: pointer to v4l2 format structure
+ */
+static void
+preview_try_format(struct vpfe_previewer_device *prev,
+		   struct v4l2_subdev_fh *fh, unsigned int pad,
+		   struct v4l2_mbus_framefmt *fmt,
+		   enum v4l2_subdev_format_whence which)
+{
+	struct imp_hw_interface *imp_hw_if;
+	unsigned int max_out_height;
+	unsigned int max_out_width;
+	unsigned int i;
+
+	imp_hw_if = prev->imp_hw_if;
+	max_out_width = imp_hw_if->get_max_output_width(0);
+	max_out_height = imp_hw_if->get_max_output_height(0);
+
+	if (pad == PREVIEWER_PAD_SINK) {
+		for (i = 0; i < ARRAY_SIZE(prev_input_fmts); i++) {
+			if (fmt->code == prev_input_fmts[i])
+				break;
+		}
+
+		/* If not found, use SBGGR10 as default */
+		if (i >= ARRAY_SIZE(prev_input_fmts))
+			fmt->code = V4L2_MBUS_FMT_SGRBG12_1X12;
+	} else if (pad == PREVIEWER_PAD_SOURCE) {
+		for (i = 0; i < ARRAY_SIZE(prev_output_fmts); i++) {
+			if (fmt->code == prev_output_fmts[i])
+				break;
+		}
+
+		/* If not found, use UYVY as default */
+		if (i >= ARRAY_SIZE(prev_output_fmts))
+			fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+	}
+
+	fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width);
+	fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height);
+}
+
+/*
+ * previewer_set_format() - Set the video format on a pad
+ * @sd : VPFE PREVIEWER V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int
+previewer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+		     struct v4l2_subdev_format *fmt)
+{
+	struct vpfe_previewer_device *previewer = v4l2_get_subdevdata(sd);
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __previewer_get_format(previewer, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	preview_try_format(previewer, fh, fmt->pad, &fmt->format, fmt->which);
+	*format = fmt->format;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	if (fmt->pad == PREVIEWER_PAD_SINK &&
+			(previewer->input == PREVIEWER_INPUT_CCDC ||
+				previewer->input == PREVIEWER_INPUT_MEMORY)) {
+		/*
+		 *In continous mode,set IPEPE input format here.
+		 */
+		imp_hw_if->set_in_mbus_format(vpfe_dev->ipipe, &fmt->format);
+		previewer->formats[fmt->pad] = fmt->format;
+
+	} else if (fmt->pad == PREVIEWER_PAD_SOURCE &&
+			previewer->output == PREVIEWER_OUTPUT_RESIZER) {
+		previewer->formats[fmt->pad] = fmt->format;
+	} else if (fmt->pad == PREVIEWER_PAD_SOURCE &&
+			previewer->output == PREVIEWER_OUTPUT_MEMORY) {
+		imp_hw_if->set_out_mbus_format(vpfe_dev->ipipe, &fmt->format);
+		previewer->formats[fmt->pad] = fmt->format;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * previewer_get_format() - Retrieve the video format on a pad
+ * @sd : VPFE PREVIEWER V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int
+previewer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+		     struct v4l2_subdev_format *fmt)
+{
+	struct vpfe_previewer_device *previewer = v4l2_get_subdevdata(sd);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		fmt->format = previewer->formats[fmt->pad];
+	else
+		fmt->format = *(v4l2_subdev_get_try_format(fh, fmt->pad));
+
+	return 0;
+}
+
+/*
+ * previewer_enum_frame_size() - enum frame sizes on pads
+ * @sd: VPFE previewer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @code: pointer to v4l2_subdev_frame_size_enum structure
+ */
+static int
+previewer_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			  struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct vpfe_previewer_device *prev = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt format;
+
+	if (fse->index != 0)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = 1;
+	format.height = 1;
+	preview_try_format(prev, fh, fse->pad, &format,
+			   V4L2_SUBDEV_FORMAT_TRY);
+	fse->min_width = format.width;
+	fse->min_height = format.height;
+
+	if (format.code != fse->code)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = -1;
+	format.height = -1;
+	preview_try_format(prev, fh, fse->pad, &format,
+			   V4L2_SUBDEV_FORMAT_TRY);
+	fse->max_width = format.width;
+	fse->max_height = format.height;
+
+	return 0;
+}
+
+/*
+ * previewer_enum_mbus_code() - enum mbus codes for pads
+ * @sd: VPFE previewer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @code: pointer to v4l2_subdev_mbus_code_enum structure
+ */
+static int
+previewer_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			 struct v4l2_subdev_mbus_code_enum *code)
+{
+	switch (code->pad) {
+	case PREVIEWER_PAD_SINK:
+		if (code->index >= ARRAY_SIZE(prev_input_fmts))
+			return -EINVAL;
+
+		code->code = prev_input_fmts[code->index];
+		break;
+	case PREVIEWER_PAD_SOURCE:
+		if (code->index >= ARRAY_SIZE(prev_output_fmts))
+			return -EINVAL;
+
+		code->code = prev_output_fmts[code->index];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * preview_s_ctrl() - Handle set control subdev method
+ * @ctrl: pointer to v4l2 control structure
+ */
+static int preview_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vpfe_previewer_device *previewer =
+	     container_of(ctrl->handler, struct vpfe_previewer_device, ctrls);
+	struct imp_hw_interface *imp_hw_if = previewer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+
+	return imp_hw_if->prv_s_ctrl(vpfe_dev->ipipe,
+				ctrl->id, ctrl->val);
+
+}
+
+/*
+ * previewer_init_formats() - Initialize formats on all pads
+ * @sd: VPFE previewer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int
+previewer_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct vpfe_previewer_device *prv = v4l2_get_subdevdata(sd);
+	struct imp_hw_interface *imp_hw_if = prv->imp_hw_if;
+	struct v4l2_subdev_format format;
+
+	memset(&format, 0, sizeof(format));
+	format.pad = PREVIEWER_PAD_SINK;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+	format.format.width = imp_hw_if->get_max_output_width(0);
+	format.format.height = imp_hw_if->get_max_output_height(0);
+	previewer_set_format(sd, fh, &format);
+
+	memset(&format, 0, sizeof(format));
+	format.pad = PREVIEWER_PAD_SOURCE;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
+	format.format.width = imp_hw_if->get_max_output_width(0);
+	format.format.height = imp_hw_if->get_max_output_height(0);
+	previewer_set_format(sd, fh, &format);
+
+	return 0;
+}
+
+/* subdev core operations */
+static const struct v4l2_subdev_core_ops previewer_v4l2_core_ops = {
+	.ioctl = previewer_ioctl,
+};
+
+static const struct v4l2_ctrl_ops preview_ctrl_ops = {
+	.s_ctrl = preview_s_ctrl,
+};
+
+/* subdev file operations */
+static const struct  v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
+	.open = previewer_init_formats,
+};
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops previewer_v4l2_video_ops = {
+	.s_stream = previewer_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops previewer_v4l2_pad_ops = {
+	.enum_mbus_code = previewer_enum_mbus_code,
+	.enum_frame_size = previewer_enum_frame_size,
+	.get_fmt = previewer_get_format,
+	.set_fmt = previewer_set_format,
+};
+
+/* v4l2 subdev operation */
+static const struct v4l2_subdev_ops previewer_v4l2_ops = {
+	.core = &previewer_v4l2_core_ops,
+	.video = &previewer_v4l2_video_ops,
+	.pad = &previewer_v4l2_pad_ops,
+};
+
+/*
+ * Media entity operations
+ */
+
+/*
+ * previewer_link_setup - Setup PREVIEWER connections
+ * @entity: PREVIEWER media entity
+ * @local: Pad at the local end of the link
+ * @remote: Pad at the remote end of the link
+ * @flags: Link flags
+ *
+ * return -EINVAL or zero on success
+ */
+static int
+previewer_link_setup(struct media_entity *entity, const struct media_pad *local,
+		     const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct vpfe_previewer_device *previewer = v4l2_get_subdevdata(sd);
+
+	switch (local->index | media_entity_type(remote->entity)) {
+	case PREVIEWER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* Read from ccdc - continous mode */
+		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+			previewer->input = PREVIEWER_INPUT_NONE;
+			reset_channel_prv_mode(previewer);
+			break;
+		}
+		if (previewer->input != PREVIEWER_INPUT_NONE)
+			return -EBUSY;
+
+		if (set_channel_prv_cont_mode(previewer))
+			return -EINVAL;
+		previewer->input = PREVIEWER_INPUT_CCDC;
+		break;
+	case PREVIEWER_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+		/* Read from memory - single shot mode*/
+		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+			previewer->input = PREVIEWER_INPUT_NONE;
+			reset_channel_prv_mode(previewer);
+			break;
+		}
+		if (set_channel_prv_ss_mode(previewer))
+			return -EINVAL;
+
+		previewer->input = PREVIEWER_INPUT_MEMORY;
+		break;
+	case PREVIEWER_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* out to RESIZER */
+		if (flags & MEDIA_LNK_FL_ENABLED)
+			previewer->output = PREVIEWER_OUTPUT_RESIZER;
+		else
+			previewer->output = PREVIEWER_OUTPUT_NONE;
+
+		break;
+	case PREVIEWER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+		/* Write to memory */
+		if (flags & MEDIA_LNK_FL_ENABLED)
+			previewer->output = PREVIEWER_OUTPUT_MEMORY;
+		else
+			previewer->output = PREVIEWER_OUTPUT_NONE;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct media_entity_operations previewer_media_ops = {
+	.link_setup = previewer_link_setup,
+};
+
+/*
+ * vpfe_previewer_unregister_entities - PREVIEWER subdevs/video
+ * driver unregistrations.
+ * @vpfe_prev - pointer to previewer subdevice structure.
+ */
+void vpfe_previewer_unregister_entities(struct vpfe_previewer_device *vpfe_prev)
+{
+	/* unregister video devices */
+	vpfe_video_unregister(&vpfe_prev->video_in);
+	vpfe_video_unregister(&vpfe_prev->video_out);
+
+	/* cleanup entity */
+	media_entity_cleanup(&vpfe_prev->subdev.entity);
+	/* unregister subdev */
+	v4l2_device_unregister_subdev(&vpfe_prev->subdev);
+}
+
+/*
+ * vpfe_previewer_register_entities() - PREVIEWER subdevs/video
+ * driver registrations.
+ * @previewer - pointer to previewer subdevice structure.
+ * @vdev: pointer to v4l2 device structure.
+ */
+int
+vpfe_previewer_register_entities(struct vpfe_previewer_device *previewer,
+				 struct v4l2_device *vdev)
+{
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	unsigned int flags;
+	int ret;
+
+	/* Register the subdev */
+	ret = v4l2_device_register_subdev(vdev, &previewer->subdev);
+	if (ret) {
+		pr_err("Failed to register previewer as v4l2 subdevice\n");
+		return ret;
+	}
+
+	ret = vpfe_video_register(&previewer->video_in, vdev);
+	if (ret) {
+		pr_err("Failed to register previewer video-in device\n");
+		goto out_video_in_register;
+	}
+
+	previewer->video_in.vpfe_dev = vpfe_dev;
+
+	ret = vpfe_video_register(&previewer->video_out, vdev);
+	if (ret) {
+		pr_err("Failed to register previewer video-out device\n");
+		goto out_video_out_register;
+	}
+
+	previewer->video_out.vpfe_dev = vpfe_dev;
+
+	flags = 0;
+	ret = media_entity_create_link(&previewer->video_in.video_dev.entity, 0,
+				       &previewer->subdev.entity, 0, flags);
+	if (ret < 0)
+		goto out_create_link;
+
+	ret = media_entity_create_link(&previewer->subdev.entity, 1,
+				       &previewer->video_out.video_dev.entity,
+				       0, flags);
+	if (ret < 0)
+		goto out_create_link;
+
+	return 0;
+
+out_create_link:
+	vpfe_video_unregister(&previewer->video_out);
+out_video_out_register:
+	vpfe_video_unregister(&previewer->video_in);
+out_video_in_register:
+	media_entity_cleanup(&previewer->subdev.entity);
+	v4l2_device_unregister_subdev(&previewer->subdev);
+	return ret;
+}
+
+#define PRV_CONTRAST_HIGH	0xff
+#define PRV_BRIGHT_HIGH		0xff
+#define PRV_GAIN_HIGH		0x3ff
+
+/*
+ * vpfe_previewer_init - PREVIEWER module initilaization.
+ * @vpfe_prev - pointer to previewer subdevice structure.
+ * @pdev: platform device pointer.
+ */
+int
+vpfe_previewer_init(struct vpfe_previewer_device *previewer,
+		    struct platform_device *pdev)
+{
+	struct imp_logical_channel *channel = &previewer->channel;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(previewer);
+	struct media_pad *pads = &previewer->pads[0];
+	struct v4l2_subdev *sd = &previewer->subdev;
+	struct media_entity *me = &sd->entity;
+	int ret = 0;
+
+	if (ipipe_init(&vpfe_dev->ipipe))
+		return -EINVAL;
+
+	previewer->imp_hw_if = imp_get_hw_if();
+	if (!previewer->imp_hw_if)
+		return -EINVAL;
+
+	previewer->video_in.ops = &video_in_ops;
+	previewer->video_out.ops = &video_out_ops;
+
+	v4l2_subdev_init(sd, &previewer_v4l2_ops);
+	sd->internal_ops = &preview_v4l2_internal_ops;
+	strlcpy(sd->name, "DAVINCI PREVIEWER", sizeof(sd->name));
+	sd->grp_id = 1 << 16;	/* group ID for davinci subdevs */
+	v4l2_set_subdevdata(sd, previewer);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	pads[PREVIEWER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	pads[PREVIEWER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	previewer->input = PREVIEWER_INPUT_NONE;
+	previewer->output = PREVIEWER_OUTPUT_NONE;
+
+	channel->type = IMP_PREVIEWER;
+	channel->config_state = STATE_NOT_CONFIGURED;
+
+	me->ops = &previewer_media_ops;
+
+	v4l2_ctrl_handler_init(&previewer->ctrls, 3);
+	v4l2_ctrl_new_std(&previewer->ctrls, &preview_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, 0,
+			  PRV_BRIGHT_HIGH, 1, 16);
+	v4l2_ctrl_new_std(&previewer->ctrls, &preview_ctrl_ops,
+			  V4L2_CID_CONTRAST, 0,
+			  PRV_CONTRAST_HIGH, 1, 16);
+	v4l2_ctrl_new_std(&previewer->ctrls, &preview_ctrl_ops,
+			  V4L2_CID_GAIN, 0,
+			  PRV_GAIN_HIGH, 1, 512);
+	v4l2_ctrl_new_std_menu(&previewer->ctrls, &preview_ctrl_ops,
+			V4L2_CID_DPCM_PREDICTOR,
+			V4L2_DPCM_PREDICTOR_ADVANCED, 0,
+			V4L2_DPCM_PREDICTOR_SIMPLE);
+
+	v4l2_ctrl_handler_setup(&previewer->ctrls);
+	sd->ctrl_handler = &previewer->ctrls;
+
+	ret = media_entity_init(me, PREVIEWER_PADS_NUM, pads, 0);
+	if (ret)
+		return ret;
+
+	previewer->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	ret = vpfe_video_init(&previewer->video_in, "PRV");
+	if (ret) {
+		pr_err("Failed to init PRV video-in device\n");
+		goto out_ipipe_init;
+	}
+	previewer->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	ret = vpfe_video_init(&previewer->video_out, "PRV");
+	if (ret) {
+		pr_err("Failed to init PRV video-out device\n");
+		goto out_ipipe_init;
+	}
+	imp_init_serializer();
+
+	return 0;
+
+out_ipipe_init:
+	v4l2_ctrl_handler_free(&previewer->ctrls);
+	ipipe_cleanup(vpfe_dev->ipipe);
+	return ret;
+}
+
+/*
+ * vpfe_previewer_cleanup() - PREVIEWER module cleanup.
+ * @dev: Device pointer specific to the VPFE.
+ */
+void vpfe_previewer_cleanup(struct platform_device *pdev, void *ipipe)
+{
+	ipipe_cleanup(ipipe);
+}
diff --git a/drivers/media/platform/davinci/vpfe_previewer.h b/drivers/media/platform/davinci/vpfe_previewer.h
new file mode 100644
index 0000000..152ab71
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_previewer.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _VPFE_PREV_H
+#define _VPFE_PREV_H
+
+#include <media/v4l2-ctrls.h>
+
+#define PREVIEWER_PAD_SINK	0
+#define PREVIEWER_PAD_SOURCE	1
+
+#define PREVIEWER_PADS_NUM	2
+
+#define PREVIEWER_OUTPUT_NONE		0
+#define PREVIEWER_OUTPUT_MEMORY		(1 << 0)
+#define PREVIEWER_OUTPUT_RESIZER	(1 << 1)
+
+enum previewer_input_entity {
+	PREVIEWER_INPUT_NONE,
+	PREVIEWER_INPUT_MEMORY,
+	PREVIEWER_INPUT_CCDC,
+};
+
+
+struct vpfe_previewer_device {
+	struct v4l2_subdev		subdev;
+	struct media_pad		pads[PREVIEWER_PADS_NUM];
+	struct v4l2_mbus_framefmt	formats[PREVIEWER_PADS_NUM];
+	enum previewer_input_entity	input;
+	unsigned int			output;
+	struct v4l2_ctrl_handler        ctrls;
+
+	/* pointer to ipipe function pointers */
+	struct imp_hw_interface		*imp_hw_if;
+	struct imp_logical_channel	channel;
+
+	struct vpfe_video_device	video_in;
+	struct vpfe_video_device	video_out;
+};
+
+int vpfe_previewer_register_entities(struct vpfe_previewer_device *vpfe_prev,
+					struct v4l2_device *v4l2_dev);
+int vpfe_previewer_init(struct vpfe_previewer_device *vpfe_prev,
+					struct platform_device *pdev);
+void vpfe_previewer_unregister_entities
+			(struct vpfe_previewer_device *vpfe_prev);
+void prv_buffer_isr(struct vpfe_previewer_device *previewer);
+void vpfe_previewer_cleanup(struct platform_device *pdev, void *ipipe);
+void prv_dma_isr(struct vpfe_previewer_device *previewer);
+void enable_serializer(void *ipipe, int val);
+void ipipe_cleanup(void *ipipe);
+int ipipe_init(void **ipipe);
+#endif
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 09/14] davinci: vpfe: resizer driver based on media framework
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (7 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 08/14] davinci: vpfe: previewer driver based on v4l2 media controller framework Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 10/14] dm365: vpss: setup ISP registers Prabhakar Lad
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

Add the video resizer driver with the v4l2 media controller framework
which takes care of resizing the video frames with both up-scaling
downscaling facility. The formats that is supported is YUV422.
The driver supports both continuous mode where it works in
tandem with the CCDC and previewer and single shot mode where
it can be used in isolation or with previewer. The driver underneath
uses the dm365 IPIPE module for programming the hardware.
The driver supports resizer as a subdevice and a media entity,
and the enumerable pads are 2(1 input and 1 output). The driver
supports streaming and all the pad and link related operations.
Specific filter functionality including filter types are set
through private ioctls.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/vpfe_resizer.c | 1080 +++++++++++++++++++++++++
 drivers/media/platform/davinci/vpfe_resizer.h |   66 ++
 2 files changed, 1146 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/platform/davinci/vpfe_resizer.c
 create mode 100644 drivers/media/platform/davinci/vpfe_resizer.h

diff --git a/drivers/media/platform/davinci/vpfe_resizer.c b/drivers/media/platform/davinci/vpfe_resizer.c
new file mode 100644
index 0000000..8b98ff5
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_resizer.c
@@ -0,0 +1,1080 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/v4l2-device.h>
+#include <media/media-entity.h>
+#include <media/davinci/vpss.h>
+#include <media/davinci/vpfe_types.h>
+
+#include "vpfe_mc_capture.h"
+#include "imp_hw_if.h"
+
+
+#define MIN_IN_WIDTH		32
+#define MIN_IN_HEIGHT		32
+#define MAX_IN_WIDTH		4095
+#define MAX_IN_HEIGHT		4095
+#define MIN_OUT_WIDTH		16
+#define MIN_OUT_HEIGHT		2
+
+/* resizer pixel formats */
+static const unsigned int resz_input_fmts[] = {
+	V4L2_MBUS_FMT_UYVY8_2X8,
+#ifdef CONFIG_ARCH_DAVINCI_DM365
+	V4L2_MBUS_FMT_Y8_1X8,
+	V4L2_MBUS_FMT_UV8_1X8,
+#endif
+};
+
+static const unsigned int resz_output_fmts[] = {
+	V4L2_MBUS_FMT_UYVY8_2X8,
+#ifdef CONFIG_ARCH_DAVINCI_DM365
+	V4L2_MBUS_FMT_Y8_1X8,
+	V4L2_MBUS_FMT_UV8_1X8,
+	V4L2_MBUS_FMT_YDYUYDYV8_1X16,
+#endif
+};
+
+static char resizer_chained;
+/*
+ * imp_set_resizer_config() - set resizer config
+ * @resizer: vpfe resizer device pointer
+ * @channel: image processor logical channel
+ * @chan_config: resizer channel configuration
+ */
+static int imp_set_resizer_config(struct vpfe_resizer_device *resizer,
+			   struct imp_logical_channel *channel,
+			   struct vpfe_rsz_config *chan_config)
+{
+	struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+	struct device *dev = resizer->subdev.v4l2_dev->dev;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
+	int ret;
+
+	if (channel->config_state == STATE_NOT_CONFIGURED) {
+		channel->config =
+			imp_hw_if->alloc_config_block(dev, vpfe_dev->ipipe);
+
+		if (!channel->config) {
+			dev_err(dev,
+			"Failed to allocate memory for channel config\n");
+			return -EFAULT;
+		}
+		/* allocate buffer for holding user configuration */
+		channel->user_config = imp_hw_if->alloc_user_config_block(dev,
+					vpfe_dev->ipipe, IMP_RESIZER);
+
+		if (!channel->user_config) {
+			dev_err(dev,
+			"Failed to allocate memory for user config\n");
+			if (!resizer_chained)
+				kfree(channel->config);
+			return -EFAULT;
+		}
+	}
+
+	if (!chan_config->config) {
+		/* put defaults for user configuration */
+		imp_hw_if->set_user_config_defaults(dev, vpfe_dev->ipipe,
+					IMP_RESIZER, channel->user_config);
+
+		dev_dbg(dev,
+			"imp_set_resizer_config: default configuration set\n");
+	} else {
+		if (copy_from_user(channel->user_config, chan_config->config,
+			sizeof(struct rsz_config)))
+			return -EFAULT;
+		dev_dbg(dev,
+			"imp_set_resizer_config: user configuration set\n");
+	}
+
+	/* Update the user configuration in the hw config block or
+	   if chained, copy it to the shared block and allow previewer
+	   to configure it */
+	ret = imp_hw_if->set_resizer_config(dev, vpfe_dev->ipipe,
+					    resizer_chained,
+					    channel->user_config,
+					    channel->config);
+
+	if (ret < 0)
+		dev_err(dev, "Failed to set resizer configuration\n");
+
+	channel->config_state = STATE_CONFIGURED;
+
+	return ret;
+}
+
+/*
+ * imp_get_resizer_config() - set resizer config
+ * @resizer: vpfe resizer device pointer
+ * @channel: image processor logical channel
+ * @chan_config: resizer channel configuration
+ */
+static int imp_get_resize_config(struct vpfe_resizer_device *resizer,
+			  struct imp_logical_channel *channel,
+			  struct vpfe_rsz_config *chan_config)
+{
+	struct device *dev = resizer->subdev.v4l2_dev->dev;
+
+	dev_dbg(dev, "imp_get_resize_config\n");
+
+	if (channel->config_state != STATE_CONFIGURED) {
+		dev_err(dev, "Resizer channel not configured\n");
+		return -EINVAL;
+	}
+
+	if (!chan_config->config) {
+		dev_err(dev, "Resizer channel invalid pointer\n");
+		return -EINVAL;
+	}
+
+	if (copy_to_user((void *)chan_config->config,
+			 (void *)channel->user_config,
+			 sizeof(struct rsz_config))) {
+		dev_err(dev, "imp_get_resize_config: Error in copy to user\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*
+ * set_resizer_channel_cont_mode() - Set continous channel mode
+ * @resizer: vpfe resizer device pointer
+ */
+static void set_resizer_channel_cont_mode(struct vpfe_resizer_device *resizer)
+{
+	struct imp_logical_channel *channel = &resizer->channel;
+
+	channel->config_state = STATE_NOT_CONFIGURED;
+	channel->user_config = NULL;
+}
+
+/*
+ * set_resizer_channel_ss_mode() - Set single-shot channel mode
+ * @resizer: vpfe resizer device pointer
+ */
+static int set_resizer_channel_ss_mode(struct vpfe_resizer_device *resizer)
+{
+	struct imp_logical_channel *channel = &resizer->channel;
+	struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
+
+	channel->config_state = STATE_NOT_CONFIGURED;
+	channel->user_config = NULL;
+	return imp_hw_if->set_oper_mode(vpfe_dev->ipipe, IMP_MODE_SINGLE_SHOT);
+}
+
+/*
+ * reset_resizer_channel_mode() - Reset channel mode
+ * @resizer: vpfe resizer device pointer
+ */
+static void reset_resizer_channel_mode(struct vpfe_resizer_device *resizer)
+{
+	struct imp_logical_channel *channel = &resizer->channel;
+	struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
+
+	if (resizer->input == RESIZER_INPUT_MEMORY)
+		imp_hw_if->reset_oper_mode(vpfe_dev->ipipe);
+
+	if (channel->config_state == STATE_CONFIGURED) {
+		kfree(channel->user_config);
+		channel->user_config = NULL;
+	}
+}
+
+/*
+ * VPFE video operations
+ */
+
+/* rsz_video_in_queue() - RESIZER video in queue
+ * @vpfe_dev: vpfe device pointer
+ * @addr: buffer address
+ */
+static void rsz_video_in_queue(struct vpfe_device *vpfe_dev,
+			       unsigned long addr)
+{
+	struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
+	struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+	struct imp_logical_channel *chan = &resizer->channel;
+
+	if (resizer->input == RESIZER_INPUT_MEMORY)
+		imp_hw_if->update_inbuf_address(chan->config, addr);
+	else
+		imp_hw_if->update_inbuf_address(NULL, addr);
+}
+
+/*
+ * rsz_video_out1_queue() - RESIZER-A video out queue
+ * @vpfe_dev: vpfe device pointer
+ * @addr: buffer address
+ */
+static void rsz_video_out1_queue(struct vpfe_device *vpfe_dev,
+				 unsigned long addr)
+{
+	struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
+	struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+	struct vpfe_pipeline *pipe = &resizer->video_out.pipe;
+	struct imp_logical_channel *chan = &resizer->channel;
+
+	if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT)
+		imp_hw_if->update_outbuf1_address(vpfe_dev->ipipe,
+						  chan->config, addr);
+	else
+		imp_hw_if->update_outbuf1_address(vpfe_dev->ipipe, NULL, addr);
+
+}
+
+/*
+ * rsz_video_out2_queue() - RESIZER-B video out queue
+ * @vpfe_dev: vpfe device pointer
+ * @addr: buffer address
+ */
+static void rsz_video_out2_queue(struct vpfe_device *vpfe_dev,
+				 unsigned long addr)
+{
+	struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
+	struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+	struct vpfe_pipeline *pipe = &resizer->video_out.pipe;
+	struct imp_logical_channel *chan = &resizer->channel;
+
+	if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT)
+		imp_hw_if->update_outbuf2_address(vpfe_dev->ipipe,
+						  chan->config, addr);
+	else
+		imp_hw_if->update_outbuf2_address(vpfe_dev->ipipe, NULL, addr);
+}
+
+static const struct vpfe_video_operations video_in_ops = {
+	.queue = rsz_video_in_queue,
+};
+
+static const struct vpfe_video_operations video_out1_ops = {
+	.queue = rsz_video_out1_queue,
+};
+
+static const struct vpfe_video_operations video_out2_ops = {
+	.queue = rsz_video_out2_queue,
+};
+
+/*
+ * rsz_ss_buffer_isr() - RESIZER module single-shot buffer scheduling isr
+ * @resizer: RESIZER device pointer
+ */
+static void rsz_ss_buffer_isr(struct vpfe_resizer_device *resizer)
+{
+	struct vpfe_video_device *video_out = &resizer->video_out;
+	struct vpfe_video_device *video_in = &resizer->video_in;
+	struct vpfe_video_device *video_out2 = &resizer->video_out2;
+	struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
+	struct imp_logical_channel *chan = &resizer->channel;
+	struct vpfe_pipeline *pipe = &video_out->pipe;
+	u32 val;
+
+	if (resizer->output == RESIZER_OUPUT_MEMORY) {
+		val = vpss_dma_complete_interrupt();
+		if (val != 0 && val != 2)
+			return;
+	}
+
+	if (resizer->input == RESIZER_INPUT_MEMORY) {
+		spin_lock(&video_in->dma_queue_lock);
+		vpfe_process_buffer_complete(video_in);
+		video_in->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
+		vpfe_schedule_next_buffer(video_in);
+		spin_unlock(&video_in->dma_queue_lock);
+	}
+
+	if (resizer->output == RESIZER_OUPUT_MEMORY) {
+		spin_lock(&video_out->dma_queue_lock);
+		vpfe_process_buffer_complete(video_out);
+		video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
+		vpfe_schedule_next_buffer(video_out);
+		spin_unlock(&video_out->dma_queue_lock);
+	}
+
+	/* If resizer B is enabled */
+	if (pipe->output_num > 1 && resizer->output2 == RESIZER_OUPUT_MEMORY) {
+		spin_lock(&video_out->dma_queue_lock);
+		vpfe_process_buffer_complete(video_out2);
+		video_out2->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
+		vpfe_schedule_next_buffer(video_out2);
+		spin_unlock(&video_out2->dma_queue_lock);
+	}
+
+	/* start HW if buffers are queued */
+	if (is_pipe_ready(pipe) && resizer->output == RESIZER_OUPUT_MEMORY)
+		imp_hw_if->enable(vpfe_dev->ipipe, 1, chan->config);
+}
+
+/*
+ * rsz_buffer_isr() - RESIZER module buffer scheduling isr
+ * @resizer: RESIZER device pointer
+ */
+void rsz_buffer_isr(struct vpfe_resizer_device *resizer)
+{
+	struct vpfe_video_device *video_out2 = &resizer->video_out2;
+	struct vpfe_video_device *video_out = &resizer->video_out;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
+	struct vpfe_pipeline *pipe = &resizer->video_out.pipe;
+	enum v4l2_field field;
+	int fid;
+
+	if (!video_out->started)
+		return;
+
+	if (resizer->input != RESIZER_INPUT_PREVIEWER)
+		return;
+
+	field = video_out->fmt.fmt.pix.field;
+
+	if (field == V4L2_FIELD_NONE) {
+		struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+
+		/* handle progressive frame capture */
+		if (video_out->cur_frm != video_out->next_frm) {
+			vpfe_process_buffer_complete(video_out);
+			if (pipe->output_num > 1)
+				vpfe_process_buffer_complete(video_out2);
+		}
+
+		video_out->skip_frame_count--;
+		if (!video_out->skip_frame_count) {
+			video_out->skip_frame_count =
+				video_out->skip_frame_count_init;
+			if (imp_hw_if->enable_resize)
+				imp_hw_if->enable_resize(1);
+		} else {
+			if (imp_hw_if->enable_resize)
+				imp_hw_if->enable_resize(0);
+		}
+		return;
+	}
+
+	/* handle interlaced frame capture */
+	fid = ccdc_get_fid(vpfe_dev);
+
+	/* switch the software maintained field id */
+	video_out->field_id ^= 1;
+	if (fid == video_out->field_id) {
+		/*
+		 * we are in-sync here,continue.
+		 * One frame is just being captured. If the
+		 * next frame is available, release the current
+		 * frame and move on
+		 */
+		if (fid == 0 && video_out->cur_frm != video_out->next_frm) {
+			vpfe_process_buffer_complete(video_out);
+			if (pipe->output_num > 1)
+				vpfe_process_buffer_complete(video_out2);
+		}
+	} else if (fid == 0) {
+		/*
+		* out of sync. Recover from any hardware out-of-sync.
+		* May loose one frame
+		*/
+		video_out->field_id = fid;
+	}
+}
+
+/*
+ * rsz_dma_isr() - RESIZER module dma isr
+ * @resizer: RESIZER device pointer
+ */
+void rsz_dma_isr(struct vpfe_resizer_device *resizer)
+{
+	struct vpfe_video_device *video_out = &resizer->video_out;
+	struct vpfe_video_device *video_out2 = &resizer->video_out2;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
+	struct vpfe_pipeline *pipe = &video_out->pipe;
+	enum v4l2_field field;
+	int schedule_capture = 0;
+	int fid;
+
+	if (!video_out->started)
+		return;
+
+	if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT) {
+		rsz_ss_buffer_isr(resizer);
+		return;
+	}
+
+	field = video_out->fmt.fmt.pix.field;
+
+	if (field == V4L2_FIELD_NONE) {
+		if (!list_empty(&video_out->dma_queue) &&
+			video_out->cur_frm == video_out->next_frm)
+			schedule_capture = 1;
+	} else {
+		fid = ccdc_get_fid(vpfe_dev);
+		if (fid == video_out->field_id) {
+			/* we are in-sync here,continue */
+			if (fid == 1 && !list_empty(&video_out->dma_queue) &&
+			    video_out->cur_frm == video_out->next_frm)
+				schedule_capture = 1;
+		}
+	}
+	if (!schedule_capture)
+		return;
+
+	spin_lock(&video_out->dma_queue_lock);
+	vpfe_schedule_next_buffer(video_out);
+	spin_unlock(&video_out->dma_queue_lock);
+	if (pipe->output_num > 1) {
+		spin_lock(&video_out2->dma_queue_lock);
+		vpfe_schedule_next_buffer(video_out2);
+		spin_unlock(&video_out2->dma_queue_lock);
+	}
+}
+
+/*
+ * V4L2 subdev operations
+ */
+
+/*
+ * resizer_ioctl() - RESIZER module private ioctl's
+ * @sd: VPFE RESZIER V4L2 subdevice
+ * @cmd: ioctl command
+ * @arg: ioctl argument
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static long resizer_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
+	struct imp_logical_channel *rsz_conf_chan = &resizer->channel;
+	struct device *dev = resizer->subdev.v4l2_dev->dev;
+	struct vpfe_rsz_config *user_config;
+	int ret = 0;
+
+	switch (cmd) {
+	case VIDIOC_VPFE_RSZ_S_CONFIG:
+		user_config = (struct vpfe_rsz_config *)arg;
+
+		dev_dbg(dev, "VIDIOC_VPFE_RSZ_S_CONFIG:\n");
+		ret = imp_set_resizer_config(resizer, rsz_conf_chan,
+						user_config);
+		break;
+	case VIDIOC_VPFE_RSZ_G_CONFIG:
+		user_config = (struct vpfe_rsz_config *)arg;
+		dev_dbg(dev, "VIDIOC_VPFE_RSZ_G_CONFIG\n");
+		if (!user_config->config) {
+			dev_err(dev, "error in VIDIOC_VPFE_RSZ_G_CONFIG\n");
+			goto ERROR;
+		}
+		ret = imp_get_resize_config(resizer, rsz_conf_chan,
+							user_config);
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+	}
+
+ERROR:
+	return ret;
+}
+
+/*
+ * resizer_set_stream() - Enable/Disable streaming on the RESIZER module
+ * @sd: VPFE RESIZER V4L2 subdevice
+ * @enable: Enable/disable stream
+ */
+static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
+	struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+	struct vpfe_pipeline *pipe = &resizer->video_out.pipe;
+	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
+	struct imp_logical_channel *chan = &resizer->channel;
+	struct device *dev = resizer->subdev.v4l2_dev->dev;
+
+	void *config = (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT) ?
+				chan->config : NULL;
+
+	if (resizer->output != RESIZER_OUPUT_MEMORY)
+		return 0;
+
+	switch (enable) {
+	case 1:
+		if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT &&
+				imp_hw_if->serialize(vpfe_dev->ipipe)) {
+			if (imp_hw_if->hw_setup(dev, vpfe_dev->ipipe,
+							config) < 0)
+				return -EINVAL;
+		} else if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) {
+			imp_hw_if->lock_chain(vpfe_dev->ipipe);
+			if (imp_hw_if->hw_setup(dev, vpfe_dev->ipipe, NULL))
+				return -EINVAL;
+		}
+		imp_hw_if->enable(vpfe_dev->ipipe, 1, config);
+		break;
+	case 0:
+		imp_hw_if->enable(vpfe_dev->ipipe, 0, config);
+		if ((pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS))
+			imp_hw_if->unlock_chain(vpfe_dev->ipipe);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * __resizer_get_format() - helper function for getting resizer format
+ * @res   : pointer to resizer private structure
+ * @pad   : pad number
+ * @fh    : V4L2 subdev file handle
+ * @which : wanted subdev format
+ * Retun wanted mbus frame format
+ */
+static struct v4l2_mbus_framefmt *
+__resizer_get_format(struct vpfe_resizer_device *res, struct v4l2_subdev_fh *fh,
+		     unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(fh, pad);
+	return &res->formats[pad];
+}
+
+/*
+ * resizer_try_format() - Handle try format by pad subdev method
+ * @res   : VPFE resizer device
+ * @fh    : V4L2 subdev file handle
+ * @pad   : pad num
+ * @fmt   : pointer to v4l2 format structure
+ * @which : wanted subdev format
+ */
+static void resizer_try_format(struct vpfe_resizer_device *res,
+			struct v4l2_subdev_fh *fh, unsigned int pad,
+			struct v4l2_mbus_framefmt *fmt,
+			enum v4l2_subdev_format_whence which)
+{
+	struct imp_hw_interface *imp_hw_if;
+	unsigned int max_out_height;
+	unsigned int max_out_width;
+	unsigned int i;
+
+	imp_hw_if = res->imp_hw_if;
+
+	if (pad == RESIZER_PAD_SINK) {
+		for (i = 0; i < ARRAY_SIZE(resz_input_fmts); i++) {
+			if (fmt->code == resz_input_fmts[i])
+				break;
+		}
+
+		/* If not found, use UYVY as default */
+		if (i >= ARRAY_SIZE(resz_input_fmts))
+			fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+
+		fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
+					MAX_IN_WIDTH);
+		fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
+				MAX_IN_HEIGHT);
+	} else if (pad == RESIZER_PAD_SOURCE) {
+		max_out_width = imp_hw_if->get_max_output_width(0);
+		max_out_height = imp_hw_if->get_max_output_height(0);
+
+		for (i = 0; i < ARRAY_SIZE(resz_output_fmts); i++) {
+			if (fmt->code == resz_output_fmts[i])
+				break;
+		}
+
+		/* If not found, use UYVY as default */
+		if (i >= ARRAY_SIZE(resz_output_fmts))
+			fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+
+		fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
+					max_out_width);
+		fmt->width &= ~15;
+		fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
+				max_out_height);
+	} else if (pad == RESIZER_PAD_SOURCE2) {
+		max_out_width = imp_hw_if->get_max_output_width(1);
+		max_out_height = imp_hw_if->get_max_output_height(1);
+
+		for (i = 0; i < ARRAY_SIZE(resz_output_fmts); i++) {
+			if (fmt->code == resz_output_fmts[i])
+				break;
+		}
+
+		/* If not found, use UYVY as default */
+		if (i >= ARRAY_SIZE(resz_output_fmts))
+			fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+
+		fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
+					max_out_width);
+		fmt->width &= ~15;
+		fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
+				max_out_height);
+	}
+}
+
+/*
+* resizer_set_format() - set format on pad
+* @sd    : VPFE resizer device
+* @fh    : V4L2 subdev file handle
+* @fmt   : pointer to v4l2 subdev format structure
+*/
+static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
+	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
+	struct imp_hw_interface *imp_hw_if = resizer->imp_hw_if;
+	struct v4l2_mbus_framefmt *format;
+
+	format = __resizer_get_format(resizer, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	resizer_try_format(resizer, fh, fmt->pad, &fmt->format, fmt->which);
+	*format = fmt->format;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	if (fmt->pad == RESIZER_PAD_SINK &&
+			resizer->input == RESIZER_INPUT_PREVIEWER) {
+		/*
+		 *This is continous mode, input format is already set in
+		 *PREVIEWER sink set format, no need to do here.
+		 */
+		resizer->formats[fmt->pad] = fmt->format;
+	} else if (fmt->pad == RESIZER_PAD_SOURCE &&
+			resizer->output == RESIZER_OUPUT_MEMORY) {
+
+		imp_hw_if->set_out_mbus_format(vpfe_dev->ipipe, &fmt->format);
+		resizer->formats[fmt->pad] = fmt->format;
+
+	} else if (fmt->pad == RESIZER_PAD_SINK &&
+			resizer->input == RESIZER_INPUT_MEMORY) {
+		/*
+		 * single shot mode
+		 */
+		imp_hw_if->set_in_mbus_format(vpfe_dev->ipipe, &fmt->format);
+		resizer->formats[fmt->pad] = fmt->format;
+	} else if (fmt->pad == RESIZER_PAD_SOURCE2 &&
+		resizer->output2 == RESIZER_OUPUT_MEMORY) {
+		imp_hw_if->set_out2_mbus_format(vpfe_dev->ipipe, &fmt->format);
+		resizer->formats[fmt->pad] = fmt->format;
+
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * resizer_get_format() - Retrieve the video format on a pad
+ * @sd : VPFE RESIZER V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct vpfe_resizer_device *res = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	fmt->format = *format;
+
+	return 0;
+}
+
+/*
+ * resizer_enum_frame_size() - enum frame sizes on pads
+ * @sd: VPFE resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @code: pointer to v4l2_subdev_frame_size_enum structure
+ */
+static int resizer_enum_frame_size(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct vpfe_resizer_device *res = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt format;
+
+	if (fse->index != 0)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = 1;
+	format.height = 1;
+	resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->min_width = format.width;
+	fse->min_height = format.height;
+
+	if (format.code != fse->code)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = -1;
+	format.height = -1;
+	resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->max_width = format.width;
+	fse->max_height = format.height;
+
+	return 0;
+}
+
+/*
+ * resizer_enum_mbus_code() - enum mbus codes for pads
+ * @sd: VPFE resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @code: pointer to v4l2_subdev_mbus_code_enum structure
+ */
+static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_fh *fh,
+			       struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad == RESIZER_PAD_SINK) {
+		if (code->index >= ARRAY_SIZE(resz_input_fmts))
+			return -EINVAL;
+
+		code->code = resz_input_fmts[code->index];
+	} else if (code->pad == RESIZER_PAD_SOURCE) {
+		if (code->index >= ARRAY_SIZE(resz_output_fmts))
+			return -EINVAL;
+
+		code->code = resz_output_fmts[code->index];
+	}
+
+	return 0;
+}
+
+/*
+ * resizer_init_formats() - Initialize formats on all pads
+ * @sd: VPFE resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int resizer_init_formats(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh)
+{
+	struct vpfe_resizer_device *res = v4l2_get_subdevdata(sd);
+	struct imp_hw_interface *imp_hw_if = res->imp_hw_if;
+	struct v4l2_subdev_format format;
+
+	memset(&format, 0, sizeof(format));
+	format.pad = RESIZER_PAD_SINK;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_YUYV8_2X8;
+	format.format.width = MAX_IN_WIDTH;
+	format.format.height = MAX_IN_HEIGHT;
+	resizer_set_format(sd, fh, &format);
+
+	memset(&format, 0, sizeof(format));
+	format.pad = RESIZER_PAD_SOURCE;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
+	format.format.width = imp_hw_if->get_max_output_width(0);
+	format.format.height = imp_hw_if->get_max_output_height(0);
+	resizer_set_format(sd, fh, &format);
+
+	return 0;
+}
+
+/* V4L2 subdev core operations */
+static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = {
+	.ioctl = resizer_ioctl,
+};
+
+/* subdev file operations */
+static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
+	.open = resizer_init_formats,
+};
+
+/* V4L2 subdev video operations */
+static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
+	.s_stream = resizer_set_stream,
+};
+
+/* V4L2 subdev pad operations */
+static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
+	.enum_mbus_code = resizer_enum_mbus_code,
+	.enum_frame_size = resizer_enum_frame_size,
+	.get_fmt = resizer_get_format,
+	.set_fmt = resizer_set_format,
+};
+
+/* V4L2 subdev operations */
+static const struct v4l2_subdev_ops resizer_v4l2_ops = {
+	.core = &resizer_v4l2_core_ops,
+	.video = &resizer_v4l2_video_ops,
+	.pad = &resizer_v4l2_pad_ops,
+};
+
+/*
+ * Media entity operations
+ */
+
+/*
+ * resizer_link_setup() - Setup RESIZER connections
+ * @entity: RESIZER media entity
+ * @local: Pad at the local end of the link
+ * @remote: Pad at the remote end of the link
+ * @flags: Link flags
+ *
+ * return -EINVAL or zero on success
+ */
+static int resizer_link_setup(struct media_entity *entity,
+			   const struct media_pad *local,
+			   const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
+
+
+	switch (local->index | media_entity_type(remote->entity)) {
+	case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* Read from previewer - continous mode */
+		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+			reset_resizer_channel_mode(resizer);
+			resizer->input = RESIZER_INPUT_NONE;
+			break;
+		}
+
+		if (resizer->input != RESIZER_INPUT_NONE)
+			return -EBUSY;
+
+		resizer->input = RESIZER_INPUT_PREVIEWER;
+		set_resizer_channel_cont_mode(resizer);
+		resizer_chained = 1;
+		break;
+	case RESIZER_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+		/* Read from memory - single shot mode*/
+		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+			reset_resizer_channel_mode(resizer);
+			resizer->input = RESIZER_INPUT_NONE;
+			break;
+		}
+
+		if (set_resizer_channel_ss_mode(resizer))
+			return -EINVAL;
+
+		resizer->input = RESIZER_INPUT_MEMORY;
+		resizer_chained = 0;
+		break;
+	case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+		/* Write to memory */
+		if (flags & MEDIA_LNK_FL_ENABLED)
+			resizer->output = RESIZER_OUPUT_MEMORY;
+		else
+			resizer->output = RESIZER_OUTPUT_NONE;
+
+		break;
+	case RESIZER_PAD_SOURCE2 | MEDIA_ENT_T_DEVNODE:
+		/* Write to memory */
+		if (flags & MEDIA_LNK_FL_ENABLED)
+			resizer->output2 = RESIZER_OUPUT_MEMORY;
+		else
+			resizer->output2 = RESIZER_OUTPUT_NONE;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+static const struct media_entity_operations resizer_media_ops = {
+	.link_setup = resizer_link_setup,
+};
+
+/*
+ * vpfe_resizer_unregister_entities() - RESIZER subdevs/video
+ * driver unregistrations.
+ * @vpfe_rsz - pointer to resizer subdevice structure.
+ */
+void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz)
+{
+	/* unregister video devices */
+	vpfe_video_unregister(&vpfe_rsz->video_in);
+	vpfe_video_unregister(&vpfe_rsz->video_out);
+	vpfe_video_unregister(&vpfe_rsz->video_out2);
+
+	/* cleanup entity */
+	media_entity_cleanup(&vpfe_rsz->subdev.entity);
+	/* unregister subdev */
+	v4l2_device_unregister_subdev(&vpfe_rsz->subdev);
+}
+
+/*
+ * vpfe_resizer_register_entities() - RESIZER subdevs/video
+ * driver registrations.
+ * @resizer - pointer to resizer subdevice structure.
+ * @vdev: pointer to v4l2 device structure.
+ */
+int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer,
+				   struct v4l2_device *vdev)
+{
+	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
+	unsigned int flags;
+	int ret;
+
+	/* Register the subdev */
+	ret = v4l2_device_register_subdev(vdev, &resizer->subdev);
+	if (ret < 0) {
+		pr_err("Failed to register resizer as v4l2-subdev\n");
+		return ret;
+	}
+
+	ret = vpfe_video_register(&resizer->video_in, vdev);
+	if (ret) {
+		pr_err("Failed to register RSZ video-in device\n");
+		goto out_video_in_register;
+	}
+
+	resizer->video_in.vpfe_dev = vpfe_dev;
+
+	ret = vpfe_video_register(&resizer->video_out, vdev);
+	if (ret) {
+		pr_err("Failed to register RSZ video-out device\n");
+		goto out_video_out_register;
+	}
+
+	resizer->video_out.vpfe_dev = vpfe_dev;
+
+	ret = vpfe_video_register(&resizer->video_out2, vdev);
+	if (ret) {
+		pr_err("Failed to register RSZ video-out2 device\n");
+		goto out_video_out2_register;
+	}
+
+	resizer->video_out2.vpfe_dev = vpfe_dev;
+
+	flags = 0;
+	ret = media_entity_create_link(&resizer->video_in.video_dev.entity, 0,
+				       &resizer->subdev.entity, 0, flags);
+	if (ret < 0)
+		goto out_create_link;
+
+	ret = media_entity_create_link(&resizer->subdev.entity, 1,
+				       &resizer->video_out.video_dev.entity,
+				       0, flags);
+	if (ret < 0)
+		goto out_create_link;
+
+	ret = media_entity_create_link(&resizer->subdev.entity, 2,
+					&resizer->video_out2.video_dev.entity,
+					0, flags);
+	if (ret < 0)
+		goto out_create_link;
+
+	return 0;
+
+out_create_link:
+	vpfe_video_unregister(&resizer->video_out2);
+out_video_out2_register:
+	vpfe_video_unregister(&resizer->video_out);
+out_video_out_register:
+	vpfe_video_unregister(&resizer->video_in);
+out_video_in_register:
+	media_entity_cleanup(&resizer->subdev.entity);
+	v4l2_device_unregister_subdev(&resizer->subdev);
+	return ret;
+}
+
+/*
+ * vpfe_resizer_init() - RESIZER module initilaization.
+ * @vpfe_rsz - pointer to resizer subdevice structure.
+ * @pdev: platform device pointer.
+ */
+int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
+		      struct platform_device *pdev)
+{
+	struct imp_logical_channel *channel = &vpfe_rsz->channel;
+	struct v4l2_subdev *resizer = &vpfe_rsz->subdev;
+	struct media_pad *pads = &vpfe_rsz->pads[0];
+	struct media_entity *me = &resizer->entity;
+	int ret;
+
+	vpfe_rsz->imp_hw_if = imp_get_hw_if();
+	if (!vpfe_rsz->imp_hw_if)
+		return -EINVAL;
+
+	vpfe_rsz->video_in.ops = &video_in_ops;
+	vpfe_rsz->video_out.ops = &video_out1_ops;
+	vpfe_rsz->video_out2.ops = &video_out2_ops;
+
+	v4l2_subdev_init(resizer, &resizer_v4l2_ops);
+	resizer->internal_ops = &resizer_v4l2_internal_ops;
+	strlcpy(resizer->name, "DAVINCI RESIZER", sizeof(resizer->name));
+	resizer->grp_id = 1 << 16;	/* group ID for davinci subdevs */
+	v4l2_set_subdevdata(resizer, vpfe_rsz);
+	resizer->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	pads[RESIZER_PAD_SOURCE2].flags = MEDIA_PAD_FL_SOURCE;
+
+	vpfe_rsz->input = RESIZER_INPUT_NONE;
+	vpfe_rsz->output = RESIZER_OUTPUT_NONE;
+	vpfe_rsz->output2 = RESIZER_OUTPUT_NONE;
+
+	channel->type = IMP_RESIZER;
+	channel->config_state = STATE_NOT_CONFIGURED;
+
+	me->ops = &resizer_media_ops;
+
+	ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
+	if (ret)
+		return ret;
+
+	vpfe_rsz->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	ret = vpfe_video_init(&vpfe_rsz->video_in, "RSZ");
+	if (ret) {
+		pr_err("Failed to init RSZ video-in device\n");
+		return ret;
+	}
+
+	vpfe_rsz->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	ret = vpfe_video_init(&vpfe_rsz->video_out, "RSZ");
+	if (ret) {
+		pr_err("Failed to init RSZ video-out device\n");
+		return ret;
+	}
+
+	vpfe_rsz->video_out2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	ret = vpfe_video_init(&vpfe_rsz->video_out2, "RSZB");
+	if (ret) {
+		pr_err("Failed to init RSZ video-out2 device\n");
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/platform/davinci/vpfe_resizer.h b/drivers/media/platform/davinci/vpfe_resizer.h
new file mode 100644
index 0000000..819af1f
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_resizer.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 Texas Instruments 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 version 2.
+ *
+ * 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
+ *
+ * Contributors:
+ *      Manjunath Hadli <manjunath.hadli@ti.com>
+ *      Prabhakar Lad <prabhakar.lad@ti.com>
+ */
+
+#ifndef _VPFE_RSZ_H
+#define _VPFE_RSZ_H
+
+#define RESIZER_PAD_SINK	0
+#define RESIZER_PAD_SOURCE	1
+#define RESIZER_PAD_SOURCE2	2
+
+#define RESIZER_PADS_NUM	3
+
+enum resizer_input_entity {
+	RESIZER_INPUT_NONE,
+	RESIZER_INPUT_MEMORY,
+	RESIZER_INPUT_PREVIEWER,
+};
+
+#define RESIZER_OUTPUT_NONE	0
+#define RESIZER_OUPUT_MEMORY	(1 << 0)
+
+struct vpfe_resizer_device {
+	struct v4l2_subdev		subdev;
+	struct media_pad		pads[RESIZER_PADS_NUM];
+	struct v4l2_mbus_framefmt	formats[RESIZER_PADS_NUM];
+	enum resizer_input_entity	input;
+	unsigned int			output;
+	unsigned int                    output2;
+
+	/* pointer to ipipe function pointers */
+	struct imp_hw_interface		*imp_hw_if;
+	struct imp_logical_channel	channel;
+
+	struct vpfe_video_device	video_in;
+	struct vpfe_video_device	video_out;
+	struct vpfe_video_device        video_out2;
+};
+
+void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz);
+int vpfe_resizer_register_entities(struct vpfe_resizer_device *vpfe_rsz,
+				   struct v4l2_device *v4l2_dev);
+int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
+		      struct platform_device *pdev);
+void rsz_buffer_isr(struct vpfe_resizer_device *resizer);
+void vpfe_resizer_cleanup(struct platform_device *pdev);
+void rsz_dma_isr(struct vpfe_resizer_device *resizer);
+
+#endif
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 10/14] dm365: vpss: setup ISP registers
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (8 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 09/14] davinci: vpfe: resizer driver based on media framework Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 11/14] dm365: vpss: set vpss clk ctrl Prabhakar Lad
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

enable PPCR, enbale ISIF out on BCR and disable all events.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/vpss.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
index 146e4b0..34ad7bd 100644
--- a/drivers/media/platform/davinci/vpss.c
+++ b/drivers/media/platform/davinci/vpss.c
@@ -52,9 +52,11 @@ MODULE_AUTHOR("Texas Instruments");
 #define DM355_VPSSBL_EVTSEL_DEFAULT	0x4
 
 #define DM365_ISP5_PCCR 		0x04
+#define DM365_ISP5_BCR			0x08
 #define DM365_ISP5_INTSEL1		0x10
 #define DM365_ISP5_INTSEL2		0x14
 #define DM365_ISP5_INTSEL3		0x18
+#define DM365_ISP5_EVTSEL		0x1c
 #define DM365_ISP5_CCDCMUX 		0x20
 #define DM365_ISP5_PG_FRAME_SIZE 	0x28
 #define DM365_VPBE_CLK_CTRL 		0x00
@@ -357,6 +359,10 @@ void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
 }
 EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size);
 
+#define DM365_ISP5_EVTSEL_EVT_DISABLE	0x00000000
+#define DM365_ISP5_BCR_ISIF_OUT_ENABLE	0x00000002
+#define DM365_ISP5_PCCR_CLK_ENABLE	0x0000007f
+
 static int __devinit vpss_probe(struct platform_device *pdev)
 {
 	struct resource		*r1, *r2;
@@ -426,9 +432,16 @@ static int __devinit vpss_probe(struct platform_device *pdev)
 		oper_cfg.hw_ops.enable_clock = dm365_enable_clock;
 		oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source;
 		/* Setup vpss interrupts */
+		isp5_write((isp5_read(DM365_ISP5_PCCR) |
+				DM365_ISP5_PCCR_CLK_ENABLE), DM365_ISP5_PCCR);
+		isp5_write((isp5_read(DM365_ISP5_BCR) |
+			     DM365_ISP5_BCR_ISIF_OUT_ENABLE), DM365_ISP5_BCR);
 		isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1);
 		isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2);
 		isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3);
+		/* No event selected */
+		isp5_write((isp5_read(DM365_ISP5_EVTSEL) |
+			DM365_ISP5_EVTSEL_EVT_DISABLE), DM365_ISP5_EVTSEL);
 	} else
 		oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
 
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 11/14] dm365: vpss: set vpss clk ctrl
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (9 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 10/14] dm365: vpss: setup ISP registers Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 12/14] dm365: vpss: add vpss helper functions to be used in the main driver for setting hardware parameters Prabhakar Lad
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

request_mem_region for VPSS_CLK_CTRL register and ioremap.
and enable clocks appropriately.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/vpss.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
index 34ad7bd..49bb045 100644
--- a/drivers/media/platform/davinci/vpss.c
+++ b/drivers/media/platform/davinci/vpss.c
@@ -103,6 +103,7 @@ struct vpss_hw_ops {
 struct vpss_oper_config {
 	__iomem void *vpss_regs_base0;
 	__iomem void *vpss_regs_base1;
+	resource_size_t *vpss_regs_base2;
 	enum vpss_platform_type platform;
 	spinlock_t vpss_lock;
 	struct vpss_hw_ops hw_ops;
@@ -484,11 +485,21 @@ static struct platform_driver vpss_driver = {
 
 static void vpss_exit(void)
 {
+	iounmap(oper_cfg.vpss_regs_base2);
+	release_mem_region(*oper_cfg.vpss_regs_base2, 4);
 	platform_driver_unregister(&vpss_driver);
 }
 
+#define VPSS_CLK_CTRL		0x01c40044
+
 static int __init vpss_init(void)
 {
+	if (request_mem_region(VPSS_CLK_CTRL, 4, "vpss_clock_control")) {
+		oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4);
+		__raw_writel(0x18, oper_cfg.vpss_regs_base2);
+	} else {
+		return -EBUSY;
+	}
 	return platform_driver_register(&vpss_driver);
 }
 subsys_initcall(vpss_init);
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 12/14] dm365: vpss: add vpss helper functions to be used in the main driver for setting hardware parameters
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (10 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 11/14] dm365: vpss: set vpss clk ctrl Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 13/14] davinci: vpfe: build infrastructure for dm365 Prabhakar Lad
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

add function to set sync polarity , interrupt completion and
pageframe size in vpss to be used by the main driver.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/vpss.c |   32 ++++++++++++++++++++++++++++++++
 include/media/davinci/vpss.h          |   16 ++++++++++++++++
 2 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
index 49bb045..3c195c0 100644
--- a/drivers/media/platform/davinci/vpss.c
+++ b/drivers/media/platform/davinci/vpss.c
@@ -97,6 +97,12 @@ struct vpss_hw_ops {
 	void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
 	/* clear wbl overflow bit */
 	int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
+	/* set sync polarity */
+	void (*set_sync_pol)(struct vpss_sync_pol);
+	/* set the PG_FRAME_SIZE register*/
+	void (*set_pg_frame_size)(struct vpss_pg_frame_size);
+	/* check and clear interrupt if occured */
+	int (*dma_complete_interrupt)(void);
 };
 
 /* vpss configuration */
@@ -161,6 +167,14 @@ static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
 	bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX);
 }
 
+int vpss_dma_complete_interrupt(void)
+{
+	if (!oper_cfg.hw_ops.dma_complete_interrupt)
+		return 2;
+	return oper_cfg.hw_ops.dma_complete_interrupt();
+}
+EXPORT_SYMBOL(vpss_dma_complete_interrupt);
+
 int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
 {
 	if (!oper_cfg.hw_ops.select_ccdc_source)
@@ -186,6 +200,15 @@ static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
 	return 0;
 }
 
+void vpss_set_sync_pol(struct vpss_sync_pol sync)
+{
+	if (!oper_cfg.hw_ops.set_sync_pol)
+		return;
+
+	oper_cfg.hw_ops.set_sync_pol(sync);
+}
+EXPORT_SYMBOL(vpss_set_sync_pol);
+
 int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
 {
 	if (!oper_cfg.hw_ops.clear_wbl_overflow)
@@ -351,6 +374,15 @@ void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync)
 }
 EXPORT_SYMBOL(dm365_vpss_set_sync_pol);
 
+void vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
+{
+	if (!oper_cfg.hw_ops.set_pg_frame_size)
+		return;
+
+	oper_cfg.hw_ops.set_pg_frame_size(frame_size);
+}
+EXPORT_SYMBOL(vpss_set_pg_frame_size);
+
 void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
 {
 	int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16;
diff --git a/include/media/davinci/vpss.h b/include/media/davinci/vpss.h
index b586495..c5f6d9a 100644
--- a/include/media/davinci/vpss.h
+++ b/include/media/davinci/vpss.h
@@ -105,4 +105,20 @@ enum vpss_wbl_sel {
 };
 /* clear wbl overflow flag for DM6446 */
 int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel);
+
+/* set sync polarity*/
+void vpss_set_sync_pol(struct vpss_sync_pol sync);
+/* set the PG_FRAME_SIZE register */
+void vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size);
+/**
+ * vpss_check_and_clear_interrupt - check and clear interrupt
+ * @irq - common enumerator for IRQ
+ *
+ * Following return values used:-
+ * 0 - interrupt occured and cleared
+ * 1 - interrupt not occured
+ * 2 - interrupt status not available
+ */
+int vpss_dma_complete_interrupt(void);
+
 #endif
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 13/14] davinci: vpfe: build infrastructure for dm365
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (11 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 12/14] dm365: vpss: add vpss helper functions to be used in the main driver for setting hardware parameters Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-14 12:46 ` [PATCH 14/14] [media] davinci: vpfe: Add documentation Prabhakar Lad
  2012-09-23 15:16 ` [PATCH 00/14] Media Controller capture driver for DM365 Sakari Ailus
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML; +Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

From: Manjunath Hadli <manjunath.hadli@ti.com>

add build infrastructure for dm365 specific modules
such as IPIPE, AEW, AF.

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 drivers/media/platform/davinci/Kconfig  |   40 +++++++++++++++++++++++++++++-
 drivers/media/platform/davinci/Makefile |    9 +++++++
 2 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig
index 78e26d2..4eddb00 100644
--- a/drivers/media/platform/davinci/Kconfig
+++ b/drivers/media/platform/davinci/Kconfig
@@ -56,7 +56,7 @@ config VIDEO_VPFE_CAPTURE
 
 config VIDEO_DM6446_CCDC
 	tristate "DM6446 CCDC HW module"
-	depends on VIDEO_VPFE_CAPTURE
+	depends on VIDEO_VPFE_CAPTURE && ARCH_DAVINCI_DM644x
 	select VIDEO_VPSS_SYSTEM
 	default y
 	help
@@ -85,7 +85,7 @@ config VIDEO_DM355_CCDC
 	   module will be called vpfe.
 
 config VIDEO_ISIF
-	tristate "ISIF HW module"
+	tristate "DM365 ISIF HW module"
 	depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
 	select VIDEO_VPSS_SYSTEM
 	default y
@@ -119,3 +119,39 @@ config VIDEO_VPBE_DISPLAY
 
 	    To compile this driver as a module, choose M here: the
 	    module will be called vpbe_display.
+
+
+config VIDEO_365_CCDC
+	tristate "DM365 CCDC HW module"
+	depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_MC_CAPTURE
+	select VIDEO_VPSS_SYSTEM
+	default y
+	help
+	   Enables ISIF hw module. This is the hardware module for
+	   configuring ISIF in VPFE to capture Raw Bayer RGB data  from
+	   a image sensor or YUV data from a YUV source.
+
+	   To compile this driver as a module, choose M here: the
+	   module will be called vpfe.
+
+config DM365_IPIPE
+	depends on ARCH_DAVINCI && ARCH_DAVINCI_DM365 && VIDEO_VPFE_MC_CAPTURE
+	tristate "DM365 IPIPE"
+	help
+	  dm365 IPIPE hardware module.
+
+	  This is the hardware module that implements imp_hw_interface
+	  for DM365. This hardware module provides previewer and resizer
+	  functionality for image processing.
+
+config VIDEO_VPFE_MC_CAPTURE
+	tristate "VPFE Media Controller Capture Driver"
+	depends on VIDEO_V4L2 && (ARCH_DAVINCI) && !VIDEO_VPFE_CAPTURE
+	select VIDEOBUF_DMA_CONTIG
+	help
+	  Support for DMx/AMx VPFE based Media Controller Capture driver. This is the
+	  common V4L2 module for following DMx/AMx SoCs from Texas
+	  Instruments:- DM6446, DM365, DM355 & AM3517/05.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpfe-mc-capture.
diff --git a/drivers/media/platform/davinci/Makefile b/drivers/media/platform/davinci/Makefile
index 74ed92d..955f63d 100644
--- a/drivers/media/platform/davinci/Makefile
+++ b/drivers/media/platform/davinci/Makefile
@@ -16,5 +16,14 @@ obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
 obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
 obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
 obj-$(CONFIG_VIDEO_ISIF) += isif.o
+obj-$(CONFIG_VIDEO_365_CCDC) += dm365_ccdc.o
+obj-$(CONFIG_VIDEO_VPFE_MC_CAPTURE) += vpfe_mc_capture.o \
+		vpfe_ccdc.o vpfe_resizer.o vpfe_previewer.o \
+		vpfe_video.o
+
+dm365_imp-objs := dm365_ipipe.o dm365_def_para.o \
+		dm365_ipipe_hw.o dm3xx_ipipeif.o
+obj-$(CONFIG_DM365_IPIPE) += dm365_imp.o
+
 obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o
 obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 14/14] [media] davinci: vpfe: Add documentation
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (12 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 13/14] davinci: vpfe: build infrastructure for dm365 Prabhakar Lad
@ 2012-09-14 12:46 ` Prabhakar Lad
  2012-09-23 15:16 ` [PATCH 00/14] Media Controller capture driver for DM365 Sakari Ailus
  14 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-14 12:46 UTC (permalink / raw)
  To: LMML
  Cc: LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad,
	Prabhakar, Rob Landley, linux-doc

From: Manjunath Hadli <manjunath.hadli@ti.com>

Add documentation on the Davinci VPFE driver. Document the subdevs,
and private IOTCLs the driver implements

Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
Cc: Rob Landley <rob@landley.net>
Cc: <linux-doc@vger.kernel.org>
---
 Documentation/video4linux/davinci-vpfe-mc.txt |   95 +++++++++++++++++++++++++
 1 files changed, 95 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/video4linux/davinci-vpfe-mc.txt

diff --git a/Documentation/video4linux/davinci-vpfe-mc.txt b/Documentation/video4linux/davinci-vpfe-mc.txt
new file mode 100644
index 0000000..9dfc4f9
--- /dev/null
+++ b/Documentation/video4linux/davinci-vpfe-mc.txt
@@ -0,0 +1,95 @@
+Davinci Video processing Front End (VPFE) driver
+
+Copyright (C) 2012 Texas Instruments Inc
+
+Contacts: Manjunath Hadli <manjunath.hadli@ti.com>
+
+
+Introduction
+============
+
+This file documents the Texas Instruments Davinci Video processing Front End
+(VPFE) driver located under drivers/media/platform/davinci. The original driver
+exists for Davinci VPFE, which is now being changed to Media Controller
+Framework.
+
+Currently the driver has been successfully used on the following
+version of Davinci:
+
+	DM365/DM368
+
+The driver implements V4L2, Media controller and v4l2_subdev interfaces. Sensor,
+lens and flash drivers using the v4l2_subdev interface in the kernel are
+supported.
+
+
+Split to subdevs
+================
+
+The Davinci VPFE is split into V4L2 subdevs, each of the blocks inside the VPFE
+having one subdev to represent it. Each of the subdevs provide a V4L2 subdev
+interface to userspace.
+
+	DAVINCI CCDC
+	DAVINCI PREVIEWER
+	DAVINCI RESIZER
+
+Each possible link in the VPFE is modeled by a link in the Media controller
+interface. For an example program see [1].
+
+
+Private IOCTLs
+==============
+
+The Davinci Video processing Front End (VPFE) driver supports standard V4L2
+IOCTLs and controls where possible and practical. Much of the functions provided
+by the VPFE, however, does not fall under the standard IOCTL's.
+
+In general, there is a private ioctl for configuring each of the blocks
+containing hardware-dependent functions.
+
+The following private IOCTLs are supported:
+
+	VIDIOC_VPFE_CCDC_[S/G]_RAW_PARAMS
+	VIDIOC_VPFE_PRV_[S/G]_CONFIG
+	VIDIOC_VPFE_RSZ_[S/G]_CONFIG
+
+The parameter structures used by these ioctl's are described in
+include/linux/davinci_vpfe.h and include/linux/dm365_ccdc.h.
+
+The VIDIOC_VPFE_CCDC_S_RAW_PARAMS, VIDIOC_VPFE_PRV_S_CONFIG and
+VIDIOC_VPFE_RSZ_S_CONFIG are used to configure, enable and disable functions in
+the CCDC, preview and resizer blocks respectively. These IOCTL's control several
+functions in the blocks they control. VIDIOC_VPFE_CCDC_S_RAW_PARAMS IOCTL
+accepts a pointer to struct ccdc_config_params_raw as its argument. Similarly
+VIDIOC_VPFE_PRV_S_CONFIG accepts a pointer to struct vpfe_prev_config. And
+VIDIOC_VPFE_RSZ_S_CONFIG accepts a pointer to struct vpfe_rsz_config as its
+argument. Similarly VIDIOC_VPFE_CCDC_G_RAW_PARAMS, VIDIOC_VPFE_PRV_G_CONFIG and
+VIDIOC_VPFE_RSZ_G_CONFIG are used to get the current configuration set
+in the CCDC, preview and resizer blocks respectively.
+
+The detailed functions of the VPFE itself related to a given VPFE block is
+described in the Technical Reference Manuals (TRMs) --- see the end of the
+document for those.
+
+
+Technical reference manuals (TRMs) and other documentation
+==========================================================
+
+Davinci DM365 TRM:
+<URL:http://www.ti.com/lit/ds/sprs457e/sprs457e.pdf>
+Referenced MARCH 2009-REVISED JUNE 2011
+
+Davinci DM368 TRM:
+<URL:http://www.ti.com/lit/ds/sprs668c/sprs668c.pdf>
+Referenced APRIL 2010-REVISED JUNE 2011
+
+Davinci Video Processing Front End (VPFE) DM36x
+<URL:http://www.ti.com/lit/ug/sprufg8c/sprufg8c.pdf>
+
+
+References
+==========
+
+[1] http://git.ideasonboard.org/?p=media-ctl.git;a=summary
+[2] include/linux/davinci_vpfe.h & include/linux/dm365_ccdc.h
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 06/14] davinci: vpfe: add v4l2 video driver support
  2012-09-14 12:46 ` [PATCH 06/14] davinci: vpfe: add v4l2 video driver support Prabhakar Lad
@ 2012-09-14 13:30   ` Hans Verkuil
  2012-09-22  5:03     ` Prabhakar Lad
  0 siblings, 1 reply; 23+ messages in thread
From: Hans Verkuil @ 2012-09-14 13:30 UTC (permalink / raw)
  To: Prabhakar Lad
  Cc: LMML, LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

On Fri 14 September 2012 14:46:36 Prabhakar Lad wrote:
> From: Manjunath Hadli <manjunath.hadli@ti.com>
> 
> add a generic video driver functionality to be used by all the vpfe
> drivers for davinci SoCs. The functionality includes all the
> standard v4l2 interfaces including streaming. The video node
> interface can be used both as an input and output node for both
> continuous and single shot modes.Also supports dv_presets to include
> HD modes, wth support for both user pointer IO and mmap.
> 
> Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
> Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
> ---
>  drivers/media/platform/davinci/vpfe_video.c | 1725 +++++++++++++++++++++++++++
>  drivers/media/platform/davinci/vpfe_video.h |  150 +++
>  2 files changed, 1875 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/platform/davinci/vpfe_video.c
>  create mode 100644 drivers/media/platform/davinci/vpfe_video.h
> 
> diff --git a/drivers/media/platform/davinci/vpfe_video.c b/drivers/media/platform/davinci/vpfe_video.c
> new file mode 100644
> index 0000000..2e696a0
> --- /dev/null
> +++ b/drivers/media/platform/davinci/vpfe_video.c
> @@ -0,0 +1,1725 @@
> +/*
> + * Copyright (C) 2012 Texas Instruments 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 version 2.
> + *
> + * 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
> + *
> + * Contributors:
> + *      Manjunath Hadli <manjunath.hadli@ti.com>
> + *      Prabhakar Lad <prabhakar.lad@ti.com>
> + */
> +
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-mediabus.h>
> +#include <media/media-entity.h>
> +#include <media/media-device.h>
> +#include <media/davinci/vpfe_types.h>
> +
> +#include <mach/cputype.h>
> +
> +#include "vpfe_mc_capture.h"
> +#include "ccdc_hw_device.h"
> +
> +/* minimum number of buffers needed in cont-mode */
> +#define CONT_MIN_NUM_BUFFERS	3
> +
> +static int debug;
> +
> +/* get v4l2 subdev pointer to external subdev which is active */
> +static struct media_entity *vpfe_get_input_entity
> +			(struct vpfe_video_device *video)
> +{
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct media_pad *remote;
> +
> +	remote = media_entity_remote_source(&vpfe_dev->vpfe_ccdc.pads[0]);
> +	if (remote == NULL) {
> +		pr_err("Invalid media connection to ccdc\n");
> +		return NULL;
> +	}
> +
> +	return remote->entity;
> +}
> +
> +/* updates external subdev(sensor/decoder) which is active */
> +static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video)
> +{
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_config *vpfe_cfg;
> +	struct v4l2_subdev *subdev;
> +	struct media_pad *remote;
> +	int i;
> +
> +	remote = media_entity_remote_source(&vpfe_dev->vpfe_ccdc.pads[0]);
> +	if (remote == NULL) {
> +		pr_err("Invalid media connection to ccdc\n");
> +		return -EINVAL;
> +	}
> +
> +	subdev = media_entity_to_v4l2_subdev(remote->entity);
> +
> +	vpfe_cfg = vpfe_dev->pdev->platform_data;
> +
> +	for (i = 0; i < vpfe_cfg->num_subdevs; i++) {
> +		if (!strcmp(vpfe_cfg->sub_devs[i].module_name, subdev->name)) {
> +			video->current_ext_subdev = &vpfe_cfg->sub_devs[i];
> +			break;
> +		}
> +	}
> +
> +	/* if user not linked decoder/sensor to ccdc */
> +	if (i == vpfe_cfg->num_subdevs) {
> +		pr_err("Invalid media chain connection to ccdc\n");
> +		return -EINVAL;
> +	}
> +
> +	/* find the v4l2 subdev pointer */
> +	for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) {
> +		if (!strcmp(video->current_ext_subdev->module_name,
> +			vpfe_dev->sd[i]->name))
> +			video->current_ext_subdev->subdev = vpfe_dev->sd[i];
> +	}
> +
> +	return 0;
> +}
> +
> +/* get the subdev which is connected to the output video node */
> +static struct v4l2_subdev *
> +vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad)
> +{
> +	struct media_pad *remote;
> +
> +	remote = media_entity_remote_source(&video->pad);
> +
> +	if (remote == NULL || remote->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
> +		return NULL;
> +
> +	if (pad)
> +		*pad = remote->index;
> +
> +	return media_entity_to_v4l2_subdev(remote->entity);
> +}
> +
> +/* get the format set at ouput pad of the adjacent subdev */
> +static int
> +__vpfe_video_get_format(struct vpfe_video_device *video,
> +			struct v4l2_format *format)
> +{
> +	struct v4l2_subdev_format fmt;
> +	struct v4l2_subdev *subdev;
> +	struct media_pad *remote;
> +	u32 pad;
> +	int ret;
> +
> +	subdev = vpfe_video_remote_subdev(video, &pad);
> +	if (subdev == NULL)
> +		return -EINVAL;
> +
> +	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +	remote = media_entity_remote_source(&video->pad);
> +	fmt.pad = remote->index;
> +
> +	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
> +	if (ret == -ENOIOCTLCMD)
> +		return -EINVAL;
> +
> +	format->type = video->type;
> +	/* convert mbus_format to v4l2_format */
> +	v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
> +	mbus_to_pix(&fmt.format, &format->fmt.pix);
> +
> +	return 0;
> +}
> +
> +/* make a note of pipeline details */
> +static void vpfe_prepare_pipeline(struct vpfe_video_device *video)
> +{
> +	struct media_entity *entity = &video->video_dev.entity;
> +	struct media_device *mdev = entity->parent;
> +	struct vpfe_pipeline *pipe = &video->pipe;
> +	struct vpfe_video_device *far_end = NULL;
> +	struct media_entity_graph graph;
> +
> +	pipe->input_num = 0;
> +	pipe->output_num = 0;
> +
> +	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
> +		pipe->inputs[pipe->input_num++] = video;
> +	else
> +		pipe->outputs[pipe->output_num++] = video;
> +
> +	mutex_lock(&mdev->graph_mutex);
> +	media_entity_graph_walk_start(&graph, entity);
> +
> +	while ((entity = media_entity_graph_walk_next(&graph))) {
> +		if (entity == &video->video_dev.entity)
> +			continue;
> +
> +		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
> +			continue;
> +
> +		far_end = to_vpfe_video(media_entity_to_video_device(entity));
> +
> +		if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
> +			pipe->inputs[pipe->input_num++] = far_end;
> +		else
> +			pipe->outputs[pipe->output_num++] = far_end;
> +	}
> +
> +	mutex_unlock(&mdev->graph_mutex);
> +}
> +
> +/* update pipe state selected by user */
> +static int vpfe_update_pipe_state(struct vpfe_video_device *video)
> +{
> +	struct vpfe_pipeline *pipe = &video->pipe;
> +	int ret;
> +
> +	vpfe_prepare_pipeline(video);
> +
> +	/* Find out if there is any input video
> +	  if yes, it is single shot.
> +	*/
> +	if (pipe->input_num == 0) {
> +		pipe->state = VPFE_PIPELINE_STREAM_CONTINUOUS;
> +		ret = vpfe_update_current_ext_subdev(video);
> +		if (ret) {
> +			pr_err("Invalid external subdev\n");
> +			return ret;
> +		}
> +	} else {
> +		pipe->state = VPFE_PIPELINE_STREAM_SINGLESHOT;
> +	}
> +
> +	video->initialized = 1;
> +	video->skip_frame_count = 1;
> +	video->skip_frame_count_init = 1;
> +
> +	return 0;
> +}
> +
> +/* checks wether pipeline is ready for enabling */
> +int is_pipe_ready(struct vpfe_pipeline *pipe)
> +{
> +	int i;
> +
> +	for (i = 0; i < pipe->input_num; i++)
> +		if (!pipe->inputs[i]->started ||
> +			pipe->inputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED)
> +			return 0;
> +
> +	for (i = 0; i < pipe->output_num; i++)
> +		if (!pipe->outputs[i]->started ||
> +			pipe->outputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED)
> +			return 0;
> +
> +	return 1;
> +}
> +
> +/**
> + * Validate a pipeline by checking both ends of all links for format
> + * discrepancies.
> + *
> + * Return 0 if all formats match, or -EPIPE if at least one link is found with
> + * different formats on its two ends.
> + */
> +static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
> +{
> +	struct v4l2_subdev_format fmt_source;
> +	struct v4l2_subdev_format fmt_sink;
> +	struct v4l2_subdev *subdev;
> +	struct media_pad *pad;
> +	int ret;
> +
> +	/* Should not matter if it is output[0] or 1 as
> +	   the general ideas is to traverse backwards and
> +	   the fact that the out video node always has the
> +	   format of the connected pad.
> +	*/
> +	subdev = vpfe_video_remote_subdev(pipe->outputs[0], NULL);
> +	if (subdev == NULL)
> +		return -EPIPE;
> +
> +	while (1) {
> +		/* Retrieve the sink format */
> +		pad = &subdev->entity.pads[0];
> +		if (!(pad->flags & MEDIA_PAD_FL_SINK))
> +			break;
> +
> +		fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +		fmt_sink.pad = pad->index;
> +		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL,
> +				       &fmt_sink);
> +
> +		if (ret < 0 && ret != -ENOIOCTLCMD)
> +			return -EPIPE;
> +
> +		/* Retrieve the source format */
> +		pad = media_entity_remote_source(pad);
> +		if (pad == NULL ||
> +			pad->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
> +			break;
> +
> +		subdev = media_entity_to_v4l2_subdev(pad->entity);
> +
> +		fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +		fmt_source.pad = pad->index;
> +		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
> +		if (ret < 0 && ret != -ENOIOCTLCMD)
> +			return -EPIPE;
> +
> +		/* Check if the two ends match */
> +		if (fmt_source.format.code != fmt_sink.format.code ||
> +		    fmt_source.format.width != fmt_sink.format.width ||
> +		    fmt_source.format.height != fmt_sink.format.height)
> +			return -EPIPE;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * vpfe_pipeline_enable() - Enable streaming on a pipeline
> + * @vpfe_dev: vpfe device
> + * @pipe: vpfe pipeline
> + *
> + * Walk the entities chain starting at the pipeline output video node and start
> + * all modules in the chain in the given mode.
> + *
> + * Return 0 if successfull, or the return value of the failed video::s_stream
> + * operation otherwise.
> + */
> +static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
> +{
> +	struct media_entity_graph graph;
> +	struct media_entity *entity;
> +	struct v4l2_subdev *subdev;
> +	struct media_device *mdev;
> +	int ret = 0;
> +
> +	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
> +		entity = vpfe_get_input_entity(pipe->outputs[0]);
> +	else
> +		entity = &pipe->inputs[0]->video_dev.entity;
> +
> +	mdev = entity->parent;
> +
> +	mutex_lock(&mdev->graph_mutex);
> +	media_entity_graph_walk_start(&graph, entity);
> +
> +	while ((entity = media_entity_graph_walk_next(&graph))) {
> +
> +		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
> +			continue;
> +
> +		subdev = media_entity_to_v4l2_subdev(entity);
> +
> +		ret = v4l2_subdev_call(subdev, video, s_stream, 1);
> +		if (ret < 0 && ret != -ENOIOCTLCMD)
> +			break;
> +	}
> +	mutex_unlock(&mdev->graph_mutex);
> +
> +	return ret;
> +}
> +
> +/**
> + * vpfe_pipeline_disable() - Disable streaming on a pipeline
> + * @vpfe_dev: vpfe device
> + * @pipe: VPFE pipeline
> + *
> + * Walk the entities chain starting at the pipeline output video node and stop
> + * all modules in the chain.
> + *
> + * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
> + * can't be stopped.
> + */
> +static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
> +{
> +	struct media_entity_graph graph;
> +	struct media_entity *entity;
> +	struct v4l2_subdev *subdev;
> +	struct media_device *mdev;
> +	int ret = 0;
> +
> +	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
> +		entity = vpfe_get_input_entity(pipe->outputs[0]);
> +	else
> +		entity = &pipe->inputs[0]->video_dev.entity;
> +
> +	mdev = entity->parent;
> +
> +	mutex_lock(&mdev->graph_mutex);
> +	media_entity_graph_walk_start(&graph, entity);
> +
> +	while ((entity = media_entity_graph_walk_next(&graph))) {
> +
> +		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
> +			continue;
> +
> +		subdev = media_entity_to_v4l2_subdev(entity);
> +
> +		ret = v4l2_subdev_call(subdev, video, s_stream, 0);
> +		if (ret < 0 && ret != -ENOIOCTLCMD)
> +			break;
> +	}
> +
> +	mutex_unlock(&mdev->graph_mutex);
> +
> +	return (ret == 0) ? ret : -ETIMEDOUT ;
> +}
> +
> +/**
> + * vpfe_pipeline_set_stream() - Enable/disable streaming on a pipeline
> + * @vpfe_dev: VPFE device
> + * @pipe: VPFE pipeline
> + * @state: Stream state (stopped or active)
> + *
> + * Set the pipeline to the given stream state.
> + *
> + * Return 0 if successfull, or the return value of the failed video::s_stream
> + * operation otherwise.
> + */
> +static int vpfe_pipeline_set_stream(struct vpfe_pipeline *pipe,
> +			    enum vpfe_pipeline_stream_state state)
> +{
> +	if (state == VPFE_PIPELINE_STREAM_STOPPED)
> +		return vpfe_pipeline_disable(pipe);
> +
> +	return vpfe_pipeline_enable(pipe);
> +}
> +
> +static int all_videos_stopped(struct vpfe_video_device *video)
> +{
> +	struct vpfe_pipeline *pipe = &video->pipe;
> +	int i;
> +
> +	for (i = 0; i < pipe->input_num; i++)
> +		if (pipe->inputs[i]->started)
> +			return 0;
> +
> +	for (i = 0; i < pipe->output_num; i++)
> +		if (pipe->outputs[i]->started)
> +			return 0;
> +
> +	return 1;
> +}
> +
> +/*
> + * vpfe_open() - open video device
> + * @file: file pointer
> + *
> + * initialize media pipeline state, allocate memory for file hadle
> + *
> + * Return 0 if successfull, or the return -ENODEV otherwise.
> + */
> +static int vpfe_open(struct file *file)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_fh *fh;
> +
> +	/* Allocate memory for the file handle object */
> +	fh = kzalloc(sizeof(struct vpfe_fh), GFP_KERNEL);

Please use struct v4l2_fh: it gives you the event API and priority handling
for free.

> +
> +	if (fh == NULL)
> +		return -ENOMEM;
> +	/* store pointer to fh in private_data member of file */
> +	file->private_data = fh;
> +	fh->video = video;
> +	mutex_lock(&video->lock);
> +	/* If decoder is not initialized. initialize it */
> +	if (!video->initialized && vpfe_update_pipe_state(video)) {
> +		mutex_unlock(&video->lock);
> +		return -ENODEV;
> +	}
> +	/* Increment device usrs counter */
> +	video->usrs++;
> +	/* Set io_allowed member to false */
> +	fh->io_allowed = 0;
> +	/* Initialize priority of this instance to default priority */
> +	fh->prio = V4L2_PRIORITY_UNSET;
> +	v4l2_prio_open(&video->prio, &fh->prio);
> +	mutex_unlock(&video->lock);
> +
> +	return 0;
> +}
> +
> +/* get the next buffer available from dma queue */
> +unsigned long vpfe_get_next_buffer(struct vpfe_video_device *video)
> +{
> +	/* mark next buffer as active */
> +	video->next_frm = list_entry(video->dma_queue.next,
> +					struct videobuf_buffer, queue);
> +
> +	/* in single shot mode both curr_frm
> +	   and next_frm point to same buffer */
> +	video->cur_frm = video->next_frm;
> +	list_del(&video->next_frm->queue);
> +	video->next_frm->state = VIDEOBUF_ACTIVE;
> +
> +	return videobuf_to_dma_contig(video->next_frm);
> +}
> +
> +/* schedule the next buffer which is available on dma queue */
> +void vpfe_schedule_next_buffer(struct vpfe_video_device *video)
> +{
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	unsigned long addr;
> +
> +	if (list_empty(&video->dma_queue))
> +		return;
> +
> +	video->next_frm = list_entry(video->dma_queue.next,
> +					struct videobuf_buffer, queue);
> +
> +	if (VPFE_PIPELINE_STREAM_SINGLESHOT == video->pipe.state)
> +		video->cur_frm = video->next_frm;
> +
> +	list_del(&video->next_frm->queue);
> +	video->next_frm->state = VIDEOBUF_ACTIVE;
> +	addr = videobuf_to_dma_contig(video->next_frm);
> +
> +	video->ops->queue(vpfe_dev, addr);
> +
> +	video->state = VPFE_VIDEO_BUFFER_QUEUED;
> +}
> +
> +/* schedule the buffer for capturing bottom field */
> +void vpfe_schedule_bottom_field(struct vpfe_video_device *video)
> +{
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	unsigned long addr;
> +
> +	addr = videobuf_to_dma_contig(video->cur_frm);

Perhaps it is a good idea to upgrade to vb2?

I'm inclined to make it a requirement for new drivers.

> +	addr += video->field_off;
> +
> +	video->ops->queue(vpfe_dev, addr);
> +}
> +
> +/* make buffer available for dequeue */
> +void vpfe_process_buffer_complete(struct vpfe_video_device *video)
> +{
> +	struct vpfe_pipeline *pipe = &video->pipe;
> +	struct timespec timespec;
> +	s64 nsec;
> +
> +	ktime_get_ts(&timespec);
> +	nsec = timespec_to_ns(&timespec);
> +
> +	video->cur_frm->ts = ns_to_timeval(nsec);
> +	video->cur_frm->state = VIDEOBUF_DONE;
> +	video->cur_frm->size = video->fmt.fmt.pix.sizeimage;
> +	wake_up_interruptible(&video->cur_frm->done);
> +	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
> +		video->cur_frm = video->next_frm;
> +}
> +
> +/* vpfe_stop_capture() - stop streaming */
> +static void vpfe_stop_capture(struct vpfe_video_device *video)
> +{
> +	struct vpfe_pipeline *pipe = &video->pipe;
> +
> +	video->started = 0;
> +
> +	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
> +		return;
> +
> +	if (all_videos_stopped(video))
> +		vpfe_pipeline_set_stream(pipe,
> +					 VPFE_PIPELINE_STREAM_STOPPED);
> +}
> +
> +/*
> + * vpfe_release() - release video device
> + * @file: file pointer
> + *
> + * deletes buffer queue, frees the buffers and the vpfe file handle
> + *
> + * Return 0
> + */
> +static int vpfe_release(struct file *file)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_fh *fh = file->private_data;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n");
> +
> +	/* Get the device lock */
> +	mutex_lock(&video->lock);
> +	/* if this instance is doing IO */
> +	if (fh->io_allowed) {
> +		if (video->started) {
> +			vpfe_stop_capture(video);
> +			/* mark pipe state as stopped in vpfe_release(),
> +			   as app might call streamon() after streamoff()
> +			   in which case driver has to start streaming.
> +			*/
> +			video->pipe.state = VPFE_PIPELINE_STREAM_STOPPED;
> +			videobuf_streamoff(&video->buffer_queue);
> +		}
> +		video->io_usrs = 0;
> +	}
> +
> +	/* Decrement device usrs counter */
> +	video->usrs--;
> +	/* Close the priority */
> +	v4l2_prio_close(&video->prio, fh->prio);
> +
> +	/* If this is the last file handle */
> +	if (!video->usrs)
> +		video->initialized = 0;
> +
> +	mutex_unlock(&video->lock);
> +	file->private_data = NULL;
> +	/* Free memory allocated to file handle object */
> +	kzfree(fh);
> +
> +	return 0;
> +}
> +
> +/*
> + * vpfe_mmap() - It is used to map kernel space buffers
> + * into user spaces
> + */
> +static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n");
> +
> +	return videobuf_mmap_mapper(&video->buffer_queue, vma);
> +}
> +
> +/*
> + * vpfe_poll() - It is used for select/poll system call
> + */
> +static unsigned int vpfe_poll(struct file *file, poll_table *wait)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n");
> +
> +	if (video->started)
> +		return videobuf_poll_stream(file,
> +					    &video->buffer_queue, wait);
> +
> +	return 0;
> +}
> +
> +/* vpfe capture driver file operations */
> +static const struct v4l2_file_operations vpfe_fops = {
> +	.owner = THIS_MODULE,
> +	.open = vpfe_open,
> +	.release = vpfe_release,
> +	.unlocked_ioctl = video_ioctl2,
> +	.mmap = vpfe_mmap,
> +	.poll = vpfe_poll
> +};
> +
> +/*
> + * vpfe_querycap() - query capabilities of video device
> + * @file: file pointer
> + * @priv: void pointer
> + * @cap: pointer to v4l2_capability structure
> + *
> + * fills v4l2 capabilities structure
> + *
> + * Return 0
> + */
> +static int vpfe_querycap(struct file *file, void  *priv,
> +			       struct v4l2_capability *cap)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
> +
> +	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
> +	else
> +		cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;

Please set cap->device_caps as well (see the spec for this new functionality).

> +
> +	cap->version = VPFE_CAPTURE_VERSION_CODE;
> +	strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
> +	strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
> +	strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
> +
> +	return 0;
> +}
> +
> +/*
> + * vpfe_g_fmt() - get the format which is active on video device
> + * @file: file pointer
> + * @priv: void pointer
> + * @fmt: pointer to v4l2_format structure
> + *
> + * fills v4l2 format structure with active format
> + *
> + * Return 0
> + */
> +static int vpfe_g_fmt(struct file *file, void *priv,
> +				struct v4l2_format *fmt)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt\n");
> +	/* Fill in the information about format */
> +	*fmt = video->fmt;
> +
> +	return 0;
> +}
> +
> +/*
> + * vpfe_enum_fmt() - enum formats supported on media chain
> + * @file: file pointer
> + * @priv: void pointer
> + * @fmt: pointer to v4l2_fmtdesc structure
> + *
> + * fills v4l2_fmtdesc structure with output format set on adjacent subdev,
> + * only one format is enumearted as subdevs are already configured
> + *
> + * Return 0 if successfull, error code otherwise
> + */
> +static int vpfe_enum_fmt(struct file *file, void  *priv,
> +				   struct v4l2_fmtdesc *fmt)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct v4l2_subdev_format sd_fmt;
> +	struct v4l2_mbus_framefmt mbus;
> +	struct v4l2_subdev *subdev;
> +	struct v4l2_format format;
> +	struct media_pad *remote;
> +	int ret;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt\n");
> +
> +	/* since already subdev pad format is set,
> +	only one pixel format is available */
> +	if (fmt->index > 0) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid index\n");
> +		return -EINVAL;
> +	}
> +
> +	/* get the remote pad */
> +	remote = media_entity_remote_source(&video->pad);
> +	if (remote == NULL) {
> +		v4l2_err(&vpfe_dev->v4l2_dev,
> +			 "invalid remote pad for video node\n");
> +		return -EINVAL;
> +	}
> +
> +	/* get the remote subdev */
> +	subdev = vpfe_video_remote_subdev(video, NULL);
> +	if (subdev == NULL) {
> +		v4l2_err(&vpfe_dev->v4l2_dev,
> +			 "invalid remote subdev for video node\n");
> +		return -EINVAL;
> +	}
> +
> +	sd_fmt.pad = remote->index;
> +	sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +	/* get output format of remote subdev */
> +	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &sd_fmt);
> +	if (ret) {
> +		v4l2_err(&vpfe_dev->v4l2_dev,
> +			 "invalid remote subdev for video node\n");
> +		return ret;
> +	}
> +	/* convert to pix format */
> +	mbus.code = sd_fmt.format.code;
> +	mbus_to_pix(&mbus, &format.fmt.pix);
> +
> +	/* copy the result */
> +	fmt->pixelformat = format.fmt.pix.pixelformat;
> +
> +	return 0;
> +}
> +
> +/*
> + * vpfe_s_fmt() - set the format on video device
> + * @file: file pointer
> + * @priv: void pointer
> + * @fmt: pointer to v4l2_format structure
> + *
> + * validate and set the format on video device
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_s_fmt(struct file *file, void *priv,
> +				struct v4l2_format *fmt)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct v4l2_format format;
> +	int ret;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt\n");
> +
> +	/* If streaming is started, return error */
> +	if (video->started) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n");
> +		return -EBUSY;
> +	}
> +
> +	/* get adjacent subdev's output pad format */
> +	ret = __vpfe_video_get_format(video, &format);
> +	if (ret)
> +		return ret;
> +
> +	*fmt = format;
> +
> +	video->fmt = *fmt;
> +
> +	return 0;
> +}
> +
> +/*
> + * vpfe_try_fmt() - try the format on video device
> + * @file: file pointer
> + * @priv: void pointer
> + * @fmt: pointer to v4l2_format structure
> + *
> + * validate the format, update with correct format
> + * based on output format set on adjacent subdev
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_try_fmt(struct file *file, void *priv,
> +				  struct v4l2_format *fmt)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct v4l2_format format;
> +	int ret;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt\n");
> +
> +	/* get adjacent subdev's output pad format */
> +	ret = __vpfe_video_get_format(video, &format);
> +	if (ret)
> +		return ret;
> +
> +	*fmt = format;
> +
> +	return 0;
> +}
> +
> +/*
> + * vpfe_enum_input() - enum inputs supported on media chain
> + * @file: file pointer
> + * @priv: void pointer
> + * @fmt: pointer to v4l2_fmtdesc structure
> + *
> + * fills v4l2_input structure with input available on media chain,
> + * only one input is enumearted as media chain is setup by this time
> + *
> + * Return 0 if successfull, -EINVAL is media chain is invalid
> + */
> +static int vpfe_enum_input(struct file *file, void *priv,
> +				 struct v4l2_input *inp)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_ext_subdev_info *sdinfo = video->current_ext_subdev;
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
> +
> +	/* enumerate from the subdev user has choosen through mc */
> +	if (inp->index < sdinfo->num_inputs) {
> +		memcpy(inp, &sdinfo->inputs[inp->index],
> +		       sizeof(struct v4l2_input));

This makes the same mistake that the vpif driver have: the assumption that
for each input there is a corresponding subdev. I'm working on a patch for
the vpif_capture/display drivers to fix that. I hope to post that today or
next week.

> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +/*
> + * vpfe_g_input() - get index of the input which is active
> + * @file: file pointer
> + * @priv: void pointer
> + * @index: pointer to unsigned int
> + *
> + * set index with input index which is active
> + *
> + * Return 0
> + */
> +static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n");
> +
> +	*index = video->current_input;
> +
> +	return 0;
> +}
> +
> +/*
> + * vpfe_s_input() - set input which is pointed by input index
> + * @file: file pointer
> + * @priv: void pointer
> + * @index: pointer to unsigned int
> + *
> + * set input on external subdev
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct ccdc_hw_device *ccdc_dev = vpfe_dev->vpfe_ccdc.ccdc_dev;
> +	struct imp_hw_interface *imp_hw_if = vpfe_dev->vpfe_previewer.imp_hw_if;
> +	struct vpfe_ext_subdev_info *sdinfo;
> +	struct vpfe_route *route;
> +	struct v4l2_input *inps;
> +	u32 output;
> +	u32 input;
> +	int ret;
> +	int i;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n");
> +
> +	ret = mutex_lock_interruptible(&video->lock);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * If streaming is started return device busy
> +	 * error
> +	 */
> +	if (video->started) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n");
> +		ret = -EBUSY;
> +		goto unlock_out;
> +	}
> +
> +	sdinfo = video->current_ext_subdev;
> +
> +	if (!sdinfo->registered) {
> +		ret = -EINVAL;
> +		goto unlock_out;
> +	}
> +
> +	if (vpfe_dev->cfg->setup_input &&
> +		vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) {
> +		ret = -EFAULT;
> +		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
> +			  "couldn't setup input for %s\n",
> +			  sdinfo->module_name);
> +		goto unlock_out;
> +	}
> +
> +	route = &sdinfo->routes[index];
> +	if (route && sdinfo->can_route) {
> +		input = route->input;
> +		output = route->output;
> +		ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
> +						 sdinfo->grp_id, video,
> +						 s_routing, input, output, 0);
> +
> +		if (ret) {
> +			v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
> +				"s_input:error in setting input in decoder\n");
> +			ret = -EINVAL;
> +			goto unlock_out;
> +		}
> +	}
> +
> +	/* set standards set by subdev in video device */
> +	for (i = 0; i < sdinfo->num_inputs; i++) {
> +		inps = &sdinfo->inputs[i];
> +		video->video_dev.tvnorms |= inps->std;
> +	}
> +
> +	/* set the bus/interface parameter for the sub device in ccdc */
> +	ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
> +	if (ret)
> +		goto unlock_out;
> +
> +	/* update the if parameters to imp hw interface */
> +	if (imp_hw_if && imp_hw_if->set_hw_if_param)
> +		ret = imp_hw_if->set_hw_if_param(vpfe_dev->ipipe,
> +						 &sdinfo->ccdc_if_params);
> +	if (ret)
> +		goto unlock_out;
> +
> +	video->current_input = index;
> +
> +unlock_out:
> +	mutex_unlock(&video->lock);
> +	return ret;
> +}
> +
> +/*
> + * vpfe_querystd() - query std which is being input on external subdev
> + * @file: file pointer
> + * @priv: void pointer
> + * @std_id: pointer to v4l2_std_id structure
> + *
> + * call external subdev through v4l2_device_call_until_err to
> + * get the std that is being active.
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_ext_subdev_info *sdinfo;
> +	int ret;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n");
> +
> +	ret = mutex_lock_interruptible(&video->lock);
> +	sdinfo = video->current_ext_subdev;
> +	if (ret)
> +		return ret;
> +
> +	/* Call querystd function of decoder device */
> +	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
> +					 video, querystd, std_id);
> +	mutex_unlock(&video->lock);
> +
> +	return ret;
> +}
> +
> +/*
> + * vpfe_s_std() - set std on external subdev
> + * @file: file pointer
> + * @priv: void pointer
> + * @std_id: pointer to v4l2_std_id structure
> + *
> + * set std pointed by std_id on external subdev by calling it using
> + * v4l2_device_call_until_err
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_ext_subdev_info *sdinfo;
> +	int ret;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n");
> +
> +	/* Call decoder driver function to set the standard */
> +	ret = mutex_lock_interruptible(&video->lock);
> +	if (ret)
> +		return ret;
> +
> +	sdinfo = video->current_ext_subdev;
> +	/* If streaming is started, return device busy error */
> +	if (video->started) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n");
> +		ret = -EBUSY;
> +		goto unlock_out;
> +	}
> +
> +	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
> +					 core, s_std, *std_id);
> +	if (ret < 0) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
> +		goto unlock_out;
> +	}
> +
> +unlock_out:
> +	mutex_unlock(&video->lock);
> +	return ret;
> +}
> +
> +/*
> + * vpfe_enum_preset() - enumerate dv_preset which are supported by
> + * to external subdev
> + *
> + * @file: file pointer
> + * @priv: void pointer
> + * @preset: pointer to v4l2_dv_enum_preset structure
> + *
> + * enum dv_preset's which are supported by external subdev through
> + * v4l2_subdev_call
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_enum_preset(struct file *file, void *fh,
> +			    struct v4l2_dv_enum_preset *preset)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_preset\n");
> +
> +	return v4l2_subdev_call(subdev, video, enum_dv_presets, preset);
> +}
> +
> +/*
> + * vpfe_query_preset() - query the dv_preset which is being input
> + * to external subdev
> + *
> + * @file: file pointer
> + * @priv: void pointer
> + * @preset: pointer to v4l2_preset structure
> + *
> + * get dv_preset which is being input on external subdev through
> + * v4l2_subdev_call
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_query_preset(struct file *file, void *fh,
> +			     struct v4l2_dv_preset *preset)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_query_preset\n");
> +
> +	return v4l2_subdev_call(subdev, video, query_dv_preset, preset);
> +}
> +
> +/*
> + * vpfe_s_preset() - set dv_preset on external subdev
> + * @file: file pointer
> + * @priv: void pointer
> + * @preset: pointer to v4l2_preset structure
> + *
> + * set dv_preset pointed by preset on external subdev through
> + * v4l2_device_call_until_err, this configures amplifier also
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_s_preset(struct file *file, void *fh,
> +			 struct v4l2_dv_preset *preset)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_preset\n");
> +
> +	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
> +					  video->current_ext_subdev->grp_id,
> +					  video, s_dv_preset, preset);
> +}
> +
> +/*
> + * vpfe_g_preset() - get dv_preset which is set on external subdev
> + * @file: file pointer
> + * @priv: void pointer
> + * @preset: pointer to v4l2_preset structure
> + *
> + * get dv_preset which is set on external subdev through
> + * v4l2_subdev_call
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_g_preset(struct file *file, void *fh,
> +			 struct v4l2_dv_preset *preset)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_preset\n");
> +
> +	return v4l2_subdev_call(subdev, video, query_dv_preset, preset);
> +}

The preset API is deprecated and replaced by the DV Timings API. New drivers
should implement that API instead.

> +
> +/*
> + *  Videobuf operations
> + */
> +static int vpfe_videobuf_setup(struct videobuf_queue *vq,
> +				unsigned int *count,
> +				unsigned int *size)
> +{
> +	struct vpfe_fh *fh = vq->priv_data;
> +	struct vpfe_video_device *video = fh->video;
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_pipeline *pipe = &video->pipe;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
> +
> +	*size = video->fmt.fmt.pix.sizeimage;
> +
> +	if (vpfe_dev->video_limit) {
> +		while (*size * *count > vpfe_dev->video_limit)
> +			(*count)--;
> +	}
> +
> +	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) {
> +		if (*count < CONT_MIN_NUM_BUFFERS)
> +			*count = CONT_MIN_NUM_BUFFERS;
> +	}
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
> +		"count=%d, size=%d\n", *count, *size);
> +
> +	return 0;
> +}
> +
> +static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
> +				struct videobuf_buffer *vb,
> +				enum v4l2_field field)
> +{
> +	struct vpfe_fh *fh = vq->priv_data;
> +	struct vpfe_video_device *video = fh->video;
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	unsigned long addr;
> +	int ret;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_prepare\n");
> +
> +	if (VIDEOBUF_NEEDS_INIT != vb->state)
> +		return 0;
> +
> +	/* Initialize buffer */
> +	vb->width = video->fmt.fmt.pix.width;
> +	vb->height = video->fmt.fmt.pix.height;
> +	vb->size = video->fmt.fmt.pix.sizeimage;
> +	vb->field = field;
> +
> +	ret = videobuf_iolock(vq, vb, NULL);
> +	if (ret < 0)
> +		return ret;
> +
> +	addr = videobuf_to_dma_contig(vb);
> +	/* Make sure user addresses are aligned to 32 bytes */
> +	if (!ALIGN(addr, 32))
> +		return -EINVAL;
> +
> +	vb->state = VIDEOBUF_PREPARED;
> +
> +	return 0;
> +}
> +
> +static void vpfe_videobuf_queue(struct videobuf_queue *vq,
> +				struct videobuf_buffer *vb)
> +{
> +	/* Get the file handle object and device object */
> +	struct vpfe_fh *fh = vq->priv_data;
> +	struct vpfe_video_device *video = fh->video;
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_pipeline *pipe = &video->pipe;
> +	unsigned long flags;
> +	unsigned long empty;
> +	unsigned long addr;
> +
> +	spin_lock_irqsave(&video->dma_queue_lock, flags);
> +	empty = list_empty(&video->dma_queue);
> +
> +	/* add the buffer to the DMA queue */
> +	list_add_tail(&vb->queue, &video->dma_queue);
> +	spin_unlock_irqrestore(&video->dma_queue_lock, flags);
> +
> +	/* Change state of the buffer */
> +	vb->state = VIDEOBUF_QUEUED;
> +
> +	/* this case happens in case of single shot */
> +	if (empty && video->started && pipe->state ==
> +		VPFE_PIPELINE_STREAM_SINGLESHOT &&
> +		video->state == VPFE_VIDEO_BUFFER_NOT_QUEUED) {
> +		spin_lock(&video->dma_queue_lock);
> +		addr = vpfe_get_next_buffer(video);
> +		video->ops->queue(vpfe_dev, addr);
> +
> +		video->state = VPFE_VIDEO_BUFFER_QUEUED;
> +		spin_unlock(&video->dma_queue_lock);
> +
> +		/* enable h/w each time in single shot */
> +		if (is_pipe_ready(pipe))
> +			vpfe_pipeline_set_stream(pipe,
> +					VPFE_PIPELINE_STREAM_SINGLESHOT);
> +	}
> +}
> +
> +static void vpfe_videobuf_release(struct videobuf_queue *vq,
> +				  struct videobuf_buffer *vb)
> +{
> +	struct vpfe_fh *fh = vq->priv_data;
> +	struct vpfe_video_device *video = fh->video;
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n");
> +
> +	if (video->memory == V4L2_MEMORY_MMAP)
> +		videobuf_dma_contig_free(vq, vb);
> +	vb->state = VIDEOBUF_NEEDS_INIT;
> +}
> +
> +static struct videobuf_queue_ops vpfe_videobuf_qops = {
> +	.buf_setup      = vpfe_videobuf_setup,
> +	.buf_prepare    = vpfe_videobuf_prepare,
> +	.buf_queue      = vpfe_videobuf_queue,
> +	.buf_release    = vpfe_videobuf_release,
> +};

Again, I highly recommend moving to the videobuf2 framework. If nothing else,
the vb2 framework will get support for DMABUF, allowing zero-copy pipelining.

> +
> +/*
> + * vpfe_reqbufs() - supported REQBUF only once opening
> + * the device.
> + */
> +static int vpfe_reqbufs(struct file *file, void *priv,
> +			struct v4l2_requestbuffers *req_buf)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_fh *fh = file->private_data;
> +	int ret;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n");
> +
> +	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type &&
> +		V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = mutex_lock_interruptible(&video->lock);
> +	if (ret)
> +		return ret;
> +
> +	if (video->io_usrs != 0) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n");
> +		ret = -EBUSY;
> +		goto unlock_out;
> +	}
> +
> +	video->memory = req_buf->memory;
> +	videobuf_queue_dma_contig_init(&video->buffer_queue,
> +				&vpfe_videobuf_qops, vpfe_dev->pdev,
> +				&video->irqlock, req_buf->type,
> +				video->fmt.fmt.pix.field,
> +				sizeof(struct videobuf_buffer),
> +				fh, NULL);
> +
> +	fh->io_allowed = 1;
> +	video->io_usrs = 1;
> +	INIT_LIST_HEAD(&video->dma_queue);
> +	ret = videobuf_reqbufs(&video->buffer_queue, req_buf);
> +
> +unlock_out:
> +	mutex_unlock(&video->lock);
> +	return ret;
> +}
> +
> +/*
> + * vpfe_querybuf() - query buffers for exchange
> + */
> +static int vpfe_querybuf(struct file *file, void *priv,
> +			 struct v4l2_buffer *buf)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n");
> +
> +	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type &&
> +		V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
> +		return  -EINVAL;
> +	}
> +
> +	if (video->memory != V4L2_MEMORY_MMAP) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Call videobuf_querybuf to get information */
> +	return videobuf_querybuf(&video->buffer_queue, buf);
> +}
> +
> +/*
> + * vpfe_qbuf() - queue buffers for capture or processing
> + */
> +static int vpfe_qbuf(struct file *file, void *priv,
> +		     struct v4l2_buffer *p)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_fh *fh = file->private_data;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n");
> +
> +	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type &&
> +		V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * If this file handle is not allowed to do IO,
> +	 * return error
> +	 */
> +	if (!fh->io_allowed) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
> +		return -EACCES;
> +	}
> +
> +	return videobuf_qbuf(&video->buffer_queue, p);
> +}
> +
> +/*
> + * vpfe_dqbuf() - deque buffer which is done with processing
> + */
> +static int vpfe_dqbuf(struct file *file, void *priv,
> +		      struct v4l2_buffer *buf)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n");
> +
> +	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type &&
> +		V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
> +		return -EINVAL;
> +	}
> +
> +	return videobuf_dqbuf(&video->buffer_queue,
> +				      buf, file->f_flags & O_NONBLOCK);
> +}
> +
> +/* vpfe_start_capture() - start streaming on all the subdevs */
> +static int vpfe_start_capture(struct vpfe_video_device *video)
> +{
> +	struct vpfe_pipeline *pipe = &video->pipe;
> +	int ret = 0;
> +
> +	video->started = 1;
> +
> +	if (is_pipe_ready(pipe))
> +		ret = vpfe_pipeline_set_stream(pipe, pipe->state);
> +
> +	return ret;
> +}
> +
> +/*
> + * vpfe_streamon() - get dv_preset which is set on external subdev
> + * @file: file pointer
> + * @priv: void pointer
> + * @buf_type: enum v4l2_buf_type
> + *
> + * queue buffer onto hardware for capture/processing and
> + * start all the subdevs which are in media chain
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_streamon(struct file *file, void *priv,
> +			 enum v4l2_buf_type buf_type)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_pipeline *pipe = &video->pipe;
> +	struct vpfe_fh *fh = file->private_data;
> +	struct vpfe_ext_subdev_info *sdinfo;
> +	unsigned long addr;
> +	int ret = -EINVAL;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n");
> +
> +	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type &&
> +		V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
> +		return ret;
> +	}
> +
> +	/* If file handle is not allowed IO, return error */
> +	if (!fh->io_allowed) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
> +		return -EACCES;
> +	}
> +	sdinfo = video->current_ext_subdev;
> +	/* If buffer queue is empty, return error */
> +	if (list_empty(&video->buffer_queue.stream)) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n");
> +		return -EIO;
> +	}
> +	/* Validate the pipeline */
> +	if (V4L2_BUF_TYPE_VIDEO_CAPTURE == buf_type) {
> +		ret = vpfe_video_validate_pipeline(pipe);
> +		if (ret < 0)
> +			return ret;
> +	}
> +	/* Call videobuf_streamon to start streaming * in videobuf */
> +	ret = videobuf_streamon(&video->buffer_queue);
> +	if (ret)
> +		return ret;
> +
> +	ret = mutex_lock_interruptible(&video->lock);
> +	if (ret)
> +		goto streamoff;
> +
> +	/* Get the next frame from the buffer queue */
> +	video->next_frm = list_entry(video->dma_queue.next,
> +					struct videobuf_buffer, queue);
> +	video->cur_frm = video->next_frm;
> +	/* Remove buffer from the buffer queue */
> +	list_del(&video->cur_frm->queue);
> +	/* Mark state of the current frame to active */
> +	video->cur_frm->state = VIDEOBUF_ACTIVE;
> +	/* Initialize field_id and started member */
> +	video->field_id = 0;
> +	addr = videobuf_to_dma_contig(video->cur_frm);
> +	video->ops->queue(vpfe_dev, addr);
> +	video->state = VPFE_VIDEO_BUFFER_QUEUED;
> +	ret = vpfe_start_capture(video);
> +	if (ret)
> +		goto unlock_out;
> +
> +	mutex_unlock(&video->lock);
> +	return ret;
> +unlock_out:
> +	mutex_unlock(&video->lock);
> +streamoff:
> +	ret = videobuf_streamoff(&video->buffer_queue);
> +	return ret;
> +}
> +
> +/*
> + * vpfe_streamoff() - get dv_preset which is set on external subdev
> + * @file: file pointer
> + * @priv: void pointer
> + * @buf_type: enum v4l2_buf_type
> + *
> + * stop all the subdevs which are in media chain
> + *
> + * Return 0 on success, error code otherwise
> + */
> +static int vpfe_streamoff(struct file *file, void *priv,
> +			  enum v4l2_buf_type buf_type)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_fh *fh = file->private_data;
> +	int ret = 0;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n");
> +
> +	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
> +		buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> +		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "Invalid buf type\n");
> +		return -EINVAL;
> +	}
> +
> +	/* If io is allowed for this file handle, return error */
> +	if (!fh->io_allowed) {
> +		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "fh->io_allowed\n");
> +		return -EACCES;
> +	}
> +
> +	/* If streaming is not started, return error */
> +	if (!video->started) {
> +		v4l2_err(&vpfe_dev->v4l2_dev, "device is not started\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = mutex_lock_interruptible(&video->lock);
> +	if (ret)
> +		return ret;
> +
> +	vpfe_stop_capture(video);
> +
> +	ret = videobuf_streamoff(&video->buffer_queue);
> +	mutex_unlock(&video->lock);
> +
> +	return ret;
> +}
> +
> +/*
> + * vpfe_queryctrl() - query for v4l2 controls which is set on external subdev
> + * @file: file pointer
> + * @priv: void pointer
> + * @ctrl: pointer to v4l2_control structure
> + *
> + * get the v4l2 controls active on external subdev through
> + * v4l2_device_call_until_err
> + *
> + * Return return value returned by v4l2_device_call_until_err
> + */
> +static int vpfe_queryctrl(struct file *file, void *priv,
> +				struct v4l2_queryctrl *qc)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_ext_subdev_info *sub_dev = video->current_ext_subdev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_queryctrl\n");
> +
> +	/* pass it to sub device */
> +	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sub_dev->grp_id,
> +					  core, queryctrl, qc);
> +}

It is compulsory to use the control framework.

Which should be simple enough: make an empty control handler, let the ctrl_handler field
of struct v4l2_device point to it and then when the subdevs are added the controls of
each subdev will be added (inherited) as well.

> +
> +/*
> + * vpfe_g_ctrl() - get the v4l2 controls which is set on external subdev
> + * @file: file pointer
> + * @priv: void pointer
> + * @ctrl: pointer to v4l2_control structure
> + *
> + * get the v4l2 controls set on external subdev through
> + * v4l2_device_call_until_err
> + *
> + * Return return value returned by v4l2_device_call_until_err
> + */
> +static int vpfe_g_ctrl(struct file *file, void *priv,
> +			struct v4l2_control *ctrl)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_ext_subdev_info *sub_dev = video->current_ext_subdev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_ctrl\n");
> +
> +	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sub_dev->grp_id,
> +					  core, g_ctrl, ctrl);
> +}
> +
> +/*
> + * vpfe_s_ctrl() - set the v4l2 controls on external subdev
> + * @file: file pointer
> + * @priv: void pointer
> + * @ctrl: pointer to v4l2_control structure
> + *
> + * call external subdev through v4l2_device_call_until_err to
> + * set v4l2 controls
> + *
> + * Return return value returned by v4l2_device_call_until_err
> + */
> +static int vpfe_s_ctrl(struct file *file, void *priv,
> +			     struct v4l2_control *ctrl)
> +{
> +	struct vpfe_video_device *video = video_drvdata(file);
> +	struct vpfe_device *vpfe_dev = video->vpfe_dev;
> +	struct vpfe_ext_subdev_info *sub_dev = video->current_ext_subdev;
> +
> +	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_ctrl\n");
> +
> +	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sub_dev->grp_id,
> +					  core, s_ctrl, ctrl);
> +}
> +
> +/* vpfe capture ioctl operations */
> +static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
> +	.vidioc_querycap	 = vpfe_querycap,
> +	.vidioc_g_fmt_vid_cap    = vpfe_g_fmt,
> +	.vidioc_s_fmt_vid_cap    = vpfe_s_fmt,
> +	.vidioc_try_fmt_vid_cap  = vpfe_try_fmt,
> +	.vidioc_enum_fmt_vid_cap = vpfe_enum_fmt,
> +	.vidioc_g_fmt_vid_out    = vpfe_g_fmt,
> +	.vidioc_s_fmt_vid_out    = vpfe_s_fmt,
> +	.vidioc_try_fmt_vid_out  = vpfe_try_fmt,
> +	.vidioc_enum_fmt_vid_out = vpfe_enum_fmt,
> +	.vidioc_enum_input	 = vpfe_enum_input,
> +	.vidioc_g_input		 = vpfe_g_input,
> +	.vidioc_s_input		 = vpfe_s_input,
> +	.vidioc_querystd	 = vpfe_querystd,
> +	.vidioc_s_std		 = vpfe_s_std,
> +	.vidioc_enum_dv_presets	 = vpfe_enum_preset,
> +	.vidioc_query_dv_preset	 = vpfe_query_preset,
> +	.vidioc_s_dv_preset	 = vpfe_s_preset,
> +	.vidioc_g_dv_preset	 = vpfe_g_preset,
> +	.vidioc_reqbufs		 = vpfe_reqbufs,
> +	.vidioc_querybuf	 = vpfe_querybuf,
> +	.vidioc_qbuf		 = vpfe_qbuf,
> +	.vidioc_dqbuf		 = vpfe_dqbuf,
> +	.vidioc_streamon	 = vpfe_streamon,
> +	.vidioc_streamoff	 = vpfe_streamoff,
> +	.vidioc_queryctrl	 = vpfe_queryctrl,
> +	.vidioc_g_ctrl		 = vpfe_g_ctrl,
> +	.vidioc_s_ctrl		 = vpfe_s_ctrl,
> +};
> +
> +/* VPFE video init function */
> +int vpfe_video_init(struct vpfe_video_device *video, const char *name)
> +{
> +	const char *direction;
> +	int ret;
> +
> +	switch (video->type) {
> +	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
> +		direction = "output";
> +		video->pad.flags = MEDIA_PAD_FL_SINK;
> +		video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +		break;
> +	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
> +		direction = "input";
> +		video->pad.flags = MEDIA_PAD_FL_SOURCE;
> +		video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	/* Initialize field of video device */
> +	video->video_dev.release = video_device_release;
> +	video->video_dev.fops = &vpfe_fops;
> +	video->video_dev.ioctl_ops = &vpfe_ioctl_ops;
> +	video->video_dev.minor = -1;
> +	video->video_dev.tvnorms = 0;
> +	video->video_dev.current_norm = V4L2_STD_NTSC;

Don't use current_norm. Create a proper vpfe_g_std instead. current_norm is
being phased out.

> +
> +	snprintf(video->video_dev.name, sizeof(video->video_dev.name),
> +		 "DAVINCI VIDEO %s %s", name, direction);
> +
> +	/* Initialize prio member of device object */
> +	v4l2_prio_init(&video->prio);
> +
> +	spin_lock_init(&video->irqlock);
> +	spin_lock_init(&video->dma_queue_lock);
> +	mutex_init(&video->lock);
> +
> +	ret = media_entity_init(&video->video_dev.entity,
> +				1, &video->pad, 0);
> +	if (ret < 0)
> +		return ret;
> +
> +	video_set_drvdata(&video->video_dev, video);
> +
> +	return 0;
> +}
> +
> +/* vpfe video device register function */
> +int vpfe_video_register(struct vpfe_video_device *video,
> +			struct v4l2_device *vdev)
> +{
> +	int ret;
> +
> +	video->video_dev.v4l2_dev = vdev;
> +
> +	ret = video_register_device(&video->video_dev, VFL_TYPE_GRABBER, -1);
> +	if (ret < 0)
> +		pr_err("%s: could not register video device (%d)\n",
> +		       __func__, ret);
> +
> +	return ret;
> +}
> +
> +/* vpfe video device unregister function */
> +void vpfe_video_unregister(struct vpfe_video_device *video)
> +{
> +	if (video_is_registered(&video->video_dev)) {
> +		media_entity_cleanup(&video->video_dev.entity);
> +		video_unregister_device(&video->video_dev);
> +	}
> +}
> diff --git a/drivers/media/platform/davinci/vpfe_video.h b/drivers/media/platform/davinci/vpfe_video.h
> new file mode 100644
> index 0000000..af68caf
> --- /dev/null
> +++ b/drivers/media/platform/davinci/vpfe_video.h
> @@ -0,0 +1,150 @@
> +/*
> + * Copyright (C) 2012 Texas Instruments 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 version 2.
> + *
> + * 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
> + *
> + * Contributors:
> + *      Manjunath Hadli <manjunath.hadli@ti.com>
> + *      Prabhakar Lad <prabhakar.lad@ti.com>
> + */
> +
> +/* All video device related structures will go here */
> +#ifndef _VPFE_VIDEO_H
> +#define _VPFE_VIDEO_H
> +
> +#include <media/media-entity.h>
> +#include <media/videobuf-dma-contig.h>
> +
> +struct vpfe_device;
> +
> +/*
> + * struct vpfe_video_operations - VPFE video operations
> + * @queue:	Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
> + *		if there was no buffer previously queued.
> + */
> +struct vpfe_video_operations {
> +	void(*queue)(struct vpfe_device *vpfe_dev, unsigned long addr);
> +};
> +
> +enum vpfe_pipeline_stream_state {
> +	VPFE_PIPELINE_STREAM_STOPPED,
> +	VPFE_PIPELINE_STREAM_CONTINUOUS,
> +	VPFE_PIPELINE_STREAM_SINGLESHOT
> +};
> +
> +enum vpfe_video_state {
> +	/* indicates that buffer is not queued */
> +	VPFE_VIDEO_BUFFER_NOT_QUEUED = 0,
> +	/* indicates that buffer is queued */
> +	VPFE_VIDEO_BUFFER_QUEUED = 1,
> +};
> +
> +struct vpfe_pipeline {
> +	/* media pipeline */
> +	struct media_pipeline		*pipe;
> +	/* state of the pipeline, continous,
> +	single-shot or stopped */
> +	enum vpfe_pipeline_stream_state	state;
> +	/* number of active input video entities */
> +	unsigned int			input_num;
> +	/* number of active output video entities */
> +	unsigned int			output_num;
> +	/* input video nodes in case of single-shot mode */
> +	struct vpfe_video_device	*inputs[10];
> +	/* capturing video nodes */
> +	struct vpfe_video_device	*outputs[10];
> +};
> +
> +#define to_vpfe_pipeline(__e) \
> +	container_of((__e)->pipe, struct vpfe_pipeline, pipe)
> +
> +#define to_vpfe_video(vdev) \
> +	container_of(vdev, struct vpfe_video_device, video_dev)
> +
> +struct vpfe_video_device {
> +	/* vpfe device */
> +	struct vpfe_device			*vpfe_dev;
> +	/* video dev */
> +	struct video_device			video_dev;
> +	/* media pad of video entity */
> +	struct media_pad			pad;
> +	/* video operations supported by video device */
> +	const struct vpfe_video_operations	*ops;
> +	/* type of the video buffers used by user */
> +	enum v4l2_buf_type			type;
> +	/* Indicates id of the field which is being captured */
> +	u32					field_id;
> +	/* pipiline for which video device is part of */
> +	struct vpfe_pipeline			pipe;
> +	/* Indicates whether streaming started */
> +	u8					started;
> +	/* Indicates state of the stream */
> +	unsigned int				state;
> +	/* current input at the sub device */
> +	int					current_input;
> +	/*
> +	 * This field keeps track of type of buffer exchange mechanism
> +	 * user has selected
> +	 */
> +	enum v4l2_memory			memory;
> +	/* Used to keep track of state of the priority */
> +	struct v4l2_prio_state			prio;
> +	/* number of open instances of the channel */
> +	u32					usrs;
> +	/* flag to indicate whether decoder is initialized */
> +	u8					initialized;
> +	/* skip frame count */
> +	u8					skip_frame_count;
> +	/* skip frame count init value */
> +	u8					skip_frame_count_init;
> +	/* time per frame for skipping */
> +	struct v4l2_fract			timeperframe;
> +	/* ptr to currently selected sub device */
> +	struct vpfe_ext_subdev_info		*current_ext_subdev;
> +	/* Pointer pointing to current v4l2_buffer */
> +	struct videobuf_buffer			*cur_frm;
> +	/* Pointer pointing to next v4l2_buffer */
> +	struct videobuf_buffer			*next_frm;
> +	/* Used to store pixel format */
> +	struct v4l2_format			fmt;
> +	/* Buffer queue used in video-buf */
> +	struct videobuf_queue			buffer_queue;
> +	/* Queue of filled frames */
> +	struct list_head			dma_queue;
> +	/* Used in video-buf */
> +	spinlock_t				irqlock;
> +	/* IRQ lock for DMA queue */
> +	spinlock_t				dma_queue_lock;
> +	/* lock used to access this structure */
> +	struct mutex				lock;
> +	/* number of users performing IO */
> +	u32					io_usrs;
> +	/*
> +	 * offset where second field starts from the starting of the
> +	 * buffer for field seperated YCbCr formats
> +	 */
> +	u32					field_off;
> +};
> +
> +int is_pipe_ready(struct vpfe_pipeline *pipe);
> +void vpfe_video_unregister(struct vpfe_video_device *video);
> +int vpfe_video_register(struct vpfe_video_device *video,
> +			struct v4l2_device *vdev);
> +int vpfe_video_init(struct vpfe_video_device *video, const char *name);
> +
> +void vpfe_process_buffer_complete(struct vpfe_video_device *video);
> +void vpfe_schedule_bottom_field(struct vpfe_video_device *video);
> +void vpfe_schedule_next_buffer(struct vpfe_video_device *video);
> +unsigned long vpfe_get_next_buffer(struct vpfe_video_device *video);
> +#endif
> 

Regards,

	Hans

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 01/14] davinci: vpfe: add dm3xx IPIPEIF hardware support module
  2012-09-14 12:46 ` [PATCH 01/14] davinci: vpfe: add dm3xx IPIPEIF hardware support module Prabhakar Lad
@ 2012-09-19 22:01   ` Laurent Pinchart
  2012-09-22  5:08     ` Prabhakar Lad
  0 siblings, 1 reply; 23+ messages in thread
From: Laurent Pinchart @ 2012-09-19 22:01 UTC (permalink / raw)
  To: davinci-linux-open-source
  Cc: Prabhakar Lad, LMML, LKML, Mauro Carvalho Chehab

Hi Prabhakar,

Thanks for the patch.

On Friday 14 September 2012 18:16:31 Prabhakar Lad wrote:
> From: Manjunath Hadli <manjunath.hadli@ti.com>
> 
> add support for dm3xx IPIPEIF hardware setup. This is the
> lowest software layer for the dm3x vpfe driver which directly
> accesses hardware. Add support for features like default
> pixel correction, dark frame substraction and hardware setup.
> 
> Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
> Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
> ---
>  drivers/media/platform/davinci/dm3xx_ipipeif.c |  318 +++++++++++++++++++++
>  drivers/media/platform/davinci/dm3xx_ipipeif.h |  262 +++++++++++++++++++
>  include/linux/dm3xx_ipipeif.h                  |   62 +++++


>  3 files changed, 642 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/platform/davinci/dm3xx_ipipeif.c
>  create mode 100644 drivers/media/platform/davinci/dm3xx_ipipeif.h
>  create mode 100644 include/linux/dm3xx_ipipeif.h
> 
> diff --git a/drivers/media/platform/davinci/dm3xx_ipipeif.c
> b/drivers/media/platform/davinci/dm3xx_ipipeif.c new file mode 100644
> index 0000000..7961a74
> --- /dev/null
> +++ b/drivers/media/platform/davinci/dm3xx_ipipeif.c

[snip]

> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/uaccess.h>
> +#include <linux/v4l2-mediabus.h>
> +#include <linux/platform_device.h>

Just a side note, I usually sort headers alphabetically, but feel free to use 
whatever convention you like.

> +#include "dm3xx_ipipeif.h"
> +
> +static void *__iomem ipipeif_base_addr;

That's not good. You shouldn't have global constants like that. The value 
should instead be stored in your device structure, that you will need to pass 
around to all functions.

> +static inline u32 regr_if(u32 offset)
> +{
> +	return readl(ipipeif_base_addr + offset);
> +}
> +
> +static inline void regw_if(u32 val, u32 offset)
> +{
> +	writel(val, ipipeif_base_addr + offset);
> +}

Maybe ipipeif_read() and ipipeif_write() ?

> +void ipipeif_set_enable()
> +{
> +	regw_if(1, IPIPEIF_ENABLE);
> +}

Please define constants in a header file for register values, masks and shifts 
instead of hardcoding the raw numbers.

[snip]

> +static int __devinit dm3xx_ipipeif_probe(struct platform_device *pdev)
> +{
> +	static resource_size_t  res_len;
> +	struct resource *res;
> +	int status;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENOENT;
> +
> +	res_len = resource_size(res);
> +
> +	res = request_mem_region(res->start, res_len, res->name);
> +	if (!res)
> +		return -EBUSY;
> +
> +	ipipeif_base_addr = ioremap_nocache(res->start, res_len);
> +	if (!ipipeif_base_addr) {
> +		status = -EBUSY;
> +		goto fail;
> +	}
> +	return 0;
> +
> +fail:
> +	release_mem_region(res->start, res_len);
> +
> +	return status;
> +}
> +
> +static int dm3xx_ipipeif_remove(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +
> +	iounmap(ipipeif_base_addr);
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (res)
> +		release_mem_region(res->start, resource_size(res));
> +	return 0;
> +}
> +
> +static struct platform_driver dm3xx_ipipeif_driver = {
> +	.driver = {
> +		.name   = "dm3xx_ipipeif",
> +		.owner = THIS_MODULE,
> +	},
> +	.remove = __devexit_p(dm3xx_ipipeif_remove),
> +	.probe = dm3xx_ipipeif_probe,
> +};
> +
> +static int dm3xx_ipipeif_init(void)
> +{
> +	return platform_driver_register(&dm3xx_ipipeif_driver);
> +}
> +
> +static void dm3xx_ipipeif_exit(void)
> +{
> +	platform_driver_unregister(&dm3xx_ipipeif_driver);
> +}
> +
> +module_init(dm3xx_ipipeif_init);
> +module_exit(dm3xx_ipipeif_exit);

I'm not sure to like this. You're registering a module for a device that 
essentially sits there without doing anything, except providing functions that 
can be called by other modules.

I somehow feel that the way the code is split amongst the different layers 
isn't optimal. Could you briefly explain the rationale behind the current 
architecture ?

(BTW, please use the module_platform_driver() macro instead of 
module_init/module_exit)

[snip]

> diff --git a/include/linux/dm3xx_ipipeif.h b/include/linux/dm3xx_ipipeif.h
> new file mode 100644
> index 0000000..1c1a830
> --- /dev/null
> +++ b/include/linux/dm3xx_ipipeif.h

[snip]

> +#include <media/davinci/vpfe_types.h>
> +#include <media/davinci/vpfe.h>

This header file defines part of the userspace API, but includes media/ 
headers that are not exported to userspace.

Header files should be split between 3 directories:

- Definitions required by platform data used to go to media/ but the new 
include/linux/platform_data/ directory might be preferred nowadays. I have no 
strong opinion on this, as other headers are already in media/ you can 
probably keep using it for now.

- Definitions requires by userspace should go to include/linux/

- The rest should go to drivers/media/platform/davinci/.

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 06/14] davinci: vpfe: add v4l2 video driver support
  2012-09-14 13:30   ` Hans Verkuil
@ 2012-09-22  5:03     ` Prabhakar Lad
  0 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-22  5:03 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: LMML, LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

Hi Hans,

Thanks for the review.

On Fri, Sep 14, 2012 at 7:00 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On Fri 14 September 2012 14:46:36 Prabhakar Lad wrote:
>> From: Manjunath Hadli <manjunath.hadli@ti.com>
>>
>> add a generic video driver functionality to be used by all the vpfe
>> drivers for davinci SoCs. The functionality includes all the
>> standard v4l2 interfaces including streaming. The video node
>> interface can be used both as an input and output node for both
>> continuous and single shot modes.Also supports dv_presets to include
>> HD modes, wth support for both user pointer IO and mmap.
>>
>> Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
>> Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
>> ---
>>  drivers/media/platform/davinci/vpfe_video.c | 1725 +++++++++++++++++++++++++++
>>  drivers/media/platform/davinci/vpfe_video.h |  150 +++
>>  2 files changed, 1875 insertions(+), 0 deletions(-)
>>  create mode 100644 drivers/media/platform/davinci/vpfe_video.c
>>  create mode 100644 drivers/media/platform/davinci/vpfe_video.h
>>
>> diff --git a/drivers/media/platform/davinci/vpfe_video.c b/drivers/media/platform/davinci/vpfe_video.c
>> new file mode 100644
>> index 0000000..2e696a0
>> --- /dev/null
>> +++ b/drivers/media/platform/davinci/vpfe_video.c
>> @@ -0,0 +1,1725 @@
>> +/*
>> + * Copyright (C) 2012 Texas Instruments 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 version 2.
>> + *
>> + * 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
>> + *
>> + * Contributors:
>> + *      Manjunath Hadli <manjunath.hadli@ti.com>
>> + *      Prabhakar Lad <prabhakar.lad@ti.com>
>> + */
>> +
>> +#include <linux/slab.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include <media/v4l2-common.h>
>> +#include <media/v4l2-mediabus.h>
>> +#include <media/media-entity.h>
>> +#include <media/media-device.h>
>> +#include <media/davinci/vpfe_types.h>
>> +
>> +#include <mach/cputype.h>
>> +
>> +#include "vpfe_mc_capture.h"
>> +#include "ccdc_hw_device.h"
>> +
>> +/* minimum number of buffers needed in cont-mode */
>> +#define CONT_MIN_NUM_BUFFERS 3
>> +
>> +static int debug;
>> +
>> +/* get v4l2 subdev pointer to external subdev which is active */
>> +static struct media_entity *vpfe_get_input_entity
>> +                     (struct vpfe_video_device *video)
>> +{
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct media_pad *remote;
>> +
>> +     remote = media_entity_remote_source(&vpfe_dev->vpfe_ccdc.pads[0]);
>> +     if (remote == NULL) {
>> +             pr_err("Invalid media connection to ccdc\n");
>> +             return NULL;
>> +     }
>> +
>> +     return remote->entity;
>> +}
>> +
>> +/* updates external subdev(sensor/decoder) which is active */
>> +static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video)
>> +{
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_config *vpfe_cfg;
>> +     struct v4l2_subdev *subdev;
>> +     struct media_pad *remote;
>> +     int i;
>> +
>> +     remote = media_entity_remote_source(&vpfe_dev->vpfe_ccdc.pads[0]);
>> +     if (remote == NULL) {
>> +             pr_err("Invalid media connection to ccdc\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     subdev = media_entity_to_v4l2_subdev(remote->entity);
>> +
>> +     vpfe_cfg = vpfe_dev->pdev->platform_data;
>> +
>> +     for (i = 0; i < vpfe_cfg->num_subdevs; i++) {
>> +             if (!strcmp(vpfe_cfg->sub_devs[i].module_name, subdev->name)) {
>> +                     video->current_ext_subdev = &vpfe_cfg->sub_devs[i];
>> +                     break;
>> +             }
>> +     }
>> +
>> +     /* if user not linked decoder/sensor to ccdc */
>> +     if (i == vpfe_cfg->num_subdevs) {
>> +             pr_err("Invalid media chain connection to ccdc\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* find the v4l2 subdev pointer */
>> +     for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) {
>> +             if (!strcmp(video->current_ext_subdev->module_name,
>> +                     vpfe_dev->sd[i]->name))
>> +                     video->current_ext_subdev->subdev = vpfe_dev->sd[i];
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +/* get the subdev which is connected to the output video node */
>> +static struct v4l2_subdev *
>> +vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad)
>> +{
>> +     struct media_pad *remote;
>> +
>> +     remote = media_entity_remote_source(&video->pad);
>> +
>> +     if (remote == NULL || remote->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
>> +             return NULL;
>> +
>> +     if (pad)
>> +             *pad = remote->index;
>> +
>> +     return media_entity_to_v4l2_subdev(remote->entity);
>> +}
>> +
>> +/* get the format set at ouput pad of the adjacent subdev */
>> +static int
>> +__vpfe_video_get_format(struct vpfe_video_device *video,
>> +                     struct v4l2_format *format)
>> +{
>> +     struct v4l2_subdev_format fmt;
>> +     struct v4l2_subdev *subdev;
>> +     struct media_pad *remote;
>> +     u32 pad;
>> +     int ret;
>> +
>> +     subdev = vpfe_video_remote_subdev(video, &pad);
>> +     if (subdev == NULL)
>> +             return -EINVAL;
>> +
>> +     fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
>> +     remote = media_entity_remote_source(&video->pad);
>> +     fmt.pad = remote->index;
>> +
>> +     ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
>> +     if (ret == -ENOIOCTLCMD)
>> +             return -EINVAL;
>> +
>> +     format->type = video->type;
>> +     /* convert mbus_format to v4l2_format */
>> +     v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
>> +     mbus_to_pix(&fmt.format, &format->fmt.pix);
>> +
>> +     return 0;
>> +}
>> +
>> +/* make a note of pipeline details */
>> +static void vpfe_prepare_pipeline(struct vpfe_video_device *video)
>> +{
>> +     struct media_entity *entity = &video->video_dev.entity;
>> +     struct media_device *mdev = entity->parent;
>> +     struct vpfe_pipeline *pipe = &video->pipe;
>> +     struct vpfe_video_device *far_end = NULL;
>> +     struct media_entity_graph graph;
>> +
>> +     pipe->input_num = 0;
>> +     pipe->output_num = 0;
>> +
>> +     if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
>> +             pipe->inputs[pipe->input_num++] = video;
>> +     else
>> +             pipe->outputs[pipe->output_num++] = video;
>> +
>> +     mutex_lock(&mdev->graph_mutex);
>> +     media_entity_graph_walk_start(&graph, entity);
>> +
>> +     while ((entity = media_entity_graph_walk_next(&graph))) {
>> +             if (entity == &video->video_dev.entity)
>> +                     continue;
>> +
>> +             if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
>> +                     continue;
>> +
>> +             far_end = to_vpfe_video(media_entity_to_video_device(entity));
>> +
>> +             if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
>> +                     pipe->inputs[pipe->input_num++] = far_end;
>> +             else
>> +                     pipe->outputs[pipe->output_num++] = far_end;
>> +     }
>> +
>> +     mutex_unlock(&mdev->graph_mutex);
>> +}
>> +
>> +/* update pipe state selected by user */
>> +static int vpfe_update_pipe_state(struct vpfe_video_device *video)
>> +{
>> +     struct vpfe_pipeline *pipe = &video->pipe;
>> +     int ret;
>> +
>> +     vpfe_prepare_pipeline(video);
>> +
>> +     /* Find out if there is any input video
>> +       if yes, it is single shot.
>> +     */
>> +     if (pipe->input_num == 0) {
>> +             pipe->state = VPFE_PIPELINE_STREAM_CONTINUOUS;
>> +             ret = vpfe_update_current_ext_subdev(video);
>> +             if (ret) {
>> +                     pr_err("Invalid external subdev\n");
>> +                     return ret;
>> +             }
>> +     } else {
>> +             pipe->state = VPFE_PIPELINE_STREAM_SINGLESHOT;
>> +     }
>> +
>> +     video->initialized = 1;
>> +     video->skip_frame_count = 1;
>> +     video->skip_frame_count_init = 1;
>> +
>> +     return 0;
>> +}
>> +
>> +/* checks wether pipeline is ready for enabling */
>> +int is_pipe_ready(struct vpfe_pipeline *pipe)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; i < pipe->input_num; i++)
>> +             if (!pipe->inputs[i]->started ||
>> +                     pipe->inputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED)
>> +                     return 0;
>> +
>> +     for (i = 0; i < pipe->output_num; i++)
>> +             if (!pipe->outputs[i]->started ||
>> +                     pipe->outputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED)
>> +                     return 0;
>> +
>> +     return 1;
>> +}
>> +
>> +/**
>> + * Validate a pipeline by checking both ends of all links for format
>> + * discrepancies.
>> + *
>> + * Return 0 if all formats match, or -EPIPE if at least one link is found with
>> + * different formats on its two ends.
>> + */
>> +static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
>> +{
>> +     struct v4l2_subdev_format fmt_source;
>> +     struct v4l2_subdev_format fmt_sink;
>> +     struct v4l2_subdev *subdev;
>> +     struct media_pad *pad;
>> +     int ret;
>> +
>> +     /* Should not matter if it is output[0] or 1 as
>> +        the general ideas is to traverse backwards and
>> +        the fact that the out video node always has the
>> +        format of the connected pad.
>> +     */
>> +     subdev = vpfe_video_remote_subdev(pipe->outputs[0], NULL);
>> +     if (subdev == NULL)
>> +             return -EPIPE;
>> +
>> +     while (1) {
>> +             /* Retrieve the sink format */
>> +             pad = &subdev->entity.pads[0];
>> +             if (!(pad->flags & MEDIA_PAD_FL_SINK))
>> +                     break;
>> +
>> +             fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
>> +             fmt_sink.pad = pad->index;
>> +             ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL,
>> +                                    &fmt_sink);
>> +
>> +             if (ret < 0 && ret != -ENOIOCTLCMD)
>> +                     return -EPIPE;
>> +
>> +             /* Retrieve the source format */
>> +             pad = media_entity_remote_source(pad);
>> +             if (pad == NULL ||
>> +                     pad->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
>> +                     break;
>> +
>> +             subdev = media_entity_to_v4l2_subdev(pad->entity);
>> +
>> +             fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
>> +             fmt_source.pad = pad->index;
>> +             ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
>> +             if (ret < 0 && ret != -ENOIOCTLCMD)
>> +                     return -EPIPE;
>> +
>> +             /* Check if the two ends match */
>> +             if (fmt_source.format.code != fmt_sink.format.code ||
>> +                 fmt_source.format.width != fmt_sink.format.width ||
>> +                 fmt_source.format.height != fmt_sink.format.height)
>> +                     return -EPIPE;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +/**
>> + * vpfe_pipeline_enable() - Enable streaming on a pipeline
>> + * @vpfe_dev: vpfe device
>> + * @pipe: vpfe pipeline
>> + *
>> + * Walk the entities chain starting at the pipeline output video node and start
>> + * all modules in the chain in the given mode.
>> + *
>> + * Return 0 if successfull, or the return value of the failed video::s_stream
>> + * operation otherwise.
>> + */
>> +static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
>> +{
>> +     struct media_entity_graph graph;
>> +     struct media_entity *entity;
>> +     struct v4l2_subdev *subdev;
>> +     struct media_device *mdev;
>> +     int ret = 0;
>> +
>> +     if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
>> +             entity = vpfe_get_input_entity(pipe->outputs[0]);
>> +     else
>> +             entity = &pipe->inputs[0]->video_dev.entity;
>> +
>> +     mdev = entity->parent;
>> +
>> +     mutex_lock(&mdev->graph_mutex);
>> +     media_entity_graph_walk_start(&graph, entity);
>> +
>> +     while ((entity = media_entity_graph_walk_next(&graph))) {
>> +
>> +             if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
>> +                     continue;
>> +
>> +             subdev = media_entity_to_v4l2_subdev(entity);
>> +
>> +             ret = v4l2_subdev_call(subdev, video, s_stream, 1);
>> +             if (ret < 0 && ret != -ENOIOCTLCMD)
>> +                     break;
>> +     }
>> +     mutex_unlock(&mdev->graph_mutex);
>> +
>> +     return ret;
>> +}
>> +
>> +/**
>> + * vpfe_pipeline_disable() - Disable streaming on a pipeline
>> + * @vpfe_dev: vpfe device
>> + * @pipe: VPFE pipeline
>> + *
>> + * Walk the entities chain starting at the pipeline output video node and stop
>> + * all modules in the chain.
>> + *
>> + * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
>> + * can't be stopped.
>> + */
>> +static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
>> +{
>> +     struct media_entity_graph graph;
>> +     struct media_entity *entity;
>> +     struct v4l2_subdev *subdev;
>> +     struct media_device *mdev;
>> +     int ret = 0;
>> +
>> +     if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
>> +             entity = vpfe_get_input_entity(pipe->outputs[0]);
>> +     else
>> +             entity = &pipe->inputs[0]->video_dev.entity;
>> +
>> +     mdev = entity->parent;
>> +
>> +     mutex_lock(&mdev->graph_mutex);
>> +     media_entity_graph_walk_start(&graph, entity);
>> +
>> +     while ((entity = media_entity_graph_walk_next(&graph))) {
>> +
>> +             if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
>> +                     continue;
>> +
>> +             subdev = media_entity_to_v4l2_subdev(entity);
>> +
>> +             ret = v4l2_subdev_call(subdev, video, s_stream, 0);
>> +             if (ret < 0 && ret != -ENOIOCTLCMD)
>> +                     break;
>> +     }
>> +
>> +     mutex_unlock(&mdev->graph_mutex);
>> +
>> +     return (ret == 0) ? ret : -ETIMEDOUT ;
>> +}
>> +
>> +/**
>> + * vpfe_pipeline_set_stream() - Enable/disable streaming on a pipeline
>> + * @vpfe_dev: VPFE device
>> + * @pipe: VPFE pipeline
>> + * @state: Stream state (stopped or active)
>> + *
>> + * Set the pipeline to the given stream state.
>> + *
>> + * Return 0 if successfull, or the return value of the failed video::s_stream
>> + * operation otherwise.
>> + */
>> +static int vpfe_pipeline_set_stream(struct vpfe_pipeline *pipe,
>> +                         enum vpfe_pipeline_stream_state state)
>> +{
>> +     if (state == VPFE_PIPELINE_STREAM_STOPPED)
>> +             return vpfe_pipeline_disable(pipe);
>> +
>> +     return vpfe_pipeline_enable(pipe);
>> +}
>> +
>> +static int all_videos_stopped(struct vpfe_video_device *video)
>> +{
>> +     struct vpfe_pipeline *pipe = &video->pipe;
>> +     int i;
>> +
>> +     for (i = 0; i < pipe->input_num; i++)
>> +             if (pipe->inputs[i]->started)
>> +                     return 0;
>> +
>> +     for (i = 0; i < pipe->output_num; i++)
>> +             if (pipe->outputs[i]->started)
>> +                     return 0;
>> +
>> +     return 1;
>> +}
>> +
>> +/*
>> + * vpfe_open() - open video device
>> + * @file: file pointer
>> + *
>> + * initialize media pipeline state, allocate memory for file hadle
>> + *
>> + * Return 0 if successfull, or the return -ENODEV otherwise.
>> + */
>> +static int vpfe_open(struct file *file)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_fh *fh;
>> +
>> +     /* Allocate memory for the file handle object */
>> +     fh = kzalloc(sizeof(struct vpfe_fh), GFP_KERNEL);
>
> Please use struct v4l2_fh: it gives you the event API and priority handling
> for free.
>
Ok.

>> +
>> +     if (fh == NULL)
>> +             return -ENOMEM;
>> +     /* store pointer to fh in private_data member of file */
>> +     file->private_data = fh;
>> +     fh->video = video;
>> +     mutex_lock(&video->lock);
>> +     /* If decoder is not initialized. initialize it */
>> +     if (!video->initialized && vpfe_update_pipe_state(video)) {
>> +             mutex_unlock(&video->lock);
>> +             return -ENODEV;
>> +     }
>> +     /* Increment device usrs counter */
>> +     video->usrs++;
>> +     /* Set io_allowed member to false */
>> +     fh->io_allowed = 0;
>> +     /* Initialize priority of this instance to default priority */
>> +     fh->prio = V4L2_PRIORITY_UNSET;
>> +     v4l2_prio_open(&video->prio, &fh->prio);
>> +     mutex_unlock(&video->lock);
>> +
>> +     return 0;
>> +}
>> +
>> +/* get the next buffer available from dma queue */
>> +unsigned long vpfe_get_next_buffer(struct vpfe_video_device *video)
>> +{
>> +     /* mark next buffer as active */
>> +     video->next_frm = list_entry(video->dma_queue.next,
>> +                                     struct videobuf_buffer, queue);
>> +
>> +     /* in single shot mode both curr_frm
>> +        and next_frm point to same buffer */
>> +     video->cur_frm = video->next_frm;
>> +     list_del(&video->next_frm->queue);
>> +     video->next_frm->state = VIDEOBUF_ACTIVE;
>> +
>> +     return videobuf_to_dma_contig(video->next_frm);
>> +}
>> +
>> +/* schedule the next buffer which is available on dma queue */
>> +void vpfe_schedule_next_buffer(struct vpfe_video_device *video)
>> +{
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     unsigned long addr;
>> +
>> +     if (list_empty(&video->dma_queue))
>> +             return;
>> +
>> +     video->next_frm = list_entry(video->dma_queue.next,
>> +                                     struct videobuf_buffer, queue);
>> +
>> +     if (VPFE_PIPELINE_STREAM_SINGLESHOT == video->pipe.state)
>> +             video->cur_frm = video->next_frm;
>> +
>> +     list_del(&video->next_frm->queue);
>> +     video->next_frm->state = VIDEOBUF_ACTIVE;
>> +     addr = videobuf_to_dma_contig(video->next_frm);
>> +
>> +     video->ops->queue(vpfe_dev, addr);
>> +
>> +     video->state = VPFE_VIDEO_BUFFER_QUEUED;
>> +}
>> +
>> +/* schedule the buffer for capturing bottom field */
>> +void vpfe_schedule_bottom_field(struct vpfe_video_device *video)
>> +{
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     unsigned long addr;
>> +
>> +     addr = videobuf_to_dma_contig(video->cur_frm);
>
> Perhaps it is a good idea to upgrade to vb2?
>
> I'm inclined to make it a requirement for new drivers.
>
Done ported vb2.

>> +     addr += video->field_off;
>> +
>> +     video->ops->queue(vpfe_dev, addr);
>> +}
>> +
>> +/* make buffer available for dequeue */
>> +void vpfe_process_buffer_complete(struct vpfe_video_device *video)
>> +{
>> +     struct vpfe_pipeline *pipe = &video->pipe;
>> +     struct timespec timespec;
>> +     s64 nsec;
>> +
>> +     ktime_get_ts(&timespec);
>> +     nsec = timespec_to_ns(&timespec);
>> +
>> +     video->cur_frm->ts = ns_to_timeval(nsec);
>> +     video->cur_frm->state = VIDEOBUF_DONE;
>> +     video->cur_frm->size = video->fmt.fmt.pix.sizeimage;
>> +     wake_up_interruptible(&video->cur_frm->done);
>> +     if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
>> +             video->cur_frm = video->next_frm;
>> +}
>> +
>> +/* vpfe_stop_capture() - stop streaming */
>> +static void vpfe_stop_capture(struct vpfe_video_device *video)
>> +{
>> +     struct vpfe_pipeline *pipe = &video->pipe;
>> +
>> +     video->started = 0;
>> +
>> +     if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
>> +             return;
>> +
>> +     if (all_videos_stopped(video))
>> +             vpfe_pipeline_set_stream(pipe,
>> +                                      VPFE_PIPELINE_STREAM_STOPPED);
>> +}
>> +
>> +/*
>> + * vpfe_release() - release video device
>> + * @file: file pointer
>> + *
>> + * deletes buffer queue, frees the buffers and the vpfe file handle
>> + *
>> + * Return 0
>> + */
>> +static int vpfe_release(struct file *file)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_fh *fh = file->private_data;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n");
>> +
>> +     /* Get the device lock */
>> +     mutex_lock(&video->lock);
>> +     /* if this instance is doing IO */
>> +     if (fh->io_allowed) {
>> +             if (video->started) {
>> +                     vpfe_stop_capture(video);
>> +                     /* mark pipe state as stopped in vpfe_release(),
>> +                        as app might call streamon() after streamoff()
>> +                        in which case driver has to start streaming.
>> +                     */
>> +                     video->pipe.state = VPFE_PIPELINE_STREAM_STOPPED;
>> +                     videobuf_streamoff(&video->buffer_queue);
>> +             }
>> +             video->io_usrs = 0;
>> +     }
>> +
>> +     /* Decrement device usrs counter */
>> +     video->usrs--;
>> +     /* Close the priority */
>> +     v4l2_prio_close(&video->prio, fh->prio);
>> +
>> +     /* If this is the last file handle */
>> +     if (!video->usrs)
>> +             video->initialized = 0;
>> +
>> +     mutex_unlock(&video->lock);
>> +     file->private_data = NULL;
>> +     /* Free memory allocated to file handle object */
>> +     kzfree(fh);
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * vpfe_mmap() - It is used to map kernel space buffers
>> + * into user spaces
>> + */
>> +static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n");
>> +
>> +     return videobuf_mmap_mapper(&video->buffer_queue, vma);
>> +}
>> +
>> +/*
>> + * vpfe_poll() - It is used for select/poll system call
>> + */
>> +static unsigned int vpfe_poll(struct file *file, poll_table *wait)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n");
>> +
>> +     if (video->started)
>> +             return videobuf_poll_stream(file,
>> +                                         &video->buffer_queue, wait);
>> +
>> +     return 0;
>> +}
>> +
>> +/* vpfe capture driver file operations */
>> +static const struct v4l2_file_operations vpfe_fops = {
>> +     .owner = THIS_MODULE,
>> +     .open = vpfe_open,
>> +     .release = vpfe_release,
>> +     .unlocked_ioctl = video_ioctl2,
>> +     .mmap = vpfe_mmap,
>> +     .poll = vpfe_poll
>> +};
>> +
>> +/*
>> + * vpfe_querycap() - query capabilities of video device
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @cap: pointer to v4l2_capability structure
>> + *
>> + * fills v4l2 capabilities structure
>> + *
>> + * Return 0
>> + */
>> +static int vpfe_querycap(struct file *file, void  *priv,
>> +                            struct v4l2_capability *cap)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
>> +
>> +     if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
>> +             cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
>> +     else
>> +             cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
>
> Please set cap->device_caps as well (see the spec for this new functionality).
>
Ok.

>> +
>> +     cap->version = VPFE_CAPTURE_VERSION_CODE;
>> +     strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
>> +     strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
>> +     strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * vpfe_g_fmt() - get the format which is active on video device
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @fmt: pointer to v4l2_format structure
>> + *
>> + * fills v4l2 format structure with active format
>> + *
>> + * Return 0
>> + */
>> +static int vpfe_g_fmt(struct file *file, void *priv,
>> +                             struct v4l2_format *fmt)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt\n");
>> +     /* Fill in the information about format */
>> +     *fmt = video->fmt;
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * vpfe_enum_fmt() - enum formats supported on media chain
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @fmt: pointer to v4l2_fmtdesc structure
>> + *
>> + * fills v4l2_fmtdesc structure with output format set on adjacent subdev,
>> + * only one format is enumearted as subdevs are already configured
>> + *
>> + * Return 0 if successfull, error code otherwise
>> + */
>> +static int vpfe_enum_fmt(struct file *file, void  *priv,
>> +                                struct v4l2_fmtdesc *fmt)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct v4l2_subdev_format sd_fmt;
>> +     struct v4l2_mbus_framefmt mbus;
>> +     struct v4l2_subdev *subdev;
>> +     struct v4l2_format format;
>> +     struct media_pad *remote;
>> +     int ret;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt\n");
>> +
>> +     /* since already subdev pad format is set,
>> +     only one pixel format is available */
>> +     if (fmt->index > 0) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Invalid index\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* get the remote pad */
>> +     remote = media_entity_remote_source(&video->pad);
>> +     if (remote == NULL) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev,
>> +                      "invalid remote pad for video node\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* get the remote subdev */
>> +     subdev = vpfe_video_remote_subdev(video, NULL);
>> +     if (subdev == NULL) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev,
>> +                      "invalid remote subdev for video node\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     sd_fmt.pad = remote->index;
>> +     sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
>> +     /* get output format of remote subdev */
>> +     ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &sd_fmt);
>> +     if (ret) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev,
>> +                      "invalid remote subdev for video node\n");
>> +             return ret;
>> +     }
>> +     /* convert to pix format */
>> +     mbus.code = sd_fmt.format.code;
>> +     mbus_to_pix(&mbus, &format.fmt.pix);
>> +
>> +     /* copy the result */
>> +     fmt->pixelformat = format.fmt.pix.pixelformat;
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * vpfe_s_fmt() - set the format on video device
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @fmt: pointer to v4l2_format structure
>> + *
>> + * validate and set the format on video device
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_s_fmt(struct file *file, void *priv,
>> +                             struct v4l2_format *fmt)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct v4l2_format format;
>> +     int ret;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt\n");
>> +
>> +     /* If streaming is started, return error */
>> +     if (video->started) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n");
>> +             return -EBUSY;
>> +     }
>> +
>> +     /* get adjacent subdev's output pad format */
>> +     ret = __vpfe_video_get_format(video, &format);
>> +     if (ret)
>> +             return ret;
>> +
>> +     *fmt = format;
>> +
>> +     video->fmt = *fmt;
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * vpfe_try_fmt() - try the format on video device
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @fmt: pointer to v4l2_format structure
>> + *
>> + * validate the format, update with correct format
>> + * based on output format set on adjacent subdev
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_try_fmt(struct file *file, void *priv,
>> +                               struct v4l2_format *fmt)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct v4l2_format format;
>> +     int ret;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt\n");
>> +
>> +     /* get adjacent subdev's output pad format */
>> +     ret = __vpfe_video_get_format(video, &format);
>> +     if (ret)
>> +             return ret;
>> +
>> +     *fmt = format;
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * vpfe_enum_input() - enum inputs supported on media chain
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @fmt: pointer to v4l2_fmtdesc structure
>> + *
>> + * fills v4l2_input structure with input available on media chain,
>> + * only one input is enumearted as media chain is setup by this time
>> + *
>> + * Return 0 if successfull, -EINVAL is media chain is invalid
>> + */
>> +static int vpfe_enum_input(struct file *file, void *priv,
>> +                              struct v4l2_input *inp)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_ext_subdev_info *sdinfo = video->current_ext_subdev;
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
>> +
>> +     /* enumerate from the subdev user has choosen through mc */
>> +     if (inp->index < sdinfo->num_inputs) {
>> +             memcpy(inp, &sdinfo->inputs[inp->index],
>> +                    sizeof(struct v4l2_input));
>
> This makes the same mistake that the vpif driver have: the assumption that
> for each input there is a corresponding subdev. I'm working on a patch for
> the vpif_capture/display drivers to fix that. I hope to post that today or
> next week.
>
Ok.

>> +             return 0;
>> +     }
>> +
>> +     return -EINVAL;
>> +}
>> +
>> +/*
>> + * vpfe_g_input() - get index of the input which is active
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @index: pointer to unsigned int
>> + *
>> + * set index with input index which is active
>> + *
>> + * Return 0
>> + */
>> +static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n");
>> +
>> +     *index = video->current_input;
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * vpfe_s_input() - set input which is pointed by input index
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @index: pointer to unsigned int
>> + *
>> + * set input on external subdev
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct ccdc_hw_device *ccdc_dev = vpfe_dev->vpfe_ccdc.ccdc_dev;
>> +     struct imp_hw_interface *imp_hw_if = vpfe_dev->vpfe_previewer.imp_hw_if;
>> +     struct vpfe_ext_subdev_info *sdinfo;
>> +     struct vpfe_route *route;
>> +     struct v4l2_input *inps;
>> +     u32 output;
>> +     u32 input;
>> +     int ret;
>> +     int i;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n");
>> +
>> +     ret = mutex_lock_interruptible(&video->lock);
>> +     if (ret)
>> +             return ret;
>> +
>> +     /*
>> +      * If streaming is started return device busy
>> +      * error
>> +      */
>> +     if (video->started) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n");
>> +             ret = -EBUSY;
>> +             goto unlock_out;
>> +     }
>> +
>> +     sdinfo = video->current_ext_subdev;
>> +
>> +     if (!sdinfo->registered) {
>> +             ret = -EINVAL;
>> +             goto unlock_out;
>> +     }
>> +
>> +     if (vpfe_dev->cfg->setup_input &&
>> +             vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) {
>> +             ret = -EFAULT;
>> +             v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
>> +                       "couldn't setup input for %s\n",
>> +                       sdinfo->module_name);
>> +             goto unlock_out;
>> +     }
>> +
>> +     route = &sdinfo->routes[index];
>> +     if (route && sdinfo->can_route) {
>> +             input = route->input;
>> +             output = route->output;
>> +             ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
>> +                                              sdinfo->grp_id, video,
>> +                                              s_routing, input, output, 0);
>> +
>> +             if (ret) {
>> +                     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
>> +                             "s_input:error in setting input in decoder\n");
>> +                     ret = -EINVAL;
>> +                     goto unlock_out;
>> +             }
>> +     }
>> +
>> +     /* set standards set by subdev in video device */
>> +     for (i = 0; i < sdinfo->num_inputs; i++) {
>> +             inps = &sdinfo->inputs[i];
>> +             video->video_dev.tvnorms |= inps->std;
>> +     }
>> +
>> +     /* set the bus/interface parameter for the sub device in ccdc */
>> +     ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
>> +     if (ret)
>> +             goto unlock_out;
>> +
>> +     /* update the if parameters to imp hw interface */
>> +     if (imp_hw_if && imp_hw_if->set_hw_if_param)
>> +             ret = imp_hw_if->set_hw_if_param(vpfe_dev->ipipe,
>> +                                              &sdinfo->ccdc_if_params);
>> +     if (ret)
>> +             goto unlock_out;
>> +
>> +     video->current_input = index;
>> +
>> +unlock_out:
>> +     mutex_unlock(&video->lock);
>> +     return ret;
>> +}
>> +
>> +/*
>> + * vpfe_querystd() - query std which is being input on external subdev
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @std_id: pointer to v4l2_std_id structure
>> + *
>> + * call external subdev through v4l2_device_call_until_err to
>> + * get the std that is being active.
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_ext_subdev_info *sdinfo;
>> +     int ret;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n");
>> +
>> +     ret = mutex_lock_interruptible(&video->lock);
>> +     sdinfo = video->current_ext_subdev;
>> +     if (ret)
>> +             return ret;
>> +
>> +     /* Call querystd function of decoder device */
>> +     ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
>> +                                      video, querystd, std_id);
>> +     mutex_unlock(&video->lock);
>> +
>> +     return ret;
>> +}
>> +
>> +/*
>> + * vpfe_s_std() - set std on external subdev
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @std_id: pointer to v4l2_std_id structure
>> + *
>> + * set std pointed by std_id on external subdev by calling it using
>> + * v4l2_device_call_until_err
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_ext_subdev_info *sdinfo;
>> +     int ret;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n");
>> +
>> +     /* Call decoder driver function to set the standard */
>> +     ret = mutex_lock_interruptible(&video->lock);
>> +     if (ret)
>> +             return ret;
>> +
>> +     sdinfo = video->current_ext_subdev;
>> +     /* If streaming is started, return device busy error */
>> +     if (video->started) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n");
>> +             ret = -EBUSY;
>> +             goto unlock_out;
>> +     }
>> +
>> +     ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
>> +                                      core, s_std, *std_id);
>> +     if (ret < 0) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
>> +             goto unlock_out;
>> +     }
>> +
>> +unlock_out:
>> +     mutex_unlock(&video->lock);
>> +     return ret;
>> +}
>> +
>> +/*
>> + * vpfe_enum_preset() - enumerate dv_preset which are supported by
>> + * to external subdev
>> + *
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @preset: pointer to v4l2_dv_enum_preset structure
>> + *
>> + * enum dv_preset's which are supported by external subdev through
>> + * v4l2_subdev_call
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_enum_preset(struct file *file, void *fh,
>> +                         struct v4l2_dv_enum_preset *preset)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_preset\n");
>> +
>> +     return v4l2_subdev_call(subdev, video, enum_dv_presets, preset);
>> +}
>> +
>> +/*
>> + * vpfe_query_preset() - query the dv_preset which is being input
>> + * to external subdev
>> + *
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @preset: pointer to v4l2_preset structure
>> + *
>> + * get dv_preset which is being input on external subdev through
>> + * v4l2_subdev_call
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_query_preset(struct file *file, void *fh,
>> +                          struct v4l2_dv_preset *preset)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_query_preset\n");
>> +
>> +     return v4l2_subdev_call(subdev, video, query_dv_preset, preset);
>> +}
>> +
>> +/*
>> + * vpfe_s_preset() - set dv_preset on external subdev
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @preset: pointer to v4l2_preset structure
>> + *
>> + * set dv_preset pointed by preset on external subdev through
>> + * v4l2_device_call_until_err, this configures amplifier also
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_s_preset(struct file *file, void *fh,
>> +                      struct v4l2_dv_preset *preset)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_preset\n");
>> +
>> +     return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
>> +                                       video->current_ext_subdev->grp_id,
>> +                                       video, s_dv_preset, preset);
>> +}
>> +
>> +/*
>> + * vpfe_g_preset() - get dv_preset which is set on external subdev
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @preset: pointer to v4l2_preset structure
>> + *
>> + * get dv_preset which is set on external subdev through
>> + * v4l2_subdev_call
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_g_preset(struct file *file, void *fh,
>> +                      struct v4l2_dv_preset *preset)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_preset\n");
>> +
>> +     return v4l2_subdev_call(subdev, video, query_dv_preset, preset);
>> +}
>
> The preset API is deprecated and replaced by the DV Timings API. New drivers
> should implement that API instead.
>
>> +
>> +/*
>> + *  Videobuf operations
>> + */
>> +static int vpfe_videobuf_setup(struct videobuf_queue *vq,
>> +                             unsigned int *count,
>> +                             unsigned int *size)
>> +{
>> +     struct vpfe_fh *fh = vq->priv_data;
>> +     struct vpfe_video_device *video = fh->video;
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_pipeline *pipe = &video->pipe;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
>> +
>> +     *size = video->fmt.fmt.pix.sizeimage;
>> +
>> +     if (vpfe_dev->video_limit) {
>> +             while (*size * *count > vpfe_dev->video_limit)
>> +                     (*count)--;
>> +     }
>> +
>> +     if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) {
>> +             if (*count < CONT_MIN_NUM_BUFFERS)
>> +                     *count = CONT_MIN_NUM_BUFFERS;
>> +     }
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
>> +             "count=%d, size=%d\n", *count, *size);
>> +
>> +     return 0;
>> +}
>> +
>> +static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
>> +                             struct videobuf_buffer *vb,
>> +                             enum v4l2_field field)
>> +{
>> +     struct vpfe_fh *fh = vq->priv_data;
>> +     struct vpfe_video_device *video = fh->video;
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     unsigned long addr;
>> +     int ret;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_prepare\n");
>> +
>> +     if (VIDEOBUF_NEEDS_INIT != vb->state)
>> +             return 0;
>> +
>> +     /* Initialize buffer */
>> +     vb->width = video->fmt.fmt.pix.width;
>> +     vb->height = video->fmt.fmt.pix.height;
>> +     vb->size = video->fmt.fmt.pix.sizeimage;
>> +     vb->field = field;
>> +
>> +     ret = videobuf_iolock(vq, vb, NULL);
>> +     if (ret < 0)
>> +             return ret;
>> +
>> +     addr = videobuf_to_dma_contig(vb);
>> +     /* Make sure user addresses are aligned to 32 bytes */
>> +     if (!ALIGN(addr, 32))
>> +             return -EINVAL;
>> +
>> +     vb->state = VIDEOBUF_PREPARED;
>> +
>> +     return 0;
>> +}
>> +
>> +static void vpfe_videobuf_queue(struct videobuf_queue *vq,
>> +                             struct videobuf_buffer *vb)
>> +{
>> +     /* Get the file handle object and device object */
>> +     struct vpfe_fh *fh = vq->priv_data;
>> +     struct vpfe_video_device *video = fh->video;
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_pipeline *pipe = &video->pipe;
>> +     unsigned long flags;
>> +     unsigned long empty;
>> +     unsigned long addr;
>> +
>> +     spin_lock_irqsave(&video->dma_queue_lock, flags);
>> +     empty = list_empty(&video->dma_queue);
>> +
>> +     /* add the buffer to the DMA queue */
>> +     list_add_tail(&vb->queue, &video->dma_queue);
>> +     spin_unlock_irqrestore(&video->dma_queue_lock, flags);
>> +
>> +     /* Change state of the buffer */
>> +     vb->state = VIDEOBUF_QUEUED;
>> +
>> +     /* this case happens in case of single shot */
>> +     if (empty && video->started && pipe->state ==
>> +             VPFE_PIPELINE_STREAM_SINGLESHOT &&
>> +             video->state == VPFE_VIDEO_BUFFER_NOT_QUEUED) {
>> +             spin_lock(&video->dma_queue_lock);
>> +             addr = vpfe_get_next_buffer(video);
>> +             video->ops->queue(vpfe_dev, addr);
>> +
>> +             video->state = VPFE_VIDEO_BUFFER_QUEUED;
>> +             spin_unlock(&video->dma_queue_lock);
>> +
>> +             /* enable h/w each time in single shot */
>> +             if (is_pipe_ready(pipe))
>> +                     vpfe_pipeline_set_stream(pipe,
>> +                                     VPFE_PIPELINE_STREAM_SINGLESHOT);
>> +     }
>> +}
>> +
>> +static void vpfe_videobuf_release(struct videobuf_queue *vq,
>> +                               struct videobuf_buffer *vb)
>> +{
>> +     struct vpfe_fh *fh = vq->priv_data;
>> +     struct vpfe_video_device *video = fh->video;
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n");
>> +
>> +     if (video->memory == V4L2_MEMORY_MMAP)
>> +             videobuf_dma_contig_free(vq, vb);
>> +     vb->state = VIDEOBUF_NEEDS_INIT;
>> +}
>> +
>> +static struct videobuf_queue_ops vpfe_videobuf_qops = {
>> +     .buf_setup      = vpfe_videobuf_setup,
>> +     .buf_prepare    = vpfe_videobuf_prepare,
>> +     .buf_queue      = vpfe_videobuf_queue,
>> +     .buf_release    = vpfe_videobuf_release,
>> +};
>
> Again, I highly recommend moving to the videobuf2 framework. If nothing else,
> the vb2 framework will get support for DMABUF, allowing zero-copy pipelining.
>
>> +
>> +/*
>> + * vpfe_reqbufs() - supported REQBUF only once opening
>> + * the device.
>> + */
>> +static int vpfe_reqbufs(struct file *file, void *priv,
>> +                     struct v4l2_requestbuffers *req_buf)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_fh *fh = file->private_data;
>> +     int ret;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n");
>> +
>> +     if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type &&
>> +             V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     ret = mutex_lock_interruptible(&video->lock);
>> +     if (ret)
>> +             return ret;
>> +
>> +     if (video->io_usrs != 0) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n");
>> +             ret = -EBUSY;
>> +             goto unlock_out;
>> +     }
>> +
>> +     video->memory = req_buf->memory;
>> +     videobuf_queue_dma_contig_init(&video->buffer_queue,
>> +                             &vpfe_videobuf_qops, vpfe_dev->pdev,
>> +                             &video->irqlock, req_buf->type,
>> +                             video->fmt.fmt.pix.field,
>> +                             sizeof(struct videobuf_buffer),
>> +                             fh, NULL);
>> +
>> +     fh->io_allowed = 1;
>> +     video->io_usrs = 1;
>> +     INIT_LIST_HEAD(&video->dma_queue);
>> +     ret = videobuf_reqbufs(&video->buffer_queue, req_buf);
>> +
>> +unlock_out:
>> +     mutex_unlock(&video->lock);
>> +     return ret;
>> +}
>> +
>> +/*
>> + * vpfe_querybuf() - query buffers for exchange
>> + */
>> +static int vpfe_querybuf(struct file *file, void *priv,
>> +                      struct v4l2_buffer *buf)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n");
>> +
>> +     if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type &&
>> +             V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
>> +             return  -EINVAL;
>> +     }
>> +
>> +     if (video->memory != V4L2_MEMORY_MMAP) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* Call videobuf_querybuf to get information */
>> +     return videobuf_querybuf(&video->buffer_queue, buf);
>> +}
>> +
>> +/*
>> + * vpfe_qbuf() - queue buffers for capture or processing
>> + */
>> +static int vpfe_qbuf(struct file *file, void *priv,
>> +                  struct v4l2_buffer *p)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_fh *fh = file->private_data;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n");
>> +
>> +     if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type &&
>> +             V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     /*
>> +      * If this file handle is not allowed to do IO,
>> +      * return error
>> +      */
>> +     if (!fh->io_allowed) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
>> +             return -EACCES;
>> +     }
>> +
>> +     return videobuf_qbuf(&video->buffer_queue, p);
>> +}
>> +
>> +/*
>> + * vpfe_dqbuf() - deque buffer which is done with processing
>> + */
>> +static int vpfe_dqbuf(struct file *file, void *priv,
>> +                   struct v4l2_buffer *buf)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n");
>> +
>> +     if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type &&
>> +             V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     return videobuf_dqbuf(&video->buffer_queue,
>> +                                   buf, file->f_flags & O_NONBLOCK);
>> +}
>> +
>> +/* vpfe_start_capture() - start streaming on all the subdevs */
>> +static int vpfe_start_capture(struct vpfe_video_device *video)
>> +{
>> +     struct vpfe_pipeline *pipe = &video->pipe;
>> +     int ret = 0;
>> +
>> +     video->started = 1;
>> +
>> +     if (is_pipe_ready(pipe))
>> +             ret = vpfe_pipeline_set_stream(pipe, pipe->state);
>> +
>> +     return ret;
>> +}
>> +
>> +/*
>> + * vpfe_streamon() - get dv_preset which is set on external subdev
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @buf_type: enum v4l2_buf_type
>> + *
>> + * queue buffer onto hardware for capture/processing and
>> + * start all the subdevs which are in media chain
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_streamon(struct file *file, void *priv,
>> +                      enum v4l2_buf_type buf_type)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_pipeline *pipe = &video->pipe;
>> +     struct vpfe_fh *fh = file->private_data;
>> +     struct vpfe_ext_subdev_info *sdinfo;
>> +     unsigned long addr;
>> +     int ret = -EINVAL;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n");
>> +
>> +     if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type &&
>> +             V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
>> +             return ret;
>> +     }
>> +
>> +     /* If file handle is not allowed IO, return error */
>> +     if (!fh->io_allowed) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
>> +             return -EACCES;
>> +     }
>> +     sdinfo = video->current_ext_subdev;
>> +     /* If buffer queue is empty, return error */
>> +     if (list_empty(&video->buffer_queue.stream)) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n");
>> +             return -EIO;
>> +     }
>> +     /* Validate the pipeline */
>> +     if (V4L2_BUF_TYPE_VIDEO_CAPTURE == buf_type) {
>> +             ret = vpfe_video_validate_pipeline(pipe);
>> +             if (ret < 0)
>> +                     return ret;
>> +     }
>> +     /* Call videobuf_streamon to start streaming * in videobuf */
>> +     ret = videobuf_streamon(&video->buffer_queue);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = mutex_lock_interruptible(&video->lock);
>> +     if (ret)
>> +             goto streamoff;
>> +
>> +     /* Get the next frame from the buffer queue */
>> +     video->next_frm = list_entry(video->dma_queue.next,
>> +                                     struct videobuf_buffer, queue);
>> +     video->cur_frm = video->next_frm;
>> +     /* Remove buffer from the buffer queue */
>> +     list_del(&video->cur_frm->queue);
>> +     /* Mark state of the current frame to active */
>> +     video->cur_frm->state = VIDEOBUF_ACTIVE;
>> +     /* Initialize field_id and started member */
>> +     video->field_id = 0;
>> +     addr = videobuf_to_dma_contig(video->cur_frm);
>> +     video->ops->queue(vpfe_dev, addr);
>> +     video->state = VPFE_VIDEO_BUFFER_QUEUED;
>> +     ret = vpfe_start_capture(video);
>> +     if (ret)
>> +             goto unlock_out;
>> +
>> +     mutex_unlock(&video->lock);
>> +     return ret;
>> +unlock_out:
>> +     mutex_unlock(&video->lock);
>> +streamoff:
>> +     ret = videobuf_streamoff(&video->buffer_queue);
>> +     return ret;
>> +}
>> +
>> +/*
>> + * vpfe_streamoff() - get dv_preset which is set on external subdev
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @buf_type: enum v4l2_buf_type
>> + *
>> + * stop all the subdevs which are in media chain
>> + *
>> + * Return 0 on success, error code otherwise
>> + */
>> +static int vpfe_streamoff(struct file *file, void *priv,
>> +                       enum v4l2_buf_type buf_type)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_fh *fh = file->private_data;
>> +     int ret = 0;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n");
>> +
>> +     if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
>> +             buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
>> +             v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "Invalid buf type\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* If io is allowed for this file handle, return error */
>> +     if (!fh->io_allowed) {
>> +             v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "fh->io_allowed\n");
>> +             return -EACCES;
>> +     }
>> +
>> +     /* If streaming is not started, return error */
>> +     if (!video->started) {
>> +             v4l2_err(&vpfe_dev->v4l2_dev, "device is not started\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     ret = mutex_lock_interruptible(&video->lock);
>> +     if (ret)
>> +             return ret;
>> +
>> +     vpfe_stop_capture(video);
>> +
>> +     ret = videobuf_streamoff(&video->buffer_queue);
>> +     mutex_unlock(&video->lock);
>> +
>> +     return ret;
>> +}
>> +
>> +/*
>> + * vpfe_queryctrl() - query for v4l2 controls which is set on external subdev
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @ctrl: pointer to v4l2_control structure
>> + *
>> + * get the v4l2 controls active on external subdev through
>> + * v4l2_device_call_until_err
>> + *
>> + * Return return value returned by v4l2_device_call_until_err
>> + */
>> +static int vpfe_queryctrl(struct file *file, void *priv,
>> +                             struct v4l2_queryctrl *qc)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_ext_subdev_info *sub_dev = video->current_ext_subdev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_queryctrl\n");
>> +
>> +     /* pass it to sub device */
>> +     return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sub_dev->grp_id,
>> +                                       core, queryctrl, qc);
>> +}
>
> It is compulsory to use the control framework.
>
> Which should be simple enough: make an empty control handler, let the ctrl_handler field
> of struct v4l2_device point to it and then when the subdevs are added the controls of
> each subdev will be added (inherited) as well.
>
Ok.

>> +
>> +/*
>> + * vpfe_g_ctrl() - get the v4l2 controls which is set on external subdev
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @ctrl: pointer to v4l2_control structure
>> + *
>> + * get the v4l2 controls set on external subdev through
>> + * v4l2_device_call_until_err
>> + *
>> + * Return return value returned by v4l2_device_call_until_err
>> + */
>> +static int vpfe_g_ctrl(struct file *file, void *priv,
>> +                     struct v4l2_control *ctrl)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_ext_subdev_info *sub_dev = video->current_ext_subdev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_ctrl\n");
>> +
>> +     return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sub_dev->grp_id,
>> +                                       core, g_ctrl, ctrl);
>> +}
>> +
>> +/*
>> + * vpfe_s_ctrl() - set the v4l2 controls on external subdev
>> + * @file: file pointer
>> + * @priv: void pointer
>> + * @ctrl: pointer to v4l2_control structure
>> + *
>> + * call external subdev through v4l2_device_call_until_err to
>> + * set v4l2 controls
>> + *
>> + * Return return value returned by v4l2_device_call_until_err
>> + */
>> +static int vpfe_s_ctrl(struct file *file, void *priv,
>> +                          struct v4l2_control *ctrl)
>> +{
>> +     struct vpfe_video_device *video = video_drvdata(file);
>> +     struct vpfe_device *vpfe_dev = video->vpfe_dev;
>> +     struct vpfe_ext_subdev_info *sub_dev = video->current_ext_subdev;
>> +
>> +     v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_ctrl\n");
>> +
>> +     return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sub_dev->grp_id,
>> +                                       core, s_ctrl, ctrl);
>> +}
>> +
>> +/* vpfe capture ioctl operations */
>> +static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
>> +     .vidioc_querycap         = vpfe_querycap,
>> +     .vidioc_g_fmt_vid_cap    = vpfe_g_fmt,
>> +     .vidioc_s_fmt_vid_cap    = vpfe_s_fmt,
>> +     .vidioc_try_fmt_vid_cap  = vpfe_try_fmt,
>> +     .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt,
>> +     .vidioc_g_fmt_vid_out    = vpfe_g_fmt,
>> +     .vidioc_s_fmt_vid_out    = vpfe_s_fmt,
>> +     .vidioc_try_fmt_vid_out  = vpfe_try_fmt,
>> +     .vidioc_enum_fmt_vid_out = vpfe_enum_fmt,
>> +     .vidioc_enum_input       = vpfe_enum_input,
>> +     .vidioc_g_input          = vpfe_g_input,
>> +     .vidioc_s_input          = vpfe_s_input,
>> +     .vidioc_querystd         = vpfe_querystd,
>> +     .vidioc_s_std            = vpfe_s_std,
>> +     .vidioc_enum_dv_presets  = vpfe_enum_preset,
>> +     .vidioc_query_dv_preset  = vpfe_query_preset,
>> +     .vidioc_s_dv_preset      = vpfe_s_preset,
>> +     .vidioc_g_dv_preset      = vpfe_g_preset,
>> +     .vidioc_reqbufs          = vpfe_reqbufs,
>> +     .vidioc_querybuf         = vpfe_querybuf,
>> +     .vidioc_qbuf             = vpfe_qbuf,
>> +     .vidioc_dqbuf            = vpfe_dqbuf,
>> +     .vidioc_streamon         = vpfe_streamon,
>> +     .vidioc_streamoff        = vpfe_streamoff,
>> +     .vidioc_queryctrl        = vpfe_queryctrl,
>> +     .vidioc_g_ctrl           = vpfe_g_ctrl,
>> +     .vidioc_s_ctrl           = vpfe_s_ctrl,
>> +};
>> +
>> +/* VPFE video init function */
>> +int vpfe_video_init(struct vpfe_video_device *video, const char *name)
>> +{
>> +     const char *direction;
>> +     int ret;
>> +
>> +     switch (video->type) {
>> +     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
>> +             direction = "output";
>> +             video->pad.flags = MEDIA_PAD_FL_SINK;
>> +             video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>> +             break;
>> +     case V4L2_BUF_TYPE_VIDEO_OUTPUT:
>> +             direction = "input";
>> +             video->pad.flags = MEDIA_PAD_FL_SOURCE;
>> +             video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
>> +             break;
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* Initialize field of video device */
>> +     video->video_dev.release = video_device_release;
>> +     video->video_dev.fops = &vpfe_fops;
>> +     video->video_dev.ioctl_ops = &vpfe_ioctl_ops;
>> +     video->video_dev.minor = -1;
>> +     video->video_dev.tvnorms = 0;
>> +     video->video_dev.current_norm = V4L2_STD_NTSC;
>
> Don't use current_norm. Create a proper vpfe_g_std instead. current_norm is
> being phased out.
>
Ok.

Regards,
--Prabhakar Lad

>> +
>> +     snprintf(video->video_dev.name, sizeof(video->video_dev.name),
>> +              "DAVINCI VIDEO %s %s", name, direction);
>> +
>> +     /* Initialize prio member of device object */
>> +     v4l2_prio_init(&video->prio);
>> +
>> +     spin_lock_init(&video->irqlock);
>> +     spin_lock_init(&video->dma_queue_lock);
>> +     mutex_init(&video->lock);
>> +
>> +     ret = media_entity_init(&video->video_dev.entity,
>> +                             1, &video->pad, 0);
>> +     if (ret < 0)
>> +             return ret;
>> +
>> +     video_set_drvdata(&video->video_dev, video);
>> +
>> +     return 0;
>> +}
>> +
>> +/* vpfe video device register function */
>> +int vpfe_video_register(struct vpfe_video_device *video,
>> +                     struct v4l2_device *vdev)
>> +{
>> +     int ret;
>> +
>> +     video->video_dev.v4l2_dev = vdev;
>> +
>> +     ret = video_register_device(&video->video_dev, VFL_TYPE_GRABBER, -1);
>> +     if (ret < 0)
>> +             pr_err("%s: could not register video device (%d)\n",
>> +                    __func__, ret);
>> +
>> +     return ret;
>> +}
>> +
>> +/* vpfe video device unregister function */
>> +void vpfe_video_unregister(struct vpfe_video_device *video)
>> +{
>> +     if (video_is_registered(&video->video_dev)) {
>> +             media_entity_cleanup(&video->video_dev.entity);
>> +             video_unregister_device(&video->video_dev);
>> +     }
>> +}
>> diff --git a/drivers/media/platform/davinci/vpfe_video.h b/drivers/media/platform/davinci/vpfe_video.h
>> new file mode 100644
>> index 0000000..af68caf
>> --- /dev/null
>> +++ b/drivers/media/platform/davinci/vpfe_video.h
>> @@ -0,0 +1,150 @@
>> +/*
>> + * Copyright (C) 2012 Texas Instruments 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 version 2.
>> + *
>> + * 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
>> + *
>> + * Contributors:
>> + *      Manjunath Hadli <manjunath.hadli@ti.com>
>> + *      Prabhakar Lad <prabhakar.lad@ti.com>
>> + */
>> +
>> +/* All video device related structures will go here */
>> +#ifndef _VPFE_VIDEO_H
>> +#define _VPFE_VIDEO_H
>> +
>> +#include <media/media-entity.h>
>> +#include <media/videobuf-dma-contig.h>
>> +
>> +struct vpfe_device;
>> +
>> +/*
>> + * struct vpfe_video_operations - VPFE video operations
>> + * @queue:   Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
>> + *           if there was no buffer previously queued.
>> + */
>> +struct vpfe_video_operations {
>> +     void(*queue)(struct vpfe_device *vpfe_dev, unsigned long addr);
>> +};
>> +
>> +enum vpfe_pipeline_stream_state {
>> +     VPFE_PIPELINE_STREAM_STOPPED,
>> +     VPFE_PIPELINE_STREAM_CONTINUOUS,
>> +     VPFE_PIPELINE_STREAM_SINGLESHOT
>> +};
>> +
>> +enum vpfe_video_state {
>> +     /* indicates that buffer is not queued */
>> +     VPFE_VIDEO_BUFFER_NOT_QUEUED = 0,
>> +     /* indicates that buffer is queued */
>> +     VPFE_VIDEO_BUFFER_QUEUED = 1,
>> +};
>> +
>> +struct vpfe_pipeline {
>> +     /* media pipeline */
>> +     struct media_pipeline           *pipe;
>> +     /* state of the pipeline, continous,
>> +     single-shot or stopped */
>> +     enum vpfe_pipeline_stream_state state;
>> +     /* number of active input video entities */
>> +     unsigned int                    input_num;
>> +     /* number of active output video entities */
>> +     unsigned int                    output_num;
>> +     /* input video nodes in case of single-shot mode */
>> +     struct vpfe_video_device        *inputs[10];
>> +     /* capturing video nodes */
>> +     struct vpfe_video_device        *outputs[10];
>> +};
>> +
>> +#define to_vpfe_pipeline(__e) \
>> +     container_of((__e)->pipe, struct vpfe_pipeline, pipe)
>> +
>> +#define to_vpfe_video(vdev) \
>> +     container_of(vdev, struct vpfe_video_device, video_dev)
>> +
>> +struct vpfe_video_device {
>> +     /* vpfe device */
>> +     struct vpfe_device                      *vpfe_dev;
>> +     /* video dev */
>> +     struct video_device                     video_dev;
>> +     /* media pad of video entity */
>> +     struct media_pad                        pad;
>> +     /* video operations supported by video device */
>> +     const struct vpfe_video_operations      *ops;
>> +     /* type of the video buffers used by user */
>> +     enum v4l2_buf_type                      type;
>> +     /* Indicates id of the field which is being captured */
>> +     u32                                     field_id;
>> +     /* pipiline for which video device is part of */
>> +     struct vpfe_pipeline                    pipe;
>> +     /* Indicates whether streaming started */
>> +     u8                                      started;
>> +     /* Indicates state of the stream */
>> +     unsigned int                            state;
>> +     /* current input at the sub device */
>> +     int                                     current_input;
>> +     /*
>> +      * This field keeps track of type of buffer exchange mechanism
>> +      * user has selected
>> +      */
>> +     enum v4l2_memory                        memory;
>> +     /* Used to keep track of state of the priority */
>> +     struct v4l2_prio_state                  prio;
>> +     /* number of open instances of the channel */
>> +     u32                                     usrs;
>> +     /* flag to indicate whether decoder is initialized */
>> +     u8                                      initialized;
>> +     /* skip frame count */
>> +     u8                                      skip_frame_count;
>> +     /* skip frame count init value */
>> +     u8                                      skip_frame_count_init;
>> +     /* time per frame for skipping */
>> +     struct v4l2_fract                       timeperframe;
>> +     /* ptr to currently selected sub device */
>> +     struct vpfe_ext_subdev_info             *current_ext_subdev;
>> +     /* Pointer pointing to current v4l2_buffer */
>> +     struct videobuf_buffer                  *cur_frm;
>> +     /* Pointer pointing to next v4l2_buffer */
>> +     struct videobuf_buffer                  *next_frm;
>> +     /* Used to store pixel format */
>> +     struct v4l2_format                      fmt;
>> +     /* Buffer queue used in video-buf */
>> +     struct videobuf_queue                   buffer_queue;
>> +     /* Queue of filled frames */
>> +     struct list_head                        dma_queue;
>> +     /* Used in video-buf */
>> +     spinlock_t                              irqlock;
>> +     /* IRQ lock for DMA queue */
>> +     spinlock_t                              dma_queue_lock;
>> +     /* lock used to access this structure */
>> +     struct mutex                            lock;
>> +     /* number of users performing IO */
>> +     u32                                     io_usrs;
>> +     /*
>> +      * offset where second field starts from the starting of the
>> +      * buffer for field seperated YCbCr formats
>> +      */
>> +     u32                                     field_off;
>> +};
>> +
>> +int is_pipe_ready(struct vpfe_pipeline *pipe);
>> +void vpfe_video_unregister(struct vpfe_video_device *video);
>> +int vpfe_video_register(struct vpfe_video_device *video,
>> +                     struct v4l2_device *vdev);
>> +int vpfe_video_init(struct vpfe_video_device *video, const char *name);
>> +
>> +void vpfe_process_buffer_complete(struct vpfe_video_device *video);
>> +void vpfe_schedule_bottom_field(struct vpfe_video_device *video);
>> +void vpfe_schedule_next_buffer(struct vpfe_video_device *video);
>> +unsigned long vpfe_get_next_buffer(struct vpfe_video_device *video);
>> +#endif
>>
>
> Regards,
>
>         Hans

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 01/14] davinci: vpfe: add dm3xx IPIPEIF hardware support module
  2012-09-19 22:01   ` Laurent Pinchart
@ 2012-09-22  5:08     ` Prabhakar Lad
  0 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-22  5:08 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: davinci-linux-open-source, LMML, LKML, Mauro Carvalho Chehab,
	Manjunath Hadli, Prabhakar Lad

Hi Laurent,

Thanks for the review.

On Thu, Sep 20, 2012 at 3:31 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> Hi Prabhakar,
>
> Thanks for the patch.
>
> On Friday 14 September 2012 18:16:31 Prabhakar Lad wrote:
>> From: Manjunath Hadli <manjunath.hadli@ti.com>
>>
>> add support for dm3xx IPIPEIF hardware setup. This is the
>> lowest software layer for the dm3x vpfe driver which directly
>> accesses hardware. Add support for features like default
>> pixel correction, dark frame substraction and hardware setup.
>>
>> Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
>> Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
>> ---
>>  drivers/media/platform/davinci/dm3xx_ipipeif.c |  318 +++++++++++++++++++++
>>  drivers/media/platform/davinci/dm3xx_ipipeif.h |  262 +++++++++++++++++++
>>  include/linux/dm3xx_ipipeif.h                  |   62 +++++
>
>
>>  3 files changed, 642 insertions(+), 0 deletions(-)
>>  create mode 100644 drivers/media/platform/davinci/dm3xx_ipipeif.c
>>  create mode 100644 drivers/media/platform/davinci/dm3xx_ipipeif.h
>>  create mode 100644 include/linux/dm3xx_ipipeif.h
>>
>> diff --git a/drivers/media/platform/davinci/dm3xx_ipipeif.c
>> b/drivers/media/platform/davinci/dm3xx_ipipeif.c new file mode 100644
>> index 0000000..7961a74
>> --- /dev/null
>> +++ b/drivers/media/platform/davinci/dm3xx_ipipeif.c
>
> [snip]
>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/v4l2-mediabus.h>
>> +#include <linux/platform_device.h>
>
> Just a side note, I usually sort headers alphabetically, but feel free to use
> whatever convention you like.
>
Ok I'll sort to.

>> +#include "dm3xx_ipipeif.h"
>> +
>> +static void *__iomem ipipeif_base_addr;
>
> That's not good. You shouldn't have global constants like that. The value
> should instead be stored in your device structure, that you will need to pass
> around to all functions.
>
Ok.

>> +static inline u32 regr_if(u32 offset)
>> +{
>> +     return readl(ipipeif_base_addr + offset);
>> +}
>> +
>> +static inline void regw_if(u32 val, u32 offset)
>> +{
>> +     writel(val, ipipeif_base_addr + offset);
>> +}
>
> Maybe ipipeif_read() and ipipeif_write() ?
>
>> +void ipipeif_set_enable()
>> +{
>> +     regw_if(1, IPIPEIF_ENABLE);
>> +}
>
> Please define constants in a header file for register values, masks and shifts
> instead of hardcoding the raw numbers.
>
Ok.

> [snip]
>
>> +static int __devinit dm3xx_ipipeif_probe(struct platform_device *pdev)
>> +{
>> +     static resource_size_t  res_len;
>> +     struct resource *res;
>> +     int status;
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     if (!res)
>> +             return -ENOENT;
>> +
>> +     res_len = resource_size(res);
>> +
>> +     res = request_mem_region(res->start, res_len, res->name);
>> +     if (!res)
>> +             return -EBUSY;
>> +
>> +     ipipeif_base_addr = ioremap_nocache(res->start, res_len);
>> +     if (!ipipeif_base_addr) {
>> +             status = -EBUSY;
>> +             goto fail;
>> +     }
>> +     return 0;
>> +
>> +fail:
>> +     release_mem_region(res->start, res_len);
>> +
>> +     return status;
>> +}
>> +
>> +static int dm3xx_ipipeif_remove(struct platform_device *pdev)
>> +{
>> +     struct resource *res;
>> +
>> +     iounmap(ipipeif_base_addr);
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     if (res)
>> +             release_mem_region(res->start, resource_size(res));
>> +     return 0;
>> +}
>> +
>> +static struct platform_driver dm3xx_ipipeif_driver = {
>> +     .driver = {
>> +             .name   = "dm3xx_ipipeif",
>> +             .owner = THIS_MODULE,
>> +     },
>> +     .remove = __devexit_p(dm3xx_ipipeif_remove),
>> +     .probe = dm3xx_ipipeif_probe,
>> +};
>> +
>> +static int dm3xx_ipipeif_init(void)
>> +{
>> +     return platform_driver_register(&dm3xx_ipipeif_driver);
>> +}
>> +
>> +static void dm3xx_ipipeif_exit(void)
>> +{
>> +     platform_driver_unregister(&dm3xx_ipipeif_driver);
>> +}
>> +
>> +module_init(dm3xx_ipipeif_init);
>> +module_exit(dm3xx_ipipeif_exit);
>
> I'm not sure to like this. You're registering a module for a device that
> essentially sits there without doing anything, except providing functions that
> can be called by other modules.
>
> I somehow feel that the way the code is split amongst the different layers
> isn't optimal. Could you briefly explain the rationale behind the current
> architecture ?
>
> (BTW, please use the module_platform_driver() macro instead of
> module_init/module_exit)
>
As discussed over the IRC, I am working on new design, hopefully
you will be happy this time :)

> [snip]
>
>> diff --git a/include/linux/dm3xx_ipipeif.h b/include/linux/dm3xx_ipipeif.h
>> new file mode 100644
>> index 0000000..1c1a830
>> --- /dev/null
>> +++ b/include/linux/dm3xx_ipipeif.h
>
> [snip]
>
>> +#include <media/davinci/vpfe_types.h>
>> +#include <media/davinci/vpfe.h>
>
> This header file defines part of the userspace API, but includes media/
> headers that are not exported to userspace.
>
> Header files should be split between 3 directories:
>
> - Definitions required by platform data used to go to media/ but the new
> include/linux/platform_data/ directory might be preferred nowadays. I have no
> strong opinion on this, as other headers are already in media/ you can
> probably keep using it for now.
>
> - Definitions requires by userspace should go to include/linux/
>
> - The rest should go to drivers/media/platform/davinci/.
>
Ok, I'll follow the same convention.

Thanks and Regards,
--Prabhakar Lad

> --
> Regards,
>
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 02/14] davinci: vpfe: add IPIPE hardware layer support
  2012-09-14 12:46 ` [PATCH 02/14] davinci: vpfe: add IPIPE hardware layer support Prabhakar Lad
@ 2012-09-23 14:36   ` Sakari Ailus
  2012-09-24  4:59     ` Prabhakar Lad
  0 siblings, 1 reply; 23+ messages in thread
From: Sakari Ailus @ 2012-09-23 14:36 UTC (permalink / raw)
  To: Prabhakar Lad
  Cc: LMML, LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

Hi Prabhakar,

Thanks for the patchset! I've got a few comments below.

Prabhakar Lad wrote:
> From: Manjunath Hadli <manjunath.hadli@ti.com>
>
> add dm365 IPIPE hardware support. IPIPE is the hardware IP which
> implements the functionality required for resizer, previewer and
> the associated feature support. This is built along with the vpfe
> driver, and implements hardware setup including coeffcient
> programming for various hardware filters, gamma, cfa and clock
> enable.
>
> Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
> Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
> ---
>   drivers/media/platform/davinci/dm365_ipipe_hw.c |  936 +++++++++++++++++++++++
>   drivers/media/platform/davinci/dm365_ipipe_hw.h |  538 +++++++++++++
>   2 files changed, 1474 insertions(+), 0 deletions(-)
>   create mode 100644 drivers/media/platform/davinci/dm365_ipipe_hw.c
>   create mode 100644 drivers/media/platform/davinci/dm365_ipipe_hw.h
>
> diff --git a/drivers/media/platform/davinci/dm365_ipipe_hw.c b/drivers/media/platform/davinci/dm365_ipipe_hw.c
> new file mode 100644
> index 0000000..4ce6d95
> --- /dev/null
> +++ b/drivers/media/platform/davinci/dm365_ipipe_hw.c
> @@ -0,0 +1,936 @@
> +/*
> + * Copyright (C) 2012 Texas Instruments 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 version 2.
> + *
> + * 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
> + *
> + * Contributors:
> + *      Manjunath Hadli <manjunath.hadli@ti.com>
> + *      Prabhakar Lad <prabhakar.lad@ti.com>
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/v4l2-mediabus.h>
> +
> +#include "dm365_ipipe.h"
> +#include "dm3xx_ipipeif.h"
> +#include "dm365_ipipe_hw.h"
> +
> +static void ipipe_clock_enable(void)
> +{
> +	/* enable IPIPE MMR for register write access */
> +	regw_ip(IPIPE_GCK_MMR_DEFAULT, IPIPE_GCK_MMR);
> +	/* enable the clock wb,cfa,dfc,d2f,pre modules */
> +	regw_ip(IPIPE_GCK_PIX_DEFAULT, IPIPE_GCK_PIX);
> +	/* enable RSZ MMR for register write access */
> +}
> +
> +/* Set input channel format to either 420 Y or C format */
> +void rsz_set_in_pix_format(unsigned char y_c)
> +{
> +	u32 val;
> +
> +	val = regr_rsz(RSZ_SRC_FMT1);
> +	val |= y_c & 1;
> +	regw_rsz(val, RSZ_SRC_FMT1);
> +}
> +
> +static void rsz_set_common_params(struct ipipe_params *params)
> +{
> +	struct rsz_common_params *rsz_common = &params->rsz_common;
> +	u32 val;
> +
> +	/* Set mode */
> +	regw_rsz(params->ipipe_mode, RSZ_SRC_MODE);
> +
> +	/* data source selection  and bypass */
> +	val = (rsz_common->passthrough << RSZ_BYPASS_SHIFT) |
> +		rsz_common->source;
> +
> +	regw_rsz(val, RSZ_SRC_FMT0);
> +	val = regr_rsz(RSZ_SRC_MODE);

val is assigned but there's no need to.

> +	/* src image selection */
> +	val = (rsz_common->raw_flip & 1) |
> +		(rsz_common->src_img_fmt << RSZ_SRC_IMG_FMT_SHIFT) |
> +		((rsz_common->y_c & 1) << RSZ_SRC_Y_C_SEL_SHIFT);
> +
> +	regw_rsz(val, RSZ_SRC_FMT1);
> +	regw_rsz(rsz_common->vps & IPIPE_RSZ_VPS_MASK, RSZ_SRC_VPS);
> +	regw_rsz(rsz_common->hps & IPIPE_RSZ_HPS_MASK, RSZ_SRC_HPS);
> +	regw_rsz(rsz_common->vsz & IPIPE_RSZ_VSZ_MASK, RSZ_SRC_VSZ);
> +	regw_rsz(rsz_common->hsz & IPIPE_RSZ_HSZ_MASK, RSZ_SRC_HSZ);
> +	regw_rsz(rsz_common->yuv_y_min, RSZ_YUV_Y_MIN);
> +	regw_rsz(rsz_common->yuv_y_max, RSZ_YUV_Y_MAX);
> +	regw_rsz(rsz_common->yuv_c_min, RSZ_YUV_C_MIN);
> +	regw_rsz(rsz_common->yuv_c_max, RSZ_YUV_C_MAX);
> +	/* chromatic position */
> +	regw_rsz(rsz_common->out_chr_pos, RSZ_YUV_PHS);
> +	val = regr_rsz(RSZ_SRC_MODE);

Same here.

> +}
> +
> +static void rsz_set_rsz_regs(unsigned int rsz_id, struct ipipe_params *params)
> +{
> +	struct ipipe_rsz_rescale_param *rsc_params;
> +	struct ipipe_ext_mem_param *ext_mem;
> +	struct ipipe_rsz_resize2rgb *rgb;
> +	u32 reg_base;
> +	u32 val;
> +
> +	val = regr_rsz(RSZ_SEQ);

And here.

> +	rsc_params = &params->rsz_rsc_param[rsz_id];
> +	rgb = &params->rsz2rgb[rsz_id];
> +	ext_mem = &params->ext_mem_param[rsz_id];
> +
> +	if (rsz_id == RSZ_A) {
> +		val = rsc_params->h_flip << RSZA_H_FLIP_SHIFT;
> +		val |= rsc_params->v_flip << RSZA_V_FLIP_SHIFT;
> +		reg_base = RSZ_EN_A;
> +	} else {
> +		val = rsc_params->h_flip << RSZB_H_FLIP_SHIFT;
> +		val |= rsc_params->v_flip << RSZB_V_FLIP_SHIFT;
> +		reg_base = RSZ_EN_B;
> +	}
> +	/* update flip settings */
> +	regw_rsz(val, RSZ_SEQ);
> +
> +	regw_rsz(rsc_params->mode, reg_base + RSZ_MODE);
> +	val = (rsc_params->cen << RSZ_CEN_SHIFT) | rsc_params->yen;
> +	regw_rsz(val, reg_base + RSZ_420);
> +	regw_rsz(rsc_params->i_vps & RSZ_VPS_MASK, reg_base + RSZ_I_VPS);
> +	regw_rsz(rsc_params->i_hps & RSZ_HPS_MASK, reg_base + RSZ_I_HPS);
> +	regw_rsz(rsc_params->o_vsz & RSZ_O_VSZ_MASK, reg_base + RSZ_O_VSZ);
> +	regw_rsz(rsc_params->o_hsz & RSZ_O_HSZ_MASK, reg_base + RSZ_O_HSZ);
> +	regw_rsz(rsc_params->v_phs_y & RSZ_V_PHS_MASK, reg_base + RSZ_V_PHS_Y);
> +	regw_rsz(rsc_params->v_phs_c & RSZ_V_PHS_MASK, reg_base + RSZ_V_PHS_C);
> +	/* keep this additional adjustment to zero for now */
> +	regw_rsz(rsc_params->v_dif & RSZ_V_DIF_MASK, reg_base + RSZ_V_DIF);
> +
> +	val = (rsc_params->v_typ_y & 1) | ((rsc_params->v_typ_c & 1) <<
> +							RSZ_TYP_C_SHIFT);
> +	regw_rsz(val, reg_base + RSZ_V_TYP);
> +
> +	val = (rsc_params->v_lpf_int_y & RSZ_LPF_INT_MASK) |
> +			((rsc_params->v_lpf_int_c & RSZ_LPF_INT_MASK) <<
> +				RSZ_LPF_INT_C_SHIFT);
> +	regw_rsz(val, reg_base + RSZ_V_LPF);
> +
> +	regw_rsz(rsc_params->h_phs & RSZ_H_PHS_MASK, reg_base + RSZ_H_PHS);
> +	regw_rsz(0, reg_base + RSZ_H_PHS_ADJ);
> +	regw_rsz(rsc_params->h_dif & RSZ_H_DIF_MASK, reg_base + RSZ_H_DIF);
> +	val = (rsc_params->h_typ_y & 1) | ((rsc_params->h_typ_c & 1) <<
> +							RSZ_TYP_C_SHIFT);
> +	regw_rsz(val, reg_base + RSZ_H_TYP);
> +	val = (rsc_params->h_lpf_int_y & RSZ_LPF_INT_MASK) |
> +		 ((rsc_params->h_lpf_int_c & RSZ_LPF_INT_MASK) <<
> +		 RSZ_LPF_INT_C_SHIFT);
> +	regw_rsz(val, reg_base + RSZ_H_LPF);
> +
> +	regw_rsz(rsc_params->dscale_en & 1, reg_base + RSZ_DWN_EN);
> +	val = rsc_params->h_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK;
> +	val |= (rsc_params->v_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK) <<
> +				  RSZ_DWN_SCALE_AV_SZ_V_SHIFT;
> +	regw_rsz(val, reg_base + RSZ_DWN_AV);
> +
> +	/* setting rgb conversion parameters */
> +	regw_rsz(rgb->rgb_en, reg_base + RSZ_RGB_EN);
> +	val = (rgb->rgb_typ << RSZ_RGB_TYP_SHIFT) |
> +		 (rgb->rgb_msk0 << RSZ_RGB_MSK0_SHIFT) |
> +		 (rgb->rgb_msk1 << RSZ_RGB_MSK1_SHIFT);
> +	regw_rsz(val, reg_base + RSZ_RGB_TYP);
> +	regw_rsz(rgb->rgb_alpha_val & RSZ_RGB_ALPHA_MASK,
> +		reg_base + RSZ_RGB_BLD);
> +
> +	/* setting external memory parameters */
> +	regw_rsz(ext_mem->rsz_sdr_oft_y, reg_base + RSZ_SDR_Y_OFT);
> +	regw_rsz(ext_mem->rsz_sdr_ptr_s_y, reg_base + RSZ_SDR_Y_PTR_S);
> +	regw_rsz(ext_mem->rsz_sdr_ptr_e_y, reg_base + RSZ_SDR_Y_PTR_E);
> +	regw_rsz(ext_mem->rsz_sdr_oft_c, reg_base + RSZ_SDR_C_OFT);
> +	regw_rsz(ext_mem->rsz_sdr_ptr_s_c, reg_base + RSZ_SDR_C_PTR_S);
> +	regw_rsz((ext_mem->rsz_sdr_ptr_e_c >> 1), reg_base + RSZ_SDR_C_PTR_E);
> +}
> +
> +/*set the registers of either RSZ0 or RSZ1 */
> +static void ipipe_setup_resizer(struct ipipe_params *params)
> +{
> +	/* enable MMR gate to write to Resizer */
> +	regw_rsz(1, RSZ_GCK_MMR);
> +
> +	/* Enable resizer if it is not in bypass mode */
> +	if (params->rsz_common.passthrough)
> +		regw_rsz(0, RSZ_GCK_SDR);
> +	else
> +		regw_rsz(1, RSZ_GCK_SDR);
> +
> +	rsz_set_common_params(params);
> +
> +	regw_rsz(params->rsz_en[RSZ_A], RSZ_EN_A);
> +	if (params->rsz_en[RSZ_A])
> +		/*setting rescale parameters */
> +		rsz_set_rsz_regs(RSZ_A, params);
> +
> +	regw_rsz(params->rsz_en[RSZ_B], RSZ_EN_B);
> +	if (params->rsz_en[RSZ_B])
> +		rsz_set_rsz_regs(RSZ_B, params);
> +
> +	regr_rsz(RSZ_SRC_MODE);
> +}
> +
> +/*
> + * ipipe_hw_setup() - Performs hardware setup of ipipe.
> + */
> +int ipipe_hw_setup(struct ipipe_params *config)
> +{
> +	u32 data_format;
> +	u32 val;
> +
> +	if (!config) {
> +		pr_err("ipipe_hw_setup- Invalid config\n");
> +		return -EINVAL;
> +	}

The function is only used byt the driver internally, so the check should 
be done elsewhere. If you want to check it also here, you can use BUG_ON().

> +	if (ipipeif_hw_setup(&config->ipipeif_param, DM365) < 0) {
> +		pr_err("ipipe_hw_setup- Failed to configure IPIPEIF");
> +		return -EINVAL;
> +	}
> +
> +	/* enable clock to IPIPE */
> +	vpss_enable_clock(VPSS_IPIPE_CLOCK, 1);
> +	/* enable clock to MMR and modules before writting
> +	 * to ipipe registers
> +	 */
> +	ipipe_clock_enable();
> +
> +	if (config->rsz_common.source == IPIPEIF_DATA) {
> +		/* we need to skip configuring IPIPE */
> +		regw_ip(0, IPIPE_SRC_EN);
> +	} else {
> +		/* enable ipipe mode to either one shot or continuous */
> +		val = config->ipipe_mode;
> +		regw_ip(val, IPIPE_SRC_MODE);

You can remove val.

> +		data_format = config->ipipe_dpaths_fmt;
> +		regw_ip(data_format, IPIPE_SRC_FMT);
> +		/* set size */
> +		regw_ip(config->ipipe_vps & IPIPE_RSZ_VPS_MASK, IPIPE_SRC_VPS);
> +		regw_ip(config->ipipe_hps & IPIPE_RSZ_HPS_MASK, IPIPE_SRC_HPS);
> +		regw_ip(config->ipipe_vsz & IPIPE_RSZ_VSZ_MASK, IPIPE_SRC_VSZ);
> +		regw_ip(config->ipipe_hsz & IPIPE_RSZ_HSZ_MASK, IPIPE_SRC_HSZ);
> +
> +		if (data_format == IPIPE_RAW2YUV ||
> +					data_format == IPIPE_RAW2RAW)
> +			regw_ip(config->ipipe_colpat, IPIPE_SRC_COL);
> +	}
> +
> +	ipipe_setup_resizer(config);
> +
> +	return 0;
> +}
> +
> +static void rsz_set_y_address(unsigned int address, unsigned int offset)
> +{
> +	u32 val;
> +
> +	val = address & SET_LOW_ADD;
> +	regw_rsz(val, offset + RSZ_SDR_Y_BAD_L);
> +	regw_rsz(val, offset + RSZ_SDR_Y_SAD_L);
> +	val = (address & SET_HIGH_ADD) >> 16;
> +	regw_rsz(val, offset + RSZ_SDR_Y_BAD_H);
> +	regw_rsz(val, offset + RSZ_SDR_Y_SAD_H);
> +}
> +
> +static void rsz_set_c_address(unsigned int address, unsigned int offset)
> +{
> +	u32 val;
> +
> +	val = address & SET_LOW_ADD;
> +
> +	regw_rsz(val, offset + RSZ_SDR_C_BAD_L);
> +	regw_rsz(val, offset + RSZ_SDR_C_SAD_L);
> +	val = (address & SET_HIGH_ADD) >> 16;
> +	regw_rsz(val, offset + RSZ_SDR_C_BAD_H);
> +	regw_rsz(val, offset + RSZ_SDR_C_SAD_H);
> +}
> +
> +/* Assume we get a valid params ptr and resize_no set to RSZ_A
> + * or RSZ_B. This could be called in the interrupt context and
> + * must be efficient
> + */
> +void rsz_set_output_address(struct ipipe_params *params,
> +			   int resize_no, unsigned int address)
> +{
> +	unsigned int rsz_start_add;
> +	unsigned int val;
> +
> +	struct ipipe_ext_mem_param *mem_param =
> +		&params->ext_mem_param[resize_no];
> +	struct rsz_common_params *rsz_common =
> +		&params->rsz_common;
> +	struct ipipe_rsz_rescale_param *rsc_param =
> +		&params->rsz_rsc_param[resize_no];
> +
> +	if (resize_no == RSZ_A)
> +		rsz_start_add = RSZ_EN_A;
> +	else
> +		rsz_start_add = RSZ_EN_B;
> +	/* y_c = 0 for y, = 1 for c */
> +	if (rsz_common->src_img_fmt == RSZ_IMG_420) {
> +		if (rsz_common->y_c) {
> +			/* C channel */
> +			val = address + mem_param->flip_ofst_c;
> +			rsz_set_c_address(val, rsz_start_add);
> +		} else {
> +			val = address + mem_param->flip_ofst_y;
> +			rsz_set_y_address(val, rsz_start_add);
> +		}
> +	} else {
> +		if (rsc_param->cen && rsc_param->yen) {
> +			/* 420 */
> +			val = address + mem_param->c_offset;
> +			val = address + mem_param->c_offset +
> +				mem_param->flip_ofst_c;

You're overwriting val immediately after assignment above.

> +			val += mem_param->user_y_ofst +
> +				mem_param->user_c_ofst;

This can be combined with the above. There are many similar cases below.

> +			if (resize_no == RSZ_B)
> +				val +=
> +				params->ext_mem_param[RSZ_A].user_y_ofst +
> +				params->ext_mem_param[RSZ_A].user_c_ofst;
> +			/* set C address */
> +			rsz_set_c_address(val, rsz_start_add);
> +		}
> +		val = address + mem_param->flip_ofst_y;
> +		val += mem_param->user_y_ofst;
> +		if (resize_no == RSZ_B)
> +			val += params->ext_mem_param[RSZ_A].user_y_ofst +
> +				params->ext_mem_param[RSZ_A].user_c_ofst;
> +		/* set Y address */
> +		rsz_set_y_address(val, rsz_start_add);
> +	}
> +	/* resizer must be enabled */
> +	regw_rsz(params->rsz_en[resize_no], rsz_start_add);
> +
> +}
> +
> +void ipipe_set_lutdpc_regs(struct prev_lutdpc *dpc)
> +{
> +	u32 max_tbl_size = LUT_DPC_MAX_SIZE >> 1;
> +	u32 lut_start_addr = DPC_TB0_START_ADDR;
> +	u32 val;
> +	u32 count;
> +
> +	ipipe_clock_enable();
> +	regw_ip(dpc->en, DPC_LUT_EN);
> +	if (dpc->en != 1)
> +		return;
> +
> +	/* if dpc is enabled */
> +	val = LUTDPC_TBL_256_EN;
> +	val |= dpc->repl_white & 1;
> +	regw_ip(val, DPC_LUT_SEL);
> +	regw_ip(LUT_DPC_START_ADDR, DPC_LUT_ADR);
> +	regw_ip(dpc->dpc_size, DPC_LUT_SIZ & LUT_DPC_SIZE_MASK);
> +
> +	if (dpc->table == NULL)
> +		return;
> +
> +	for (count = 0; count < dpc->dpc_size; count++) {
> +		if (count >= max_tbl_size)
> +			lut_start_addr = DPC_TB1_START_ADDR;
> +		val = dpc->table[count].horz_pos & LUT_DPC_H_POS_MASK;
> +		val |= (dpc->table[count].vert_pos & LUT_DPC_V_POS_MASK) <<
> +			LUT_DPC_V_POS_SHIFT;
> +		val |= dpc->table[count].method << LUT_DPC_CORR_METH_SHIFT;
> +		w_ip_table(val, (lut_start_addr +
> +						((count % max_tbl_size) << 2)));
> +	}
> +}
> +
> +static void set_dpc_thresholds(struct prev_otfdpc_2_0 *dpc_thr)
> +{
> +	regw_ip((dpc_thr->corr_thr.r & OTFDPC_DPC2_THR_MASK),
> +		DPC_OTF_2C_THR_R);
> +	regw_ip((dpc_thr->corr_thr.gr & OTFDPC_DPC2_THR_MASK),
> +		DPC_OTF_2C_THR_GR);
> +	regw_ip((dpc_thr->corr_thr.gb & OTFDPC_DPC2_THR_MASK),
> +		DPC_OTF_2C_THR_GB);
> +	regw_ip((dpc_thr->corr_thr.b & OTFDPC_DPC2_THR_MASK),
> +		DPC_OTF_2C_THR_B);
> +	regw_ip((dpc_thr->det_thr.r & OTFDPC_DPC2_THR_MASK),
> +		DPC_OTF_2D_THR_R);
> +	regw_ip((dpc_thr->det_thr.gr & OTFDPC_DPC2_THR_MASK),
> +		DPC_OTF_2D_THR_GR);
> +	regw_ip((dpc_thr->det_thr.gb & OTFDPC_DPC2_THR_MASK),
> +		DPC_OTF_2D_THR_GB);
> +	regw_ip((dpc_thr->det_thr.b & OTFDPC_DPC2_THR_MASK),
> +		DPC_OTF_2D_THR_B);
> +}
> +
> +void ipipe_set_otfdpc_regs(struct prev_otfdpc *otfdpc)
> +{
> +	struct prev_otfdpc_2_0 *dpc_2_0 = &otfdpc->alg_cfg.dpc_2_0;
> +	struct prev_otfdpc_3_0 *dpc_3_0 = &otfdpc->alg_cfg.dpc_3_0;
> +	u32 val;
> +
> +	ipipe_clock_enable();
> +
> +	regw_ip((otfdpc->en & 1), DPC_OTF_EN);
> +	if (otfdpc->en != 1)

otfdpc->en could be made bool.

> +		return;
> +
> +	/* dpc enabled */
> +	val = otfdpc->det_method << OTF_DET_METHOD_SHIFT;
> +	val |= otfdpc->alg;
> +	regw_ip(val, DPC_OTF_TYP);
> +	if (otfdpc->det_method == IPIPE_DPC_OTF_MIN_MAX) {
> +		/* ALG= 0, TYP = 0, DPC_OTF_2D_THR_[x]=0
> +		 * DPC_OTF_2C_THR_[x] = Maximum thresohld
> +		 * MinMax method
> +		 */
> +		dpc_2_0->det_thr.r = dpc_2_0->det_thr.gb =
> +		dpc_2_0->det_thr.gr = dpc_2_0->det_thr.b = 0;
> +		set_dpc_thresholds(dpc_2_0);
> +		return;
> +	}
> +	/* MinMax2 */
> +	if (otfdpc->alg == IPIPE_OTFDPC_2_0) {
> +		set_dpc_thresholds(dpc_2_0);
> +		return;
> +	}
> +	regw_ip((dpc_3_0->act_adj_shf & OTF_DPC3_0_SHF_MASK), DPC_OTF_3_SHF);
> +	/* Detection thresholds */
> +	regw_ip(((dpc_3_0->det_thr & OTF_DPC3_0_THR_MASK) <<
> +		OTF_DPC3_0_THR_SHIFT), DPC_OTF_3D_THR);
> +	regw_ip((dpc_3_0->det_slp & OTF_DPC3_0_SLP_MASK), DPC_OTF_3D_SLP);
> +	regw_ip((dpc_3_0->det_thr_min & OTF_DPC3_0_DET_MASK), DPC_OTF_3D_MIN);
> +	regw_ip((dpc_3_0->det_thr_max & OTF_DPC3_0_DET_MASK), DPC_OTF_3D_MAX);
> +	/* Correction thresholds */
> +	regw_ip(((dpc_3_0->corr_thr & OTF_DPC3_0_THR_MASK) <<
> +		OTF_DPC3_0_THR_SHIFT), DPC_OTF_3C_THR);
> +	regw_ip((dpc_3_0->corr_slp & OTF_DPC3_0_SLP_MASK), DPC_OTF_3C_SLP);
> +	regw_ip((dpc_3_0->corr_thr_min & OTF_DPC3_0_CORR_MASK), DPC_OTF_3C_MIN);
> +	regw_ip((dpc_3_0->corr_thr_max & OTF_DPC3_0_CORR_MASK), DPC_OTF_3C_MAX);

Extra parenthesis may be removed.

> +}
> +
> +/* 2D Noise filter */
> +void ipipe_set_d2f_regs(unsigned int id, struct prev_nf *noise_filter)
> +{
> +
> +	u32 offset = D2F_1ST;
> +	int count;
> +	u32 val;
> +
> +	/* id = 0 , NF1 & id = 1, NF 2 */
> +	if (id)
> +		offset = D2F_2ND;

You could make id an enum, or create #defines to tell the two noise 
filters apart.

> +	ipipe_clock_enable();
> +	regw_ip(noise_filter->en & 1, offset + D2F_EN);
> +	if (noise_filter->en != 1)

How about making noise_filter->en bool?

> +		return;
> +
> +	/*noise filter enabled */
> +	/* Combine all the fields to make D2F_CFG register of IPIPE */
> +	val = ((noise_filter->spread_val & D2F_SPR_VAL_MASK) <<
> +		 D2F_SPR_VAL_SHIFT) |
> +		 ((noise_filter->shft_val & D2F_SHFT_VAL_MASK) <<
> +		 D2F_SHFT_VAL_SHIFT) |
> +		 (noise_filter->gr_sample_meth <<
> +		 D2F_SAMPLE_METH_SHIFT) |
> +		 ((noise_filter->apply_lsc_gain & 1) <<
> +		 D2F_APPLY_LSC_GAIN_SHIFT) | D2F_USE_SPR_REG_VAL;
> +
> +	regw_ip(val, offset + D2F_TYP);
> +	/* edge detection minimum */
> +	regw_ip(noise_filter->edge_det_min_thr & D2F_EDGE_DET_THR_MASK,
> +		offset + D2F_EDG_MIN);
> +	/* edge detection maximum */
> +	regw_ip(noise_filter->edge_det_max_thr & D2F_EDGE_DET_THR_MASK,
> +		offset + D2F_EDG_MAX);
> +	for (count = 0; count < IPIPE_NF_STR_TABLE_SIZE; count++) {
> +		regw_ip((noise_filter->str[count] & D2F_STR_VAL_MASK),
> +			offset + D2F_STR + count * 4);
> +
> +	}
> +	for (count = 0; count < IPIPE_NF_THR_TABLE_SIZE; count++) {
> +		regw_ip(noise_filter->thr[count] & D2F_THR_VAL_MASK,
> +			offset + D2F_THR + count * 4);
> +	}

Extra braces may be removed above.

> +}
> +
> +#define IPIPE_U8Q5(decimal, integer) \
> +	(((decimal & 0x1f) | ((integer & 0x7) << 5)))
> +
> +/* Green Imbalance Correction */
> +void ipipe_set_gic_regs(struct prev_gic *gic)
> +{
> +	u32 val;
> +
> +	ipipe_clock_enable();
> +	regw_ip(gic->en & 1, GIC_EN);
> +
> +	if (!gic->en)
> +		return;
> +
> +	/*gic enabled */
> +	val = gic->wt_fn_type << GIC_TYP_SHIFT;
> +	val |= gic->thr_sel << GIC_THR_SEL_SHIFT;
> +	val |= (gic->apply_lsc_gain & 1) << GIC_APPLY_LSC_GAIN_SHIFT;
> +	regw_ip(val, GIC_TYP);
> +	regw_ip(gic->gain & GIC_GAIN_MASK, GIC_GAN);
> +
> +	if (gic->gic_alg != IPIPE_GIC_ALG_ADAPT_GAIN) {
> +		/* Constant Gain. Set threshold to maximum */
> +		regw_ip(GIC_THR_MASK, GIC_THR);
> +		return;
> +	}
> +
> +	if (gic->thr_sel == IPIPE_GIC_THR_REG) {
> +		regw_ip(gic->thr & GIC_THR_MASK, GIC_THR);
> +		regw_ip(gic->slope & GIC_SLOPE_MASK, GIC_SLP);
> +	} else {
> +		/* Use NF thresholds */
> +		val = IPIPE_U8Q5(gic->nf2_thr_gain.decimal,
> +				gic->nf2_thr_gain.integer);
> +		regw_ip(val, GIC_NFGAN);
> +	}
> +}
> +
> +#define IPIPE_U13Q9(decimal, integer) \
> +	(((decimal & 0x1ff) | ((integer & 0xf) << 9)))
> +/* White balance */
> +void ipipe_set_wb_regs(struct prev_wb *wb)
> +{
> +	u32 val;
> +
> +	ipipe_clock_enable();
> +	/* Ofsets. S12 */
> +	regw_ip(wb->ofst_r & WB_OFFSET_MASK, WB2_OFT_R);
> +	regw_ip(wb->ofst_gr & WB_OFFSET_MASK, WB2_OFT_GR);
> +	regw_ip(wb->ofst_gb & WB_OFFSET_MASK, WB2_OFT_GB);
> +	regw_ip(wb->ofst_b & WB_OFFSET_MASK, WB2_OFT_B);
> +
> +	/* Gains. U13Q9 */
> +	val = IPIPE_U13Q9(wb->gain_r.decimal, wb->gain_r.integer);
> +	regw_ip(val, WB2_WGN_R);
> +	val = IPIPE_U13Q9(wb->gain_gr.decimal, wb->gain_gr.integer);
> +	regw_ip(val, WB2_WGN_GR);
> +	val = IPIPE_U13Q9(wb->gain_gb.decimal, wb->gain_gb.integer);
> +	regw_ip(val, WB2_WGN_GB);
> +	val = IPIPE_U13Q9(wb->gain_b.decimal, wb->gain_b.integer);
> +	regw_ip(val, WB2_WGN_B);
> +}
> +
> +/* CFA */
> +void ipipe_set_cfa_regs(struct prev_cfa *cfa)
> +{
> +	ipipe_clock_enable();
> +	regw_ip(cfa->alg, CFA_MODE);
> +	regw_ip(cfa->hpf_thr_2dir & CFA_HPF_THR_2DIR_MASK, CFA_2DIR_HPF_THR);
> +	regw_ip(cfa->hpf_slp_2dir & CFA_HPF_SLOPE_2DIR_MASK, CFA_2DIR_HPF_SLP);
> +	regw_ip(cfa->hp_mix_thr_2dir & CFA_HPF_MIX_THR_2DIR_MASK,
> +			CFA_2DIR_MIX_THR);
> +	regw_ip(cfa->hp_mix_slope_2dir & CFA_HPF_MIX_SLP_2DIR_MASK,
> +			CFA_2DIR_MIX_SLP);
> +	regw_ip(cfa->dir_thr_2dir & CFA_DIR_THR_2DIR_MASK, CFA_2DIR_DIR_THR);
> +	regw_ip(cfa->dir_slope_2dir & CFA_DIR_SLP_2DIR_MASK, CFA_2DIR_DIR_SLP);
> +	regw_ip(cfa->nd_wt_2dir & CFA_ND_WT_2DIR_MASK, CFA_2DIR_NDWT);
> +	regw_ip(cfa->hue_fract_daa & CFA_DAA_HUE_FRA_MASK, CFA_MONO_HUE_FRA);
> +	regw_ip(cfa->edge_thr_daa & CFA_DAA_EDG_THR_MASK, CFA_MONO_EDG_THR);
> +	regw_ip(cfa->thr_min_daa & CFA_DAA_THR_MIN_MASK, CFA_MONO_THR_MIN);
> +	regw_ip(cfa->thr_slope_daa & CFA_DAA_THR_SLP_MASK, CFA_MONO_THR_SLP);
> +	regw_ip(cfa->slope_min_daa & CFA_DAA_SLP_MIN_MASK, CFA_MONO_SLP_MIN);
> +	regw_ip(cfa->slope_slope_daa & CFA_DAA_SLP_SLP_MASK, CFA_MONO_SLP_SLP);
> +	regw_ip(cfa->lp_wt_daa & CFA_DAA_LP_WT_MASK, CFA_MONO_LPWT);
> +}
> +
> +void ipipe_set_rgb2rgb_regs(unsigned int id, struct prev_rgb2rgb *rgb)
> +{
> +	u32 offset_mask = RGB2RGB_1_OFST_MASK;
> +	u32 offset = RGB1_MUL_BASE;
> +	u32 integ_mask = 0xf;
> +	u32 val;
> +
> +	ipipe_clock_enable();
> +
> +	if (id) {
> +		/* For second RGB module, gain integer is 3 bits instead
> +		of 4, offset has 11 bits insread of 13 */
> +		offset = RGB2_MUL_BASE;
> +		integ_mask = 0x7;
> +		offset_mask = RGB2RGB_2_OFST_MASK;
> +	}
> +	/* Gains */
> +	val = (rgb->coef_rr.decimal & 0xff) |
> +		((rgb->coef_rr.integer & integ_mask) << 8);
> +	regw_ip(val, offset + RGB_MUL_RR);
> +	val = (rgb->coef_gr.decimal & 0xff) |
> +		((rgb->coef_gr.integer & integ_mask) << 8);
> +	regw_ip(val, offset + RGB_MUL_GR);
> +	val = (rgb->coef_br.decimal & 0xff) |
> +		((rgb->coef_br.integer & integ_mask) << 8);
> +	regw_ip(val, offset + RGB_MUL_BR);
> +	val = (rgb->coef_rg.decimal & 0xff) |
> +		((rgb->coef_rg.integer & integ_mask) << 8);
> +	regw_ip(val, offset + RGB_MUL_RG);
> +	val = (rgb->coef_gg.decimal & 0xff) |
> +		((rgb->coef_gg.integer & integ_mask) << 8);
> +	regw_ip(val, offset + RGB_MUL_GG);
> +	val = (rgb->coef_bg.decimal & 0xff) |
> +		((rgb->coef_bg.integer & integ_mask) << 8);
> +	regw_ip(val, offset + RGB_MUL_BG);
> +	val = (rgb->coef_rb.decimal & 0xff) |
> +		((rgb->coef_rb.integer & integ_mask) << 8);
> +	regw_ip(val, offset + RGB_MUL_RB);
> +	val = (rgb->coef_gb.decimal & 0xff) |
> +		((rgb->coef_gb.integer & integ_mask) << 8);
> +	regw_ip(val, offset + RGB_MUL_GB);
> +	val = (rgb->coef_bb.decimal & 0xff) |
> +		((rgb->coef_bb.integer & integ_mask) << 8);
> +	regw_ip(val, offset + RGB_MUL_BB);
> +
> +	/* Offsets */
> +	regw_ip(rgb->out_ofst_r & offset_mask, offset + RGB_OFT_OR);
> +	regw_ip(rgb->out_ofst_g & offset_mask, offset + RGB_OFT_OG);
> +	regw_ip(rgb->out_ofst_b & offset_mask, offset + RGB_OFT_OB);
> +}
> +
> +static void ipipe_update_gamma_tbl(struct ipipe_gamma_entry *table,
> +				   int size, u32 addr)
> +{
> +	int count;
> +	u32 val;
> +
> +	for (count = 0; count < size; count++) {
> +		val = table[count].slope & GAMMA_MASK;
> +		val |= (table[count].offset & GAMMA_MASK) << GAMMA_SHIFT;
> +		w_ip_table(val, (addr + (count * 4)));
> +	}
> +}
> +
> +/* Gamma correction */
> +void ipipe_set_gamma_regs(struct prev_gamma *gamma)
> +{
> +	int table_size;
> +	u32 val;
> +
> +	ipipe_clock_enable();
> +	val = (gamma->bypass_r << GAMMA_BYPR_SHIFT) |
> +		(gamma->bypass_b << GAMMA_BYPG_SHIFT) |
> +		(gamma->bypass_g << GAMMA_BYPB_SHIFT) |
> +		(gamma->tbl_sel << GAMMA_TBL_SEL_SHIFT) |
> +		(gamma->tbl_size << GAMMA_TBL_SIZE_SHIFT);
> +
> +	regw_ip(val, GMM_CFG);
> +
> +	if (gamma->tbl_sel != IPIPE_GAMMA_TBL_RAM)
> +		return;
> +
> +	table_size = gamma->tbl_size;
> +
> +	if (!gamma->bypass_r && gamma->table_r != NULL) {
> +		ipipe_update_gamma_tbl(gamma->table_r, table_size,
> +					GAMMA_R_START_ADDR);
> +	}
> +	if (!gamma->bypass_b && gamma->table_b != NULL) {
> +		ipipe_update_gamma_tbl(gamma->table_b, table_size,
> +					GAMMA_B_START_ADDR);
> +	}
> +	if (!gamma->bypass_g && gamma->table_g != NULL) {
> +		ipipe_update_gamma_tbl(gamma->table_g, table_size,
> +					GAMMA_G_START_ADDR);
> +	}

Extra braces may be removed.

> +}
> +
> +/* 3D LUT */
> +void ipipe_set_3d_lut_regs(struct prev_3d_lut *lut_3d)
> +{
> +	struct ipipe_3d_lut_entry *tbl;
> +	u32 bnk_index;
> +	u32 tbl_index;
> +	u32 val;
> +	u32 i;
> +
> +	ipipe_clock_enable();
> +	regw_ip(lut_3d->en, D3LUT_EN);
> +
> +	if (!lut_3d->en)
> +		return;
> +
> +	/* lut_3d enabled */
> +	if (!lut_3d->table)
> +		return;
> +
> +	/* valied table */
> +	tbl = lut_3d->table;
> +	for (i = 0 ; i < MAX_SIZE_3D_LUT; i++) {
> +		/* Each entry has 0-9 (B), 10-19 (G) and
> +		20-29 R values */
> +		val = tbl[i].b & D3_LUT_ENTRY_MASK;
> +		val |= (tbl[i].g & D3_LUT_ENTRY_MASK) <<
> +			 D3_LUT_ENTRY_G_SHIFT;
> +		val |= (tbl[i].r & D3_LUT_ENTRY_MASK) <<
> +			 D3_LUT_ENTRY_R_SHIFT;
> +		bnk_index = i % 4;
> +		tbl_index = i >> 2;
> +		tbl_index <<= 2;
> +		if (bnk_index == 0)
> +			w_ip_table(val, tbl_index + D3L_TB0_START_ADDR);
> +		else if (bnk_index == 1)
> +			w_ip_table(val, tbl_index + D3L_TB1_START_ADDR);
> +		else if (bnk_index == 2)
> +			w_ip_table(val, tbl_index + D3L_TB2_START_ADDR);
> +		else
> +			w_ip_table(val, tbl_index + D3L_TB3_START_ADDR);
> +	}
> +}
> +
> +/* Lumina adjustments */
> +void ipipe_set_lum_adj_regs(struct prev_lum_adj *lum_adj)
> +{
> +	u32 val;
> +
> +	ipipe_clock_enable();
> +	/* combine fields of YUV_ADJ to set brightness and contrast */
> +	val = lum_adj->contrast << LUM_ADJ_CONTR_SHIFT |
> +			lum_adj->brightness << LUM_ADJ_BRIGHT_SHIFT;
> +	regw_ip(val, YUV_ADJ);
> +}
> +
> +#define IPIPE_S12Q8(decimal, integer) \
> +	(((decimal & 0xff) | ((integer & 0xf) << 8)))
> +/* RGB2YUV */
> +void ipipe_set_rgb2ycbcr_regs(struct prev_rgb2yuv *yuv)
> +{
> +	u32 val;
> +
> +	/* S10Q8 */
> +	ipipe_clock_enable();
> +	val = IPIPE_S12Q8(yuv->coef_ry.decimal, yuv->coef_ry.integer);
> +	regw_ip(val, YUV_MUL_RY);
> +	val = IPIPE_S12Q8(yuv->coef_gy.decimal, yuv->coef_gy.integer);
> +	regw_ip(val, YUV_MUL_GY);
> +	val = IPIPE_S12Q8(yuv->coef_by.decimal, yuv->coef_by.integer);
> +	regw_ip(val, YUV_MUL_BY);
> +	val = IPIPE_S12Q8(yuv->coef_rcb.decimal, yuv->coef_rcb.integer);
> +	regw_ip(val, YUV_MUL_RCB);
> +	val = IPIPE_S12Q8(yuv->coef_gcb.decimal, yuv->coef_gcb.integer);
> +	regw_ip(val, YUV_MUL_GCB);
> +	val = IPIPE_S12Q8(yuv->coef_bcb.decimal, yuv->coef_bcb.integer);
> +	regw_ip(val, YUV_MUL_BCB);
> +	val = IPIPE_S12Q8(yuv->coef_rcr.decimal, yuv->coef_rcr.integer);
> +	regw_ip(val, YUV_MUL_RCR);
> +	val = IPIPE_S12Q8(yuv->coef_gcr.decimal, yuv->coef_gcr.integer);
> +	regw_ip(val, YUV_MUL_GCR);
> +	val = IPIPE_S12Q8(yuv->coef_bcr.decimal, yuv->coef_bcr.integer);
> +	regw_ip(val, YUV_MUL_BCR);
> +	regw_ip(yuv->out_ofst_y & RGB2YCBCR_OFST_MASK, YUV_OFT_Y);
> +	regw_ip(yuv->out_ofst_cb & RGB2YCBCR_OFST_MASK, YUV_OFT_CB);
> +	regw_ip(yuv->out_ofst_cr & RGB2YCBCR_OFST_MASK, YUV_OFT_CR);
> +}
> +
> +/* YUV 422 conversion */
> +void ipipe_set_yuv422_conv_regs(struct prev_yuv422_conv *conv)
> +{
> +	u32 val;
> +
> +	ipipe_clock_enable();
> +	/* Combine all the fields to make YUV_PHS register of IPIPE */
> +	val = (conv->chrom_pos << 0) | (conv->en_chrom_lpf << 1);
> +	regw_ip(val, YUV_PHS);
> +}
> +
> +/* GBCE */
> +void ipipe_set_gbce_regs(struct prev_gbce *gbce)
> +{
> +	unsigned int tbl_index;
> +	unsigned int count;
> +	u32 mask = GBCE_Y_VAL_MASK;
> +	u32 val;
> +
> +	if (gbce->type == IPIPE_GBCE_GAIN_TBL)
> +		mask = GBCE_GAIN_VAL_MASK;
> +
> +	ipipe_clock_enable();
> +	regw_ip(gbce->en & 1, GBCE_EN);
> +
> +	if (!gbce->en)
> +		return;
> +
> +	regw_ip(gbce->type, GBCE_TYP);
> +
> +	if (!gbce->table)
> +		return;
> +
> +	/* set to 0 */
> +	val = 0;
> +
> +	for (count = 0; count < MAX_SIZE_GBCE_LUT; count++) {
> +		tbl_index = count >> 1;
> +		tbl_index <<= 2;
> +		/* Each table has 2 LUT entries, first in LS
> +		  * and second in MS positions
> +		  */
> +		if (count % 2) {
> +			val |=
> +				(gbce->table[count] & mask) <<
> +				GBCE_ENTRY_SHIFT;
> +			w_ip_table(val, tbl_index + GBCE_TB_START_ADDR);

You can clean this up by looping half the times, and replace the inside 
of the loop with this (or something close anyway):

w_ip_table(((gbce->table[count + 1] & mask) << GBCE_ENTRY_SHIFT) |
		gbce->table[count] & mask), (count << 2) +
					GBCE_TB_START_ADDR));


> +		} else {
> +			val = gbce->table[count] & mask;
> +		}
> +	}
> +}
> +
> +/* Edge Enhancement */
> +void ipipe_set_ee_regs(struct prev_yee *ee)
> +{
> +	unsigned int tbl_index;
> +	unsigned int count;
> +	u32 val;
> +
> +	ipipe_clock_enable();
> +	regw_ip(ee->en, YEE_EN);
> +
> +	if (!ee->en)
> +		return;
> +
> +	val = ee->en_halo_red & 1;
> +	val |= ee->merge_meth << YEE_HALO_RED_EN_SHIFT;
> +	regw_ip(val, YEE_TYP);
> +	regw_ip(ee->hpf_shft, YEE_SHF);
> +	regw_ip(ee->hpf_coef_00 & YEE_COEF_MASK, YEE_MUL_00);
> +	regw_ip(ee->hpf_coef_01 & YEE_COEF_MASK, YEE_MUL_01);
> +	regw_ip(ee->hpf_coef_02 & YEE_COEF_MASK, YEE_MUL_02);
> +	regw_ip(ee->hpf_coef_10 & YEE_COEF_MASK, YEE_MUL_10);
> +	regw_ip(ee->hpf_coef_11 & YEE_COEF_MASK, YEE_MUL_11);
> +	regw_ip(ee->hpf_coef_12 & YEE_COEF_MASK, YEE_MUL_12);
> +	regw_ip(ee->hpf_coef_20 & YEE_COEF_MASK, YEE_MUL_20);
> +	regw_ip(ee->hpf_coef_21 & YEE_COEF_MASK, YEE_MUL_21);
> +	regw_ip(ee->hpf_coef_22 & YEE_COEF_MASK, YEE_MUL_22);
> +	regw_ip(ee->yee_thr & YEE_THR_MASK, YEE_THR);
> +	regw_ip(ee->es_gain & YEE_ES_GAIN_MASK, YEE_E_GAN);
> +	regw_ip(ee->es_thr1 & YEE_ES_THR1_MASK, YEE_E_THR1);
> +	regw_ip(ee->es_thr2 & YEE_THR_MASK, YEE_E_THR2);
> +	regw_ip(ee->es_gain_grad & YEE_THR_MASK, YEE_G_GAN);
> +	regw_ip(ee->es_ofst_grad & YEE_THR_MASK, YEE_G_OFT);
> +
> +	if (ee->table == NULL)
> +		return;
> +
> +	for (count = 0; count < MAX_SIZE_YEE_LUT; count++) {
> +		tbl_index = count >> 1;
> +		tbl_index <<= 2;
> +		/* Each table has 2 LUT entries, first in LS
> +		  * and second in MS positions
> +		  */
> +		if (count % 2) {
> +			val |= (ee->table[count] & YEE_ENTRY_MASK) <<
> +				YEE_ENTRY_SHIFT;
> +			w_ip_table(val, tbl_index + YEE_TB_START_ADDR);
> +		} else {
> +			val = ee->table[count] & YEE_ENTRY_MASK;
> +		}

Same here.

> +	}
> +}
> +
> +/* Chromatic Artifact Correction. CAR */
> +static void ipipe_set_mf(void)
> +{
> +	/* typ to dynamic switch */
> +	regw_ip(IPIPE_CAR_DYN_SWITCH, CAR_TYP);
> +	/* Set SW0 to maximum */
> +	regw_ip(CAR_MF_THR, CAR_SW);
> +}
> +
> +static void ipipe_set_gain_ctrl(struct prev_car *car)
> +{
> +	regw_ip(IPIPE_CAR_CHR_GAIN_CTRL, CAR_TYP);
> +	regw_ip(car->hpf, CAR_HPF_TYP);
> +	regw_ip(car->hpf_shft & CAR_HPF_SHIFT_MASK, CAR_HPF_SHF);
> +	regw_ip(car->hpf_thr, CAR_HPF_THR);
> +	regw_ip(car->gain1.gain, CAR_GN1_GAN);
> +	regw_ip(car->gain1.shft & CAR_GAIN1_SHFT_MASK, CAR_GN1_SHF);
> +	regw_ip(car->gain1.gain_min & CAR_GAIN_MIN_MASK, CAR_GN1_MIN);
> +	regw_ip(car->gain2.gain, CAR_GN2_GAN);
> +	regw_ip(car->gain2.shft & CAR_GAIN2_SHFT_MASK, CAR_GN2_SHF);
> +	regw_ip(car->gain2.gain_min & CAR_GAIN_MIN_MASK, CAR_GN2_MIN);
> +}
> +
> +void ipipe_set_car_regs(struct prev_car *car)
> +{
> +	u32 val;
> +
> +	ipipe_clock_enable();
> +	regw_ip(car->en, CAR_EN);
> +
> +	if (!car->en)
> +		return;
> +
> +	switch (car->meth) {
> +	case IPIPE_CAR_MED_FLTR:
> +		ipipe_set_mf();
> +		break;
> +	case IPIPE_CAR_CHR_GAIN_CTRL:
> +		ipipe_set_gain_ctrl(car);
> +		break;
> +	default:
> +		/* Dynamic switch between MF and Gain Ctrl. */
> +		ipipe_set_mf();
> +		ipipe_set_gain_ctrl(car);
> +		/* Set the threshold for switching between
> +		  * the two Here we overwrite the MF SW0 value
> +		  */
> +		regw_ip(IPIPE_CAR_DYN_SWITCH, CAR_TYP);
> +		val = car->sw1;
> +		val <<= CAR_SW1_SHIFT;
> +		val |= car->sw0;
> +		regw_ip(val, CAR_SW);
> +	}
> +}
> +
> +/* Chromatic Gain Suppression */
> +void ipipe_set_cgs_regs(struct prev_cgs *cgs)
> +{
> +	ipipe_clock_enable();
> +	regw_ip(cgs->en, CGS_EN);
> +
> +	if (!cgs->en)
> +		return;
> +
> +	/* Set the bright side parameters */
> +	regw_ip(cgs->h_thr, CGS_GN1_H_THR);
> +	regw_ip(cgs->h_slope, CGS_GN1_H_GAN);
> +	regw_ip(cgs->h_shft & CAR_SHIFT_MASK, CGS_GN1_H_SHF);
> +	regw_ip(cgs->h_min, CGS_GN1_H_MIN);
> +}
> +
> +void rsz_src_enable(int enable)
> +{
> +	regw_rsz(enable, RSZ_SRC_EN);
> +}
> +
> +int rsz_enable(int rsz_id, int enable)
> +{
> +	if (rsz_id == RSZ_A) {
> +		regw_rsz(enable, RSZ_EN_A);
> +		/* We always enable RSZ_A. RSZ_B is enable upon request from
> +		 * application. So enable RSZ_SRC_EN along with RSZ_A
> +		 */
> +		regw_rsz(enable, RSZ_SRC_EN);
> +	} else if (rsz_id == RSZ_B) {
> +		regw_rsz(enable, RSZ_EN_B);
> +	} else {
> +		return -EINVAL;

This should be BUG() or WARN(). It's a driver bug if this happens.

> +	}
> +
> +	return 0;
> +}
> diff --git a/drivers/media/platform/davinci/dm365_ipipe_hw.h b/drivers/media/platform/davinci/dm365_ipipe_hw.h
> new file mode 100644
> index 0000000..7e92633
> --- /dev/null
> +++ b/drivers/media/platform/davinci/dm365_ipipe_hw.h
> @@ -0,0 +1,538 @@
> +/*
> + * Copyright (C) 2012 Texas Instruments 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 version 2.
> + *
> + * 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
> + *
> + * Contributors:
> + *      Manjunath Hadli <manjunath.hadli@ti.com>
> + *      Prabhakar Lad <prabhakar.lad@ti.com>
> + */
> +
> +#ifndef _DM365_IPIPE_HW_H
> +#define _DM365_IPIPE_HW_H
> +
> +#include <linux/kernel.h>
> +#include <linux/io.h>
> +
> +#define IPIPE_IOBASE_VADDR		IO_ADDRESS(0x01c70800)
> +#define RSZ_IOBASE_VADDR		IO_ADDRESS(0x01c70400)
> +#define IPIPE_INT_TABLE_IOBASE_VADDR	IO_ADDRESS(0x01c70000)

The above three look like something that should come through platform data.

> +#define SET_LOW_ADD     0x0000ffff
> +#define SET_HIGH_ADD    0xffff0000

Address is often shortened as "addr" but seldom "add". This is because 
the obvious confusing with adding. Up to you.

> +/* Below are the internal tables */
> +#define DPC_TB0_START_ADDR	0x8000
> +#define DPC_TB1_START_ADDR	0x8400
> +
> +#define GAMMA_R_START_ADDR	0xa800
> +#define GAMMA_G_START_ADDR	0xb000
> +#define GAMMA_B_START_ADDR	0xb800
> +
> +/* RAM table addresses for edge enhancement correction*/
> +#define YEE_TB_START_ADDR	0x8800
> +
> +/* RAM table address for GBC LUT */
> +#define GBCE_TB_START_ADDR	0x9000
> +
> +/* RAM table for 3D NF LUT */
> +#define D3L_TB0_START_ADDR	0x9800
> +#define D3L_TB1_START_ADDR	0x9c00
> +#define D3L_TB2_START_ADDR	0xa000
> +#define D3L_TB3_START_ADDR	0xa400
> +
> +/* IPIPE Register Offsets from the base address */
> +#define IPIPE_SRC_EN		0x0000
> +#define IPIPE_SRC_MODE		0x0004
> +#define IPIPE_SRC_FMT		0x0008
> +#define IPIPE_SRC_COL		0x000c
> +#define IPIPE_SRC_VPS		0x0010
> +#define IPIPE_SRC_VSZ		0x0014
> +#define IPIPE_SRC_HPS		0x0018
> +#define IPIPE_SRC_HSZ		0x001c
> +
> +#define IPIPE_SEL_SBU		0x0020
> +
> +#define IPIPE_DMA_STA		0x0024
> +#define IPIPE_GCK_MMR		0x0028
> +#define IPIPE_GCK_PIX		0x002c
> +#define IPIPE_RESERVED0		0x0030
> +
> +/* Defect Correction */
> +#define DPC_LUT_EN		0x0034
> +#define DPC_LUT_SEL		0x0038
> +#define DPC_LUT_ADR		0x003c
> +#define DPC_LUT_SIZ		0x0040
> +#define DPC_OTF_EN		0x0044
> +#define DPC_OTF_TYP		0x0048
> +#define DPC_OTF_2D_THR_R	0x004c
> +#define DPC_OTF_2D_THR_GR	0x0050
> +#define DPC_OTF_2D_THR_GB	0x0054
> +#define DPC_OTF_2D_THR_B	0x0058
> +#define DPC_OTF_2C_THR_R	0x005c
> +#define DPC_OTF_2C_THR_GR	0x0060
> +#define DPC_OTF_2C_THR_GB	0x0064
> +#define DPC_OTF_2C_THR_B	0x0068
> +#define DPC_OTF_3_SHF		0x006c
> +#define DPC_OTF_3D_THR		0x0070
> +#define DPC_OTF_3D_SLP		0x0074
> +#define DPC_OTF_3D_MIN		0x0078
> +#define DPC_OTF_3D_MAX		0x007c
> +#define DPC_OTF_3C_THR		0x0080
> +#define DPC_OTF_3C_SLP		0x0084
> +#define DPC_OTF_3C_MIN		0x0088
> +#define DPC_OTF_3C_MAX		0x008c
> +
> +/* Lense Shading Correction */
> +#define LSC_VOFT		0x90
> +#define LSC_VA2			0x94
> +#define LSC_VA1			0x98
> +#define LSC_VS			0x9c
> +#define LSC_HOFT		0xa0
> +#define LSC_HA2			0xa4
> +#define LSC_HA1			0xa8
> +#define LSC_HS			0xac
> +#define LSC_GAIN_R		0xb0
> +#define LSC_GAIN_GR		0xb4
> +#define LSC_GAIN_GB		0xb8
> +#define LSC_GAIN_B		0xbc
> +#define LSC_OFT_R		0xc0
> +#define LSC_OFT_GR		0xc4
> +#define LSC_OFT_GB		0xc8
> +#define LSC_OFT_B		0xcc
> +#define LSC_SHF			0xd0
> +#define LSC_MAX			0xd4
> +
> +/* Noise Filter 1. Ofsets from start address given */
> +#define D2F_1ST			0xd8
> +#define D2F_EN			0x0
> +#define D2F_TYP			0x4
> +#define D2F_THR			0x8
> +#define D2F_STR			0x28
> +#define D2F_SPR			0x48
> +#define D2F_EDG_MIN		0x68
> +#define D2F_EDG_MAX		0x6c
> +
> +/* Noise Filter 2 */
> +#define D2F_2ND			0x148
> +
> +/* GIC */
> +#define GIC_EN			0x1b8
> +#define GIC_TYP			0x1bc
> +#define GIC_GAN			0x1c0
> +#define GIC_NFGAN		0x1c4
> +#define GIC_THR			0x1c8
> +#define GIC_SLP			0x1cc
> +
> +/* White Balance */
> +#define WB2_OFT_R		0x1d0
> +#define WB2_OFT_GR		0x1d4
> +#define WB2_OFT_GB		0x1d8
> +#define WB2_OFT_B		0x1dc
> +#define WB2_WGN_R		0x1e0
> +#define WB2_WGN_GR		0x1e4
> +#define WB2_WGN_GB		0x1e8
> +#define WB2_WGN_B		0x1ec
> +
> +/* CFA interpolation */
> +#define CFA_MODE		0x1f0
> +#define CFA_2DIR_HPF_THR	0x1f4
> +#define CFA_2DIR_HPF_SLP	0x1f8
> +#define CFA_2DIR_MIX_THR	0x1fc
> +#define CFA_2DIR_MIX_SLP	0x200
> +#define CFA_2DIR_DIR_THR	0x204
> +#define CFA_2DIR_DIR_SLP	0x208
> +#define CFA_2DIR_NDWT		0x20c
> +#define CFA_MONO_HUE_FRA	0x210
> +#define CFA_MONO_EDG_THR	0x214
> +#define CFA_MONO_THR_MIN	0x218
> +#define CFA_MONO_THR_SLP	0x21c
> +#define CFA_MONO_SLP_MIN	0x220
> +#define CFA_MONO_SLP_SLP	0x224
> +#define CFA_MONO_LPWT		0x228
> +
> +/* RGB to RGB conversiona - 1st */
> +#define RGB1_MUL_BASE		0x22c
> +/* Offsets from base */
> +#define RGB_MUL_RR		0x0
> +#define RGB_MUL_GR		0x4
> +#define RGB_MUL_BR		0x8
> +#define RGB_MUL_RG		0xc
> +#define RGB_MUL_GG		0x10
> +#define RGB_MUL_BG		0x14
> +#define RGB_MUL_RB		0x18
> +#define RGB_MUL_GB		0x1c
> +#define RGB_MUL_BB		0x20
> +#define RGB_OFT_OR		0x24
> +#define RGB_OFT_OG		0x28
> +#define RGB_OFT_OB		0x2c
> +
> +/* Gamma */
> +#define GMM_CFG			0x25c
> +
> +/* RGB to RGB conversiona - 2nd */
> +#define RGB2_MUL_BASE		0x260
> +
> +/* 3D LUT */
> +#define D3LUT_EN		0x290
> +
> +/* RGB to YUV(YCbCr) conversion */
> +#define YUV_ADJ			0x294
> +#define YUV_MUL_RY		0x298
> +#define YUV_MUL_GY		0x29c
> +#define YUV_MUL_BY		0x2a0
> +#define YUV_MUL_RCB		0x2a4
> +#define YUV_MUL_GCB		0x2a8
> +#define YUV_MUL_BCB		0x2ac
> +#define YUV_MUL_RCR		0x2b0
> +#define YUV_MUL_GCR		0x2b4
> +#define YUV_MUL_BCR		0x2b8
> +#define YUV_OFT_Y		0x2bc
> +#define YUV_OFT_CB		0x2c0
> +#define YUV_OFT_CR		0x2c4
> +#define YUV_PHS			0x2c8
> +
> +/* Global Brightness and Contrast */
> +#define GBCE_EN			0x2cc
> +#define GBCE_TYP		0x2d0
> +
> +/* Edge Enhancer */
> +#define YEE_EN			0x2d4
> +#define YEE_TYP			0x2d8
> +#define YEE_SHF			0x2dc
> +#define YEE_MUL_00		0x2e0
> +#define YEE_MUL_01		0x2e4
> +#define YEE_MUL_02		0x2e8
> +#define YEE_MUL_10		0x2ec
> +#define YEE_MUL_11		0x2f0
> +#define YEE_MUL_12		0x2f4
> +#define YEE_MUL_20		0x2f8
> +#define YEE_MUL_21		0x2fc
> +#define YEE_MUL_22		0x300
> +#define YEE_THR			0x304
> +#define YEE_E_GAN		0x308
> +#define YEE_E_THR1		0x30c
> +#define YEE_E_THR2		0x310
> +#define YEE_G_GAN		0x314
> +#define YEE_G_OFT		0x318
> +
> +/* Chroma Artifact Reduction */
> +#define CAR_EN			0x31c
> +#define CAR_TYP			0x320
> +#define CAR_SW			0x324
> +#define CAR_HPF_TYP		0x328
> +#define CAR_HPF_SHF		0x32c
> +#define	CAR_HPF_THR		0x330
> +#define CAR_GN1_GAN		0x334
> +#define CAR_GN1_SHF		0x338
> +#define CAR_GN1_MIN		0x33c
> +#define CAR_GN2_GAN		0x340
> +#define CAR_GN2_SHF		0x344
> +#define CAR_GN2_MIN		0x348
> +
> +/* Chroma Gain Suppression */
> +#define CGS_EN			0x34c
> +#define CGS_GN1_L_THR		0x350
> +#define CGS_GN1_L_GAN		0x354
> +#define CGS_GN1_L_SHF		0x358
> +#define CGS_GN1_L_MIN		0x35c
> +#define CGS_GN1_H_THR		0x360
> +#define CGS_GN1_H_GAN		0x364
> +#define CGS_GN1_H_SHF		0x368
> +#define CGS_GN1_H_MIN		0x36c
> +#define CGS_GN2_L_THR		0x370
> +#define CGS_GN2_L_GAN		0x374
> +#define CGS_GN2_L_SHF		0x378
> +#define CGS_GN2_L_MIN		0x37c
> +
> +/* Resizer */
> +#define RSZ_SRC_EN		0x0
> +#define RSZ_SRC_MODE		0x4
> +#define RSZ_SRC_FMT0		0x8
> +#define RSZ_SRC_FMT1		0xc
> +#define RSZ_SRC_VPS		0x10
> +#define RSZ_SRC_VSZ		0x14
> +#define RSZ_SRC_HPS		0x18
> +#define RSZ_SRC_HSZ		0x1c
> +#define RSZ_DMA_RZA		0x20
> +#define RSZ_DMA_RZB		0x24
> +#define RSZ_DMA_STA		0x28
> +#define RSZ_GCK_MMR		0x2c
> +#define RSZ_RESERVED0		0x30
> +#define RSZ_GCK_SDR		0x34
> +#define RSZ_IRQ_RZA		0x38
> +#define RSZ_IRQ_RZB		0x3c
> +#define RSZ_YUV_Y_MIN		0x40
> +#define RSZ_YUV_Y_MAX		0x44
> +#define RSZ_YUV_C_MIN		0x48
> +#define RSZ_YUV_C_MAX		0x4c
> +#define RSZ_YUV_PHS		0x50
> +#define RSZ_SEQ			0x54
> +
> +/* Resizer Rescale Parameters */
> +#define RSZ_EN_A		0x58
> +#define RSZ_EN_B		0xe8
> +/* offset of the registers to be added with base register of
> +   either RSZ0 or RSZ1
> +*/
> +#define RSZ_MODE		0x4
> +#define RSZ_420			0x8
> +#define RSZ_I_VPS		0xc
> +#define RSZ_I_HPS		0x10
> +#define RSZ_O_VSZ		0x14
> +#define RSZ_O_HSZ		0x18
> +#define RSZ_V_PHS_Y		0x1c
> +#define RSZ_V_PHS_C		0x20
> +#define RSZ_V_DIF		0x24
> +#define RSZ_V_TYP		0x28
> +#define RSZ_V_LPF		0x2c
> +#define RSZ_H_PHS		0x30
> +#define RSZ_H_PHS_ADJ		0x34
> +#define RSZ_H_DIF		0x38
> +#define RSZ_H_TYP		0x3c
> +#define RSZ_H_LPF		0x40
> +#define RSZ_DWN_EN		0x44
> +#define RSZ_DWN_AV		0x48
> +
> +/* Resizer RGB Conversion Parameters */
> +#define RSZ_RGB_EN		0x4c
> +#define RSZ_RGB_TYP		0x50
> +#define RSZ_RGB_BLD		0x54
> +
> +/* Resizer External Memory Parameters */
> +#define RSZ_SDR_Y_BAD_H		0x58
> +#define RSZ_SDR_Y_BAD_L		0x5c
> +#define RSZ_SDR_Y_SAD_H		0x60
> +#define RSZ_SDR_Y_SAD_L		0x64
> +#define RSZ_SDR_Y_OFT		0x68
> +#define RSZ_SDR_Y_PTR_S		0x6c
> +#define RSZ_SDR_Y_PTR_E		0x70
> +#define RSZ_SDR_C_BAD_H		0x74
> +#define RSZ_SDR_C_BAD_L		0x78
> +#define RSZ_SDR_C_SAD_H		0x7c
> +#define RSZ_SDR_C_SAD_L		0x80
> +#define RSZ_SDR_C_OFT		0x84
> +#define RSZ_SDR_C_PTR_S		0x88
> +#define RSZ_SDR_C_PTR_E		0x8c
> +
> +/* Macro for resizer */
> +#define IPIPE_RESIZER_A(i)	(RSZ_IOBASE_VADDR + RSZ_EN_A + i)
> +#define IPIPE_RESIZER_B(i)	(RSZ_IOBASE_VADDR + RSZ_EN_B + i)
> +
> +#define RSZ_YUV_Y_MIN		0x40
> +#define RSZ_YUV_Y_MAX		0x44
> +#define RSZ_YUV_C_MIN		0x48
> +#define RSZ_YUV_C_MAX		0x4c
> +
> +#define IPIPE_GCK_MMR_DEFAULT	1
> +#define IPIPE_GCK_PIX_DEFAULT	0xe
> +#define RSZ_GCK_MMR_DEFAULT	1
> +#define RSZ_GCK_SDR_DEFAULT	1
> +
> +/* LUTDPC */
> +#define LUTDPC_TBL_256_EN	0
> +#define LUTDPC_INF_TBL_EN	1
> +#define LUT_DPC_START_ADDR	0
> +#define LUT_DPC_H_POS_MASK	0x1fff
> +#define LUT_DPC_V_POS_MASK	0x1fff
> +#define LUT_DPC_V_POS_SHIFT	13
> +#define LUT_DPC_CORR_METH_SHIFT	26
> +#define LUT_DPC_MAX_SIZE	256
> +#define LUT_DPC_SIZE_MASK	0x3ff
> +
> +/* OTFDPC */
> +#define OTFDPC_DPC2_THR_MASK	0xfff
> +#define OTF_DET_METHOD_SHIFT	1
> +#define OTF_DPC3_0_SHF_MASK	3
> +#define OTF_DPC3_0_THR_SHIFT	6
> +#define OTF_DPC3_0_THR_MASK	0x3f
> +#define OTF_DPC3_0_SLP_MASK	0x3f
> +#define OTF_DPC3_0_DET_MASK	0xfff
> +#define OTF_DPC3_0_CORR_MASK	0xfff
> +
> +/* NF (D2F) */
> +#define D2F_SPR_VAL_MASK		0x1f
> +#define D2F_SPR_VAL_SHIFT		0
> +#define D2F_SHFT_VAL_MASK		3
> +#define D2F_SHFT_VAL_SHIFT		5
> +#define D2F_SAMPLE_METH_SHIFT		7
> +#define D2F_APPLY_LSC_GAIN_SHIFT	8
> +#define D2F_USE_SPR_REG_VAL		0
> +#define D2F_STR_VAL_MASK		0x1f
> +#define D2F_THR_VAL_MASK		0x3ff
> +#define D2F_EDGE_DET_THR_MASK		0x7ff
> +
> +/* Green Imbalance Correction */
> +#define GIC_TYP_SHIFT			0
> +#define GIC_THR_SEL_SHIFT		1
> +#define	GIC_APPLY_LSC_GAIN_SHIFT	2
> +#define GIC_GAIN_MASK			0xff
> +#define GIC_THR_MASK			0xfff
> +#define GIC_SLOPE_MASK			0xfff
> +#define GIC_NFGAN_INT_MASK		7
> +#define GIC_NFGAN_DECI_MASK		0x1f
> +
> +/* WB */
> +#define WB_OFFSET_MASK			0xfff
> +#define WB_GAIN_INT_MASK		0xf
> +#define WB_GAIN_DECI_MASK		0x1ff
> +
> +/* CFA */
> +#define CFA_HPF_THR_2DIR_MASK		0x1fff
> +#define CFA_HPF_SLOPE_2DIR_MASK		0x3ff
> +#define CFA_HPF_MIX_THR_2DIR_MASK	0x1fff
> +#define CFA_HPF_MIX_SLP_2DIR_MASK	0x3ff
> +#define CFA_DIR_THR_2DIR_MASK		0x3ff
> +#define CFA_DIR_SLP_2DIR_MASK		0x7f
> +#define CFA_ND_WT_2DIR_MASK		0x3f
> +#define CFA_DAA_HUE_FRA_MASK		0x3f
> +#define CFA_DAA_EDG_THR_MASK		0xff
> +#define CFA_DAA_THR_MIN_MASK		0x3ff
> +#define CFA_DAA_THR_SLP_MASK		0x3ff
> +#define CFA_DAA_SLP_MIN_MASK		0x3ff
> +#define CFA_DAA_SLP_SLP_MASK		0x3ff
> +#define CFA_DAA_LP_WT_MASK		0x3f
> +
> +/* RGB2RGB */
> +#define RGB2RGB_1_OFST_MASK		0x1fff
> +#define RGB2RGB_1_GAIN_INT_MASK		0xf
> +#define RGB2RGB_GAIN_DECI_MASK		0xff
> +#define RGB2RGB_2_OFST_MASK		0x7ff
> +#define RGB2RGB_2_GAIN_INT_MASK		0x7
> +
> +/* Gamma */
> +#define GAMMA_BYPR_SHIFT		0
> +#define GAMMA_BYPG_SHIFT		1
> +#define GAMMA_BYPB_SHIFT		2
> +#define GAMMA_TBL_SEL_SHIFT		4
> +#define GAMMA_TBL_SIZE_SHIFT		5
> +#define GAMMA_MASK			0x3ff
> +#define GAMMA_SHIFT			10
> +
> +/* 3D LUT */
> +#define D3_LUT_ENTRY_MASK		0x3ff
> +#define D3_LUT_ENTRY_R_SHIFT		20
> +#define D3_LUT_ENTRY_G_SHIFT		10
> +#define D3_LUT_ENTRY_B_SHIFT		0
> +
> +/* Lumina adj */
> +#define	LUM_ADJ_CONTR_SHIFT		0
> +#define	LUM_ADJ_BRIGHT_SHIFT		8
> +
> +/* RGB2YCbCr */
> +#define RGB2YCBCR_OFST_MASK		0x7ff
> +#define RGB2YCBCR_COEF_INT_MASK		0xf
> +#define RGB2YCBCR_COEF_DECI_MASK	0xff
> +
> +/* GBCE */
> +#define GBCE_Y_VAL_MASK			0xff
> +#define GBCE_GAIN_VAL_MASK		0x3ff
> +#define GBCE_ENTRY_SHIFT		10
> +
> +/* Edge Enhancements */
> +#define YEE_HALO_RED_EN_SHIFT		1
> +#define YEE_HPF_SHIFT_MASK		0xf
> +#define YEE_COEF_MASK			0x3ff
> +#define YEE_THR_MASK			0x3f
> +#define YEE_ES_GAIN_MASK		0xfff
> +#define YEE_ES_THR1_MASK		0xfff
> +#define YEE_ENTRY_SHIFT			9
> +#define YEE_ENTRY_MASK			0x1ff
> +
> +/* CAR */
> +#define CAR_MF_THR			0xff
> +#define CAR_SW1_SHIFT			8
> +#define CAR_GAIN1_SHFT_MASK		7
> +#define CAR_GAIN_MIN_MASK		0x1ff
> +#define CAR_GAIN2_SHFT_MASK		0xf
> +#define CAR_HPF_SHIFT_MASK		3
> +
> +/* CGS */
> +#define CAR_SHIFT_MASK			3
> +
> +/* Resizer */
> +#define RSZ_BYPASS_SHIFT		1
> +#define RSZ_SRC_IMG_FMT_SHIFT		1
> +#define RSZ_SRC_Y_C_SEL_SHIFT		2
> +#define IPIPE_RSZ_VPS_MASK		0xffff
> +#define IPIPE_RSZ_HPS_MASK		0xffff
> +#define IPIPE_RSZ_VSZ_MASK		0x1fff
> +#define IPIPE_RSZ_HSZ_MASK		0x1fff
> +#define RSZ_HPS_MASK			0x1fff
> +#define RSZ_VPS_MASK			0x1fff
> +#define RSZ_O_HSZ_MASK			0x1fff
> +#define RSZ_O_VSZ_MASK			0x1fff
> +#define RSZ_V_PHS_MASK			0x3fff
> +#define RSZ_V_DIF_MASK			0x3fff
> +
> +#define RSZA_H_FLIP_SHIFT		0
> +#define RSZA_V_FLIP_SHIFT		1
> +#define RSZB_H_FLIP_SHIFT		2
> +#define RSZB_V_FLIP_SHIFT		3
> +#define RSZ_A				0
> +#define RSZ_B				1
> +#define RSZ_CEN_SHIFT			1
> +#define RSZ_YEN_SHIFT			0
> +#define RSZ_TYP_Y_SHIFT			0
> +#define RSZ_TYP_C_SHIFT			1
> +#define RSZ_LPF_INT_MASK		0x3f
> +#define RSZ_LPF_INT_MASK		0x3f
> +#define RSZ_LPF_INT_C_SHIFT		6
> +#define RSZ_H_PHS_MASK			0x3fff
> +#define RSZ_H_DIF_MASK			0x3fff
> +#define RSZ_DIFF_DOWN_THR		256
> +#define RSZ_DWN_SCALE_AV_SZ_V_SHIFT	3
> +#define RSZ_DWN_SCALE_AV_SZ_MASK	7
> +#define RSZ_RGB_MSK1_SHIFT		2
> +#define RSZ_RGB_MSK0_SHIFT		1
> +#define RSZ_RGB_TYP_SHIFT		0
> +#define RSZ_RGB_ALPHA_MASK		0xff
> +
> +static inline u32 regr_ip(u32 offset)
> +{
> +	return readl(IPIPE_IOBASE_VADDR + offset);
> +}
> +
> +static inline u32 regw_ip(u32 val, u32 offset)
> +{
> +	writel(val, IPIPE_IOBASE_VADDR + offset);
> +
> +	return val;

Is it useful to return the written value? It's the same as the first 
argument in any case. All I can think of is a funny way of assigning 
that value somewhere, but that might not look as good as just doing the 
assignment without this function.

> +}
> +
> +static inline u32 r_ip_table(u32 offset)
> +{
> +	return readl(IPIPE_INT_TABLE_IOBASE_VADDR + offset);
> +}
> +
> +static inline u32 w_ip_table(u32 val, u32 offset)
> +{
> +	writel(val, IPIPE_INT_TABLE_IOBASE_VADDR + offset);
> +
> +	return val;
> +}
> +
> +static inline u32 regr_rsz(u32 offset)
> +{
> +	return readl(RSZ_IOBASE_VADDR + offset);
> +}
> +
> +static inline u32 regw_rsz(u32 val, u32 offset)
> +{
> +	writel(val, RSZ_IOBASE_VADDR + offset);
> +
> +	return val;
> +}
> +
> +#endif  /* End of #ifdef _DM365_IPIPE_HW_H */
>

Kind regards,

-- 
Sakari Ailus
sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 00/14] Media Controller capture driver for DM365
  2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
                   ` (13 preceding siblings ...)
  2012-09-14 12:46 ` [PATCH 14/14] [media] davinci: vpfe: Add documentation Prabhakar Lad
@ 2012-09-23 15:16 ` Sakari Ailus
  2012-09-24  4:49   ` Prabhakar Lad
  14 siblings, 1 reply; 23+ messages in thread
From: Sakari Ailus @ 2012-09-23 15:16 UTC (permalink / raw)
  To: Prabhakar Lad; +Cc: LMML, LKML, Mauro Carvalho Chehab, DLOS, Lad, Prabhakar

Hi Prabhakar,

Prabhakar Lad wrote:
> From: Lad, Prabhakar <prabhakar.lad@ti.com>
>
> This patch set adds media controller based capture driver for
> DM365.

Thanks for the set. Do you happen to have an updated version of the same 
documentation you posted to the list a while ago?

Kind regards,

-- 
Sakari Ailus
sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 00/14] Media Controller capture driver for DM365
  2012-09-23 15:16 ` [PATCH 00/14] Media Controller capture driver for DM365 Sakari Ailus
@ 2012-09-24  4:49   ` Prabhakar Lad
  0 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-24  4:49 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: LMML, LKML, Mauro Carvalho Chehab, DLOS, Lad, Prabhakar, Manjunath Hadli

Hi Sakari,

On Sun, Sep 23, 2012 at 8:46 PM, Sakari Ailus <sakari.ailus@iki.fi> wrote:
> Hi Prabhakar,
>
>
> Prabhakar Lad wrote:
>>
>> From: Lad, Prabhakar <prabhakar.lad@ti.com>
>>
>> This patch set adds media controller based capture driver for
>> DM365.
>
>
> Thanks for the set. Do you happen to have an updated version of the same
> documentation you posted to the list a while ago?
>
Yes I have included the documentation patch in same series.
'Documentation/video4linux/davinci-vpfe-mc.txt' is the one
which contains the documentation.

Regards,
--Prabhakar Lad

> Kind regards,
>
> --
> Sakari Ailus
> sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 02/14] davinci: vpfe: add IPIPE hardware layer support
  2012-09-23 14:36   ` Sakari Ailus
@ 2012-09-24  4:59     ` Prabhakar Lad
  0 siblings, 0 replies; 23+ messages in thread
From: Prabhakar Lad @ 2012-09-24  4:59 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: LMML, LKML, Mauro Carvalho Chehab, DLOS, Manjunath Hadli, Lad, Prabhakar

Hi Sakari,

Thanks for the review.

On Sun, Sep 23, 2012 at 8:06 PM, Sakari Ailus <sakari.ailus@iki.fi> wrote:
> Hi Prabhakar,
>
> Thanks for the patchset! I've got a few comments below.
>
>
> Prabhakar Lad wrote:
>>
>> From: Manjunath Hadli <manjunath.hadli@ti.com>
>>
>> add dm365 IPIPE hardware support. IPIPE is the hardware IP which
>> implements the functionality required for resizer, previewer and
>> the associated feature support. This is built along with the vpfe
>> driver, and implements hardware setup including coeffcient
>> programming for various hardware filters, gamma, cfa and clock
>> enable.
>>
>> Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
>> Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
>> ---
>>   drivers/media/platform/davinci/dm365_ipipe_hw.c |  936
>> +++++++++++++++++++++++
>>   drivers/media/platform/davinci/dm365_ipipe_hw.h |  538 +++++++++++++
>>   2 files changed, 1474 insertions(+), 0 deletions(-)
>>   create mode 100644 drivers/media/platform/davinci/dm365_ipipe_hw.c
>>   create mode 100644 drivers/media/platform/davinci/dm365_ipipe_hw.h
>>
>> diff --git a/drivers/media/platform/davinci/dm365_ipipe_hw.c
>> b/drivers/media/platform/davinci/dm365_ipipe_hw.c
>> new file mode 100644
>> index 0000000..4ce6d95
>> --- /dev/null
>> +++ b/drivers/media/platform/davinci/dm365_ipipe_hw.c
>> @@ -0,0 +1,936 @@
>> +/*
>> + * Copyright (C) 2012 Texas Instruments 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 version 2.
>> + *
>> + * 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
>> + *
>> + * Contributors:
>> + *      Manjunath Hadli <manjunath.hadli@ti.com>
>> + *      Prabhakar Lad <prabhakar.lad@ti.com>
>> + */
>> +
>> +#include <linux/errno.h>
>> +#include <linux/delay.h>
>> +#include <linux/device.h>
>> +#include <linux/v4l2-mediabus.h>
>> +
>> +#include "dm365_ipipe.h"
>> +#include "dm3xx_ipipeif.h"
>> +#include "dm365_ipipe_hw.h"
>> +
>> +static void ipipe_clock_enable(void)
>> +{
>> +       /* enable IPIPE MMR for register write access */
>> +       regw_ip(IPIPE_GCK_MMR_DEFAULT, IPIPE_GCK_MMR);
>> +       /* enable the clock wb,cfa,dfc,d2f,pre modules */
>> +       regw_ip(IPIPE_GCK_PIX_DEFAULT, IPIPE_GCK_PIX);
>> +       /* enable RSZ MMR for register write access */
>> +}
>> +
>> +/* Set input channel format to either 420 Y or C format */
>> +void rsz_set_in_pix_format(unsigned char y_c)
>> +{
>> +       u32 val;
>> +
>> +       val = regr_rsz(RSZ_SRC_FMT1);
>> +       val |= y_c & 1;
>> +       regw_rsz(val, RSZ_SRC_FMT1);
>> +}
>> +
>> +static void rsz_set_common_params(struct ipipe_params *params)
>> +{
>> +       struct rsz_common_params *rsz_common = &params->rsz_common;
>> +       u32 val;
>> +
>> +       /* Set mode */
>> +       regw_rsz(params->ipipe_mode, RSZ_SRC_MODE);
>> +
>> +       /* data source selection  and bypass */
>> +       val = (rsz_common->passthrough << RSZ_BYPASS_SHIFT) |
>> +               rsz_common->source;
>> +
>> +       regw_rsz(val, RSZ_SRC_FMT0);
>> +       val = regr_rsz(RSZ_SRC_MODE);
>
>
> val is assigned but there's no need to.
>
Agreed.
>
>> +       /* src image selection */
>> +       val = (rsz_common->raw_flip & 1) |
>> +               (rsz_common->src_img_fmt << RSZ_SRC_IMG_FMT_SHIFT) |
>> +               ((rsz_common->y_c & 1) << RSZ_SRC_Y_C_SEL_SHIFT);
>> +
>> +       regw_rsz(val, RSZ_SRC_FMT1);
>> +       regw_rsz(rsz_common->vps & IPIPE_RSZ_VPS_MASK, RSZ_SRC_VPS);
>> +       regw_rsz(rsz_common->hps & IPIPE_RSZ_HPS_MASK, RSZ_SRC_HPS);
>> +       regw_rsz(rsz_common->vsz & IPIPE_RSZ_VSZ_MASK, RSZ_SRC_VSZ);
>> +       regw_rsz(rsz_common->hsz & IPIPE_RSZ_HSZ_MASK, RSZ_SRC_HSZ);
>> +       regw_rsz(rsz_common->yuv_y_min, RSZ_YUV_Y_MIN);
>> +       regw_rsz(rsz_common->yuv_y_max, RSZ_YUV_Y_MAX);
>> +       regw_rsz(rsz_common->yuv_c_min, RSZ_YUV_C_MIN);
>> +       regw_rsz(rsz_common->yuv_c_max, RSZ_YUV_C_MAX);
>> +       /* chromatic position */
>> +       regw_rsz(rsz_common->out_chr_pos, RSZ_YUV_PHS);
>> +       val = regr_rsz(RSZ_SRC_MODE);
>
>
> Same here.
>
Ok.
>
>> +}
>> +
>> +static void rsz_set_rsz_regs(unsigned int rsz_id, struct ipipe_params
>> *params)
>> +{
>> +       struct ipipe_rsz_rescale_param *rsc_params;
>> +       struct ipipe_ext_mem_param *ext_mem;
>> +       struct ipipe_rsz_resize2rgb *rgb;
>> +       u32 reg_base;
>> +       u32 val;
>> +
>> +       val = regr_rsz(RSZ_SEQ);
>
>
> And here.
>
>
>> +       rsc_params = &params->rsz_rsc_param[rsz_id];
>> +       rgb = &params->rsz2rgb[rsz_id];
>> +       ext_mem = &params->ext_mem_param[rsz_id];
>> +
>> +       if (rsz_id == RSZ_A) {
>> +               val = rsc_params->h_flip << RSZA_H_FLIP_SHIFT;
>> +               val |= rsc_params->v_flip << RSZA_V_FLIP_SHIFT;
>> +               reg_base = RSZ_EN_A;
>> +       } else {
>> +               val = rsc_params->h_flip << RSZB_H_FLIP_SHIFT;
>> +               val |= rsc_params->v_flip << RSZB_V_FLIP_SHIFT;
>> +               reg_base = RSZ_EN_B;
>> +       }
>> +       /* update flip settings */
>> +       regw_rsz(val, RSZ_SEQ);
>> +
>> +       regw_rsz(rsc_params->mode, reg_base + RSZ_MODE);
>> +       val = (rsc_params->cen << RSZ_CEN_SHIFT) | rsc_params->yen;
>> +       regw_rsz(val, reg_base + RSZ_420);
>> +       regw_rsz(rsc_params->i_vps & RSZ_VPS_MASK, reg_base + RSZ_I_VPS);
>> +       regw_rsz(rsc_params->i_hps & RSZ_HPS_MASK, reg_base + RSZ_I_HPS);
>> +       regw_rsz(rsc_params->o_vsz & RSZ_O_VSZ_MASK, reg_base +
>> RSZ_O_VSZ);
>> +       regw_rsz(rsc_params->o_hsz & RSZ_O_HSZ_MASK, reg_base +
>> RSZ_O_HSZ);
>> +       regw_rsz(rsc_params->v_phs_y & RSZ_V_PHS_MASK, reg_base +
>> RSZ_V_PHS_Y);
>> +       regw_rsz(rsc_params->v_phs_c & RSZ_V_PHS_MASK, reg_base +
>> RSZ_V_PHS_C);
>> +       /* keep this additional adjustment to zero for now */
>> +       regw_rsz(rsc_params->v_dif & RSZ_V_DIF_MASK, reg_base +
>> RSZ_V_DIF);
>> +
>> +       val = (rsc_params->v_typ_y & 1) | ((rsc_params->v_typ_c & 1) <<
>> +                                                       RSZ_TYP_C_SHIFT);
>> +       regw_rsz(val, reg_base + RSZ_V_TYP);
>> +
>> +       val = (rsc_params->v_lpf_int_y & RSZ_LPF_INT_MASK) |
>> +                       ((rsc_params->v_lpf_int_c & RSZ_LPF_INT_MASK) <<
>> +                               RSZ_LPF_INT_C_SHIFT);
>> +       regw_rsz(val, reg_base + RSZ_V_LPF);
>> +
>> +       regw_rsz(rsc_params->h_phs & RSZ_H_PHS_MASK, reg_base +
>> RSZ_H_PHS);
>> +       regw_rsz(0, reg_base + RSZ_H_PHS_ADJ);
>> +       regw_rsz(rsc_params->h_dif & RSZ_H_DIF_MASK, reg_base +
>> RSZ_H_DIF);
>> +       val = (rsc_params->h_typ_y & 1) | ((rsc_params->h_typ_c & 1) <<
>> +                                                       RSZ_TYP_C_SHIFT);
>> +       regw_rsz(val, reg_base + RSZ_H_TYP);
>> +       val = (rsc_params->h_lpf_int_y & RSZ_LPF_INT_MASK) |
>> +                ((rsc_params->h_lpf_int_c & RSZ_LPF_INT_MASK) <<
>> +                RSZ_LPF_INT_C_SHIFT);
>> +       regw_rsz(val, reg_base + RSZ_H_LPF);
>> +
>> +       regw_rsz(rsc_params->dscale_en & 1, reg_base + RSZ_DWN_EN);
>> +       val = rsc_params->h_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK;
>> +       val |= (rsc_params->v_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK) <<
>> +                                 RSZ_DWN_SCALE_AV_SZ_V_SHIFT;
>> +       regw_rsz(val, reg_base + RSZ_DWN_AV);
>> +
>> +       /* setting rgb conversion parameters */
>> +       regw_rsz(rgb->rgb_en, reg_base + RSZ_RGB_EN);
>> +       val = (rgb->rgb_typ << RSZ_RGB_TYP_SHIFT) |
>> +                (rgb->rgb_msk0 << RSZ_RGB_MSK0_SHIFT) |
>> +                (rgb->rgb_msk1 << RSZ_RGB_MSK1_SHIFT);
>> +       regw_rsz(val, reg_base + RSZ_RGB_TYP);
>> +       regw_rsz(rgb->rgb_alpha_val & RSZ_RGB_ALPHA_MASK,
>> +               reg_base + RSZ_RGB_BLD);
>> +
>> +       /* setting external memory parameters */
>> +       regw_rsz(ext_mem->rsz_sdr_oft_y, reg_base + RSZ_SDR_Y_OFT);
>> +       regw_rsz(ext_mem->rsz_sdr_ptr_s_y, reg_base + RSZ_SDR_Y_PTR_S);
>> +       regw_rsz(ext_mem->rsz_sdr_ptr_e_y, reg_base + RSZ_SDR_Y_PTR_E);
>> +       regw_rsz(ext_mem->rsz_sdr_oft_c, reg_base + RSZ_SDR_C_OFT);
>> +       regw_rsz(ext_mem->rsz_sdr_ptr_s_c, reg_base + RSZ_SDR_C_PTR_S);
>> +       regw_rsz((ext_mem->rsz_sdr_ptr_e_c >> 1), reg_base +
>> RSZ_SDR_C_PTR_E);
>> +}
>> +
>> +/*set the registers of either RSZ0 or RSZ1 */
>> +static void ipipe_setup_resizer(struct ipipe_params *params)
>> +{
>> +       /* enable MMR gate to write to Resizer */
>> +       regw_rsz(1, RSZ_GCK_MMR);
>> +
>> +       /* Enable resizer if it is not in bypass mode */
>> +       if (params->rsz_common.passthrough)
>> +               regw_rsz(0, RSZ_GCK_SDR);
>> +       else
>> +               regw_rsz(1, RSZ_GCK_SDR);
>> +
>> +       rsz_set_common_params(params);
>> +
>> +       regw_rsz(params->rsz_en[RSZ_A], RSZ_EN_A);
>> +       if (params->rsz_en[RSZ_A])
>> +               /*setting rescale parameters */
>> +               rsz_set_rsz_regs(RSZ_A, params);
>> +
>> +       regw_rsz(params->rsz_en[RSZ_B], RSZ_EN_B);
>> +       if (params->rsz_en[RSZ_B])
>> +               rsz_set_rsz_regs(RSZ_B, params);
>> +
>> +       regr_rsz(RSZ_SRC_MODE);
>> +}
>> +
>> +/*
>> + * ipipe_hw_setup() - Performs hardware setup of ipipe.
>> + */
>> +int ipipe_hw_setup(struct ipipe_params *config)
>> +{
>> +       u32 data_format;
>> +       u32 val;
>> +
>> +       if (!config) {
>> +               pr_err("ipipe_hw_setup- Invalid config\n");
>> +               return -EINVAL;
>> +       }
>
>
> The function is only used byt the driver internally, so the check should be
> done elsewhere. If you want to check it also here, you can use BUG_ON().
>
Ok.
>
>> +       if (ipipeif_hw_setup(&config->ipipeif_param, DM365) < 0) {
>> +               pr_err("ipipe_hw_setup- Failed to configure IPIPEIF");
>> +               return -EINVAL;
>> +       }
>> +
>> +       /* enable clock to IPIPE */
>> +       vpss_enable_clock(VPSS_IPIPE_CLOCK, 1);
>> +       /* enable clock to MMR and modules before writting
>> +        * to ipipe registers
>> +        */
>> +       ipipe_clock_enable();
>> +
>> +       if (config->rsz_common.source == IPIPEIF_DATA) {
>> +               /* we need to skip configuring IPIPE */
>> +               regw_ip(0, IPIPE_SRC_EN);
>> +       } else {
>> +               /* enable ipipe mode to either one shot or continuous */
>> +               val = config->ipipe_mode;
>> +               regw_ip(val, IPIPE_SRC_MODE);
>
>
> You can remove val.
>
Ok.
>
>> +               data_format = config->ipipe_dpaths_fmt;
>> +               regw_ip(data_format, IPIPE_SRC_FMT);
>> +               /* set size */
>> +               regw_ip(config->ipipe_vps & IPIPE_RSZ_VPS_MASK,
>> IPIPE_SRC_VPS);
>> +               regw_ip(config->ipipe_hps & IPIPE_RSZ_HPS_MASK,
>> IPIPE_SRC_HPS);
>> +               regw_ip(config->ipipe_vsz & IPIPE_RSZ_VSZ_MASK,
>> IPIPE_SRC_VSZ);
>> +               regw_ip(config->ipipe_hsz & IPIPE_RSZ_HSZ_MASK,
>> IPIPE_SRC_HSZ);
>> +
>> +               if (data_format == IPIPE_RAW2YUV ||
>> +                                       data_format == IPIPE_RAW2RAW)
>> +                       regw_ip(config->ipipe_colpat, IPIPE_SRC_COL);
>> +       }
>> +
>> +       ipipe_setup_resizer(config);
>> +
>> +       return 0;
>> +}
>> +
>> +static void rsz_set_y_address(unsigned int address, unsigned int offset)
>> +{
>> +       u32 val;
>> +
>> +       val = address & SET_LOW_ADD;
>> +       regw_rsz(val, offset + RSZ_SDR_Y_BAD_L);
>> +       regw_rsz(val, offset + RSZ_SDR_Y_SAD_L);
>> +       val = (address & SET_HIGH_ADD) >> 16;
>> +       regw_rsz(val, offset + RSZ_SDR_Y_BAD_H);
>> +       regw_rsz(val, offset + RSZ_SDR_Y_SAD_H);
>> +}
>> +
>> +static void rsz_set_c_address(unsigned int address, unsigned int offset)
>> +{
>> +       u32 val;
>> +
>> +       val = address & SET_LOW_ADD;
>> +
>> +       regw_rsz(val, offset + RSZ_SDR_C_BAD_L);
>> +       regw_rsz(val, offset + RSZ_SDR_C_SAD_L);
>> +       val = (address & SET_HIGH_ADD) >> 16;
>> +       regw_rsz(val, offset + RSZ_SDR_C_BAD_H);
>> +       regw_rsz(val, offset + RSZ_SDR_C_SAD_H);
>> +}
>> +
>> +/* Assume we get a valid params ptr and resize_no set to RSZ_A
>> + * or RSZ_B. This could be called in the interrupt context and
>> + * must be efficient
>> + */
>> +void rsz_set_output_address(struct ipipe_params *params,
>> +                          int resize_no, unsigned int address)
>> +{
>> +       unsigned int rsz_start_add;
>> +       unsigned int val;
>> +
>> +       struct ipipe_ext_mem_param *mem_param =
>> +               &params->ext_mem_param[resize_no];
>> +       struct rsz_common_params *rsz_common =
>> +               &params->rsz_common;
>> +       struct ipipe_rsz_rescale_param *rsc_param =
>> +               &params->rsz_rsc_param[resize_no];
>> +
>> +       if (resize_no == RSZ_A)
>> +               rsz_start_add = RSZ_EN_A;
>> +       else
>> +               rsz_start_add = RSZ_EN_B;
>> +       /* y_c = 0 for y, = 1 for c */
>> +       if (rsz_common->src_img_fmt == RSZ_IMG_420) {
>> +               if (rsz_common->y_c) {
>> +                       /* C channel */
>> +                       val = address + mem_param->flip_ofst_c;
>> +                       rsz_set_c_address(val, rsz_start_add);
>> +               } else {
>> +                       val = address + mem_param->flip_ofst_y;
>> +                       rsz_set_y_address(val, rsz_start_add);
>> +               }
>> +       } else {
>> +               if (rsc_param->cen && rsc_param->yen) {
>> +                       /* 420 */
>> +                       val = address + mem_param->c_offset;
>> +                       val = address + mem_param->c_offset +
>> +                               mem_param->flip_ofst_c;
>
>
> You're overwriting val immediately after assignment above.
>
>
Ok I'll fix it.

>> +                       val += mem_param->user_y_ofst +
>> +                               mem_param->user_c_ofst;
>
>
> This can be combined with the above. There are many similar cases below.
>
Ok.
>
>> +                       if (resize_no == RSZ_B)
>> +                               val +=
>> +                               params->ext_mem_param[RSZ_A].user_y_ofst +
>> +                               params->ext_mem_param[RSZ_A].user_c_ofst;
>> +                       /* set C address */
>> +                       rsz_set_c_address(val, rsz_start_add);
>> +               }
>> +               val = address + mem_param->flip_ofst_y;
>> +               val += mem_param->user_y_ofst;
>> +               if (resize_no == RSZ_B)
>> +                       val += params->ext_mem_param[RSZ_A].user_y_ofst +
>> +                               params->ext_mem_param[RSZ_A].user_c_ofst;
>> +               /* set Y address */
>> +               rsz_set_y_address(val, rsz_start_add);
>> +       }
>> +       /* resizer must be enabled */
>> +       regw_rsz(params->rsz_en[resize_no], rsz_start_add);
>> +
>> +}
>> +
>> +void ipipe_set_lutdpc_regs(struct prev_lutdpc *dpc)
>> +{
>> +       u32 max_tbl_size = LUT_DPC_MAX_SIZE >> 1;
>> +       u32 lut_start_addr = DPC_TB0_START_ADDR;
>> +       u32 val;
>> +       u32 count;
>> +
>> +       ipipe_clock_enable();
>> +       regw_ip(dpc->en, DPC_LUT_EN);
>> +       if (dpc->en != 1)
>> +               return;
>> +
>> +       /* if dpc is enabled */
>> +       val = LUTDPC_TBL_256_EN;
>> +       val |= dpc->repl_white & 1;
>> +       regw_ip(val, DPC_LUT_SEL);
>> +       regw_ip(LUT_DPC_START_ADDR, DPC_LUT_ADR);
>> +       regw_ip(dpc->dpc_size, DPC_LUT_SIZ & LUT_DPC_SIZE_MASK);
>> +
>> +       if (dpc->table == NULL)
>> +               return;
>> +
>> +       for (count = 0; count < dpc->dpc_size; count++) {
>> +               if (count >= max_tbl_size)
>> +                       lut_start_addr = DPC_TB1_START_ADDR;
>> +               val = dpc->table[count].horz_pos & LUT_DPC_H_POS_MASK;
>> +               val |= (dpc->table[count].vert_pos & LUT_DPC_V_POS_MASK)
>> <<
>> +                       LUT_DPC_V_POS_SHIFT;
>> +               val |= dpc->table[count].method <<
>> LUT_DPC_CORR_METH_SHIFT;
>> +               w_ip_table(val, (lut_start_addr +
>> +                                               ((count % max_tbl_size) <<
>> 2)));
>> +       }
>> +}
>> +
>> +static void set_dpc_thresholds(struct prev_otfdpc_2_0 *dpc_thr)
>> +{
>> +       regw_ip((dpc_thr->corr_thr.r & OTFDPC_DPC2_THR_MASK),
>> +               DPC_OTF_2C_THR_R);
>> +       regw_ip((dpc_thr->corr_thr.gr & OTFDPC_DPC2_THR_MASK),
>> +               DPC_OTF_2C_THR_GR);
>> +       regw_ip((dpc_thr->corr_thr.gb & OTFDPC_DPC2_THR_MASK),
>> +               DPC_OTF_2C_THR_GB);
>> +       regw_ip((dpc_thr->corr_thr.b & OTFDPC_DPC2_THR_MASK),
>> +               DPC_OTF_2C_THR_B);
>> +       regw_ip((dpc_thr->det_thr.r & OTFDPC_DPC2_THR_MASK),
>> +               DPC_OTF_2D_THR_R);
>> +       regw_ip((dpc_thr->det_thr.gr & OTFDPC_DPC2_THR_MASK),
>> +               DPC_OTF_2D_THR_GR);
>> +       regw_ip((dpc_thr->det_thr.gb & OTFDPC_DPC2_THR_MASK),
>> +               DPC_OTF_2D_THR_GB);
>> +       regw_ip((dpc_thr->det_thr.b & OTFDPC_DPC2_THR_MASK),
>> +               DPC_OTF_2D_THR_B);
>> +}
>> +
>> +void ipipe_set_otfdpc_regs(struct prev_otfdpc *otfdpc)
>> +{
>> +       struct prev_otfdpc_2_0 *dpc_2_0 = &otfdpc->alg_cfg.dpc_2_0;
>> +       struct prev_otfdpc_3_0 *dpc_3_0 = &otfdpc->alg_cfg.dpc_3_0;
>> +       u32 val;
>> +
>> +       ipipe_clock_enable();
>> +
>> +       regw_ip((otfdpc->en & 1), DPC_OTF_EN);
>> +       if (otfdpc->en != 1)
>
>
> otfdpc->en could be made bool.
>
Ok.
>
>> +               return;
>> +
>> +       /* dpc enabled */
>> +       val = otfdpc->det_method << OTF_DET_METHOD_SHIFT;
>> +       val |= otfdpc->alg;
>> +       regw_ip(val, DPC_OTF_TYP);
>> +       if (otfdpc->det_method == IPIPE_DPC_OTF_MIN_MAX) {
>> +               /* ALG= 0, TYP = 0, DPC_OTF_2D_THR_[x]=0
>> +                * DPC_OTF_2C_THR_[x] = Maximum thresohld
>> +                * MinMax method
>> +                */
>> +               dpc_2_0->det_thr.r = dpc_2_0->det_thr.gb =
>> +               dpc_2_0->det_thr.gr = dpc_2_0->det_thr.b = 0;
>> +               set_dpc_thresholds(dpc_2_0);
>> +               return;
>> +       }
>> +       /* MinMax2 */
>> +       if (otfdpc->alg == IPIPE_OTFDPC_2_0) {
>> +               set_dpc_thresholds(dpc_2_0);
>> +               return;
>> +       }
>> +       regw_ip((dpc_3_0->act_adj_shf & OTF_DPC3_0_SHF_MASK),
>> DPC_OTF_3_SHF);
>> +       /* Detection thresholds */
>> +       regw_ip(((dpc_3_0->det_thr & OTF_DPC3_0_THR_MASK) <<
>> +               OTF_DPC3_0_THR_SHIFT), DPC_OTF_3D_THR);
>> +       regw_ip((dpc_3_0->det_slp & OTF_DPC3_0_SLP_MASK), DPC_OTF_3D_SLP);
>> +       regw_ip((dpc_3_0->det_thr_min & OTF_DPC3_0_DET_MASK),
>> DPC_OTF_3D_MIN);
>> +       regw_ip((dpc_3_0->det_thr_max & OTF_DPC3_0_DET_MASK),
>> DPC_OTF_3D_MAX);
>> +       /* Correction thresholds */
>> +       regw_ip(((dpc_3_0->corr_thr & OTF_DPC3_0_THR_MASK) <<
>> +               OTF_DPC3_0_THR_SHIFT), DPC_OTF_3C_THR);
>> +       regw_ip((dpc_3_0->corr_slp & OTF_DPC3_0_SLP_MASK),
>> DPC_OTF_3C_SLP);
>> +       regw_ip((dpc_3_0->corr_thr_min & OTF_DPC3_0_CORR_MASK),
>> DPC_OTF_3C_MIN);
>> +       regw_ip((dpc_3_0->corr_thr_max & OTF_DPC3_0_CORR_MASK),
>> DPC_OTF_3C_MAX);
>
>
> Extra parenthesis may be removed.
>
Ok.
>
>> +}
>> +
>> +/* 2D Noise filter */
>> +void ipipe_set_d2f_regs(unsigned int id, struct prev_nf *noise_filter)
>> +{
>> +
>> +       u32 offset = D2F_1ST;
>> +       int count;
>> +       u32 val;
>> +
>> +       /* id = 0 , NF1 & id = 1, NF 2 */
>> +       if (id)
>> +               offset = D2F_2ND;
>
>
> You could make id an enum, or create #defines to tell the two noise filters
> apart.
>
>
>> +       ipipe_clock_enable();
>> +       regw_ip(noise_filter->en & 1, offset + D2F_EN);
>> +       if (noise_filter->en != 1)
>
>
> How about making noise_filter->en bool?
>
Can be done.

>
>> +               return;
>> +
>> +       /*noise filter enabled */
>> +       /* Combine all the fields to make D2F_CFG register of IPIPE */
>> +       val = ((noise_filter->spread_val & D2F_SPR_VAL_MASK) <<
>> +                D2F_SPR_VAL_SHIFT) |
>> +                ((noise_filter->shft_val & D2F_SHFT_VAL_MASK) <<
>> +                D2F_SHFT_VAL_SHIFT) |
>> +                (noise_filter->gr_sample_meth <<
>> +                D2F_SAMPLE_METH_SHIFT) |
>> +                ((noise_filter->apply_lsc_gain & 1) <<
>> +                D2F_APPLY_LSC_GAIN_SHIFT) | D2F_USE_SPR_REG_VAL;
>> +
>> +       regw_ip(val, offset + D2F_TYP);
>> +       /* edge detection minimum */
>> +       regw_ip(noise_filter->edge_det_min_thr & D2F_EDGE_DET_THR_MASK,
>> +               offset + D2F_EDG_MIN);
>> +       /* edge detection maximum */
>> +       regw_ip(noise_filter->edge_det_max_thr & D2F_EDGE_DET_THR_MASK,
>> +               offset + D2F_EDG_MAX);
>> +       for (count = 0; count < IPIPE_NF_STR_TABLE_SIZE; count++) {
>> +               regw_ip((noise_filter->str[count] & D2F_STR_VAL_MASK),
>> +                       offset + D2F_STR + count * 4);
>> +
>> +       }
>> +       for (count = 0; count < IPIPE_NF_THR_TABLE_SIZE; count++) {
>> +               regw_ip(noise_filter->thr[count] & D2F_THR_VAL_MASK,
>> +                       offset + D2F_THR + count * 4);
>> +       }
>
>
> Extra braces may be removed above.
>
Ok.
>
>> +}
>> +
>> +#define IPIPE_U8Q5(decimal, integer) \
>> +       (((decimal & 0x1f) | ((integer & 0x7) << 5)))
>> +
>> +/* Green Imbalance Correction */
>> +void ipipe_set_gic_regs(struct prev_gic *gic)
>> +{
>> +       u32 val;
>> +
>> +       ipipe_clock_enable();
>> +       regw_ip(gic->en & 1, GIC_EN);
>> +
>> +       if (!gic->en)
>> +               return;
>> +
>> +       /*gic enabled */
>> +       val = gic->wt_fn_type << GIC_TYP_SHIFT;
>> +       val |= gic->thr_sel << GIC_THR_SEL_SHIFT;
>> +       val |= (gic->apply_lsc_gain & 1) << GIC_APPLY_LSC_GAIN_SHIFT;
>> +       regw_ip(val, GIC_TYP);
>> +       regw_ip(gic->gain & GIC_GAIN_MASK, GIC_GAN);
>> +
>> +       if (gic->gic_alg != IPIPE_GIC_ALG_ADAPT_GAIN) {
>> +               /* Constant Gain. Set threshold to maximum */
>> +               regw_ip(GIC_THR_MASK, GIC_THR);
>> +               return;
>> +       }
>> +
>> +       if (gic->thr_sel == IPIPE_GIC_THR_REG) {
>> +               regw_ip(gic->thr & GIC_THR_MASK, GIC_THR);
>> +               regw_ip(gic->slope & GIC_SLOPE_MASK, GIC_SLP);
>> +       } else {
>> +               /* Use NF thresholds */
>> +               val = IPIPE_U8Q5(gic->nf2_thr_gain.decimal,
>> +                               gic->nf2_thr_gain.integer);
>> +               regw_ip(val, GIC_NFGAN);
>> +       }
>> +}
>> +
>> +#define IPIPE_U13Q9(decimal, integer) \
>> +       (((decimal & 0x1ff) | ((integer & 0xf) << 9)))
>> +/* White balance */
>> +void ipipe_set_wb_regs(struct prev_wb *wb)
>> +{
>> +       u32 val;
>> +
>> +       ipipe_clock_enable();
>> +       /* Ofsets. S12 */
>> +       regw_ip(wb->ofst_r & WB_OFFSET_MASK, WB2_OFT_R);
>> +       regw_ip(wb->ofst_gr & WB_OFFSET_MASK, WB2_OFT_GR);
>> +       regw_ip(wb->ofst_gb & WB_OFFSET_MASK, WB2_OFT_GB);
>> +       regw_ip(wb->ofst_b & WB_OFFSET_MASK, WB2_OFT_B);
>> +
>> +       /* Gains. U13Q9 */
>> +       val = IPIPE_U13Q9(wb->gain_r.decimal, wb->gain_r.integer);
>> +       regw_ip(val, WB2_WGN_R);
>> +       val = IPIPE_U13Q9(wb->gain_gr.decimal, wb->gain_gr.integer);
>> +       regw_ip(val, WB2_WGN_GR);
>> +       val = IPIPE_U13Q9(wb->gain_gb.decimal, wb->gain_gb.integer);
>> +       regw_ip(val, WB2_WGN_GB);
>> +       val = IPIPE_U13Q9(wb->gain_b.decimal, wb->gain_b.integer);
>> +       regw_ip(val, WB2_WGN_B);
>> +}
>> +
>> +/* CFA */
>> +void ipipe_set_cfa_regs(struct prev_cfa *cfa)
>> +{
>> +       ipipe_clock_enable();
>> +       regw_ip(cfa->alg, CFA_MODE);
>> +       regw_ip(cfa->hpf_thr_2dir & CFA_HPF_THR_2DIR_MASK,
>> CFA_2DIR_HPF_THR);
>> +       regw_ip(cfa->hpf_slp_2dir & CFA_HPF_SLOPE_2DIR_MASK,
>> CFA_2DIR_HPF_SLP);
>> +       regw_ip(cfa->hp_mix_thr_2dir & CFA_HPF_MIX_THR_2DIR_MASK,
>> +                       CFA_2DIR_MIX_THR);
>> +       regw_ip(cfa->hp_mix_slope_2dir & CFA_HPF_MIX_SLP_2DIR_MASK,
>> +                       CFA_2DIR_MIX_SLP);
>> +       regw_ip(cfa->dir_thr_2dir & CFA_DIR_THR_2DIR_MASK,
>> CFA_2DIR_DIR_THR);
>> +       regw_ip(cfa->dir_slope_2dir & CFA_DIR_SLP_2DIR_MASK,
>> CFA_2DIR_DIR_SLP);
>> +       regw_ip(cfa->nd_wt_2dir & CFA_ND_WT_2DIR_MASK, CFA_2DIR_NDWT);
>> +       regw_ip(cfa->hue_fract_daa & CFA_DAA_HUE_FRA_MASK,
>> CFA_MONO_HUE_FRA);
>> +       regw_ip(cfa->edge_thr_daa & CFA_DAA_EDG_THR_MASK,
>> CFA_MONO_EDG_THR);
>> +       regw_ip(cfa->thr_min_daa & CFA_DAA_THR_MIN_MASK,
>> CFA_MONO_THR_MIN);
>> +       regw_ip(cfa->thr_slope_daa & CFA_DAA_THR_SLP_MASK,
>> CFA_MONO_THR_SLP);
>> +       regw_ip(cfa->slope_min_daa & CFA_DAA_SLP_MIN_MASK,
>> CFA_MONO_SLP_MIN);
>> +       regw_ip(cfa->slope_slope_daa & CFA_DAA_SLP_SLP_MASK,
>> CFA_MONO_SLP_SLP);
>> +       regw_ip(cfa->lp_wt_daa & CFA_DAA_LP_WT_MASK, CFA_MONO_LPWT);
>> +}
>> +
>> +void ipipe_set_rgb2rgb_regs(unsigned int id, struct prev_rgb2rgb *rgb)
>> +{
>> +       u32 offset_mask = RGB2RGB_1_OFST_MASK;
>> +       u32 offset = RGB1_MUL_BASE;
>> +       u32 integ_mask = 0xf;
>> +       u32 val;
>> +
>> +       ipipe_clock_enable();
>> +
>> +       if (id) {
>> +               /* For second RGB module, gain integer is 3 bits instead
>> +               of 4, offset has 11 bits insread of 13 */
>> +               offset = RGB2_MUL_BASE;
>> +               integ_mask = 0x7;
>> +               offset_mask = RGB2RGB_2_OFST_MASK;
>> +       }
>> +       /* Gains */
>> +       val = (rgb->coef_rr.decimal & 0xff) |
>> +               ((rgb->coef_rr.integer & integ_mask) << 8);
>> +       regw_ip(val, offset + RGB_MUL_RR);
>> +       val = (rgb->coef_gr.decimal & 0xff) |
>> +               ((rgb->coef_gr.integer & integ_mask) << 8);
>> +       regw_ip(val, offset + RGB_MUL_GR);
>> +       val = (rgb->coef_br.decimal & 0xff) |
>> +               ((rgb->coef_br.integer & integ_mask) << 8);
>> +       regw_ip(val, offset + RGB_MUL_BR);
>> +       val = (rgb->coef_rg.decimal & 0xff) |
>> +               ((rgb->coef_rg.integer & integ_mask) << 8);
>> +       regw_ip(val, offset + RGB_MUL_RG);
>> +       val = (rgb->coef_gg.decimal & 0xff) |
>> +               ((rgb->coef_gg.integer & integ_mask) << 8);
>> +       regw_ip(val, offset + RGB_MUL_GG);
>> +       val = (rgb->coef_bg.decimal & 0xff) |
>> +               ((rgb->coef_bg.integer & integ_mask) << 8);
>> +       regw_ip(val, offset + RGB_MUL_BG);
>> +       val = (rgb->coef_rb.decimal & 0xff) |
>> +               ((rgb->coef_rb.integer & integ_mask) << 8);
>> +       regw_ip(val, offset + RGB_MUL_RB);
>> +       val = (rgb->coef_gb.decimal & 0xff) |
>> +               ((rgb->coef_gb.integer & integ_mask) << 8);
>> +       regw_ip(val, offset + RGB_MUL_GB);
>> +       val = (rgb->coef_bb.decimal & 0xff) |
>> +               ((rgb->coef_bb.integer & integ_mask) << 8);
>> +       regw_ip(val, offset + RGB_MUL_BB);
>> +
>> +       /* Offsets */
>> +       regw_ip(rgb->out_ofst_r & offset_mask, offset + RGB_OFT_OR);
>> +       regw_ip(rgb->out_ofst_g & offset_mask, offset + RGB_OFT_OG);
>> +       regw_ip(rgb->out_ofst_b & offset_mask, offset + RGB_OFT_OB);
>> +}
>> +
>> +static void ipipe_update_gamma_tbl(struct ipipe_gamma_entry *table,
>> +                                  int size, u32 addr)
>> +{
>> +       int count;
>> +       u32 val;
>> +
>> +       for (count = 0; count < size; count++) {
>> +               val = table[count].slope & GAMMA_MASK;
>> +               val |= (table[count].offset & GAMMA_MASK) << GAMMA_SHIFT;
>> +               w_ip_table(val, (addr + (count * 4)));
>> +       }
>> +}
>> +
>> +/* Gamma correction */
>> +void ipipe_set_gamma_regs(struct prev_gamma *gamma)
>> +{
>> +       int table_size;
>> +       u32 val;
>> +
>> +       ipipe_clock_enable();
>> +       val = (gamma->bypass_r << GAMMA_BYPR_SHIFT) |
>> +               (gamma->bypass_b << GAMMA_BYPG_SHIFT) |
>> +               (gamma->bypass_g << GAMMA_BYPB_SHIFT) |
>> +               (gamma->tbl_sel << GAMMA_TBL_SEL_SHIFT) |
>> +               (gamma->tbl_size << GAMMA_TBL_SIZE_SHIFT);
>> +
>> +       regw_ip(val, GMM_CFG);
>> +
>> +       if (gamma->tbl_sel != IPIPE_GAMMA_TBL_RAM)
>> +               return;
>> +
>> +       table_size = gamma->tbl_size;
>> +
>> +       if (!gamma->bypass_r && gamma->table_r != NULL) {
>> +               ipipe_update_gamma_tbl(gamma->table_r, table_size,
>> +                                       GAMMA_R_START_ADDR);
>> +       }
>> +       if (!gamma->bypass_b && gamma->table_b != NULL) {
>> +               ipipe_update_gamma_tbl(gamma->table_b, table_size,
>> +                                       GAMMA_B_START_ADDR);
>> +       }
>> +       if (!gamma->bypass_g && gamma->table_g != NULL) {
>> +               ipipe_update_gamma_tbl(gamma->table_g, table_size,
>> +                                       GAMMA_G_START_ADDR);
>> +       }
>
>
> Extra braces may be removed.
>
Ok.
>
>> +}
>> +
>> +/* 3D LUT */
>> +void ipipe_set_3d_lut_regs(struct prev_3d_lut *lut_3d)
>> +{
>> +       struct ipipe_3d_lut_entry *tbl;
>> +       u32 bnk_index;
>> +       u32 tbl_index;
>> +       u32 val;
>> +       u32 i;
>> +
>> +       ipipe_clock_enable();
>> +       regw_ip(lut_3d->en, D3LUT_EN);
>> +
>> +       if (!lut_3d->en)
>> +               return;
>> +
>> +       /* lut_3d enabled */
>> +       if (!lut_3d->table)
>> +               return;
>> +
>> +       /* valied table */
>> +       tbl = lut_3d->table;
>> +       for (i = 0 ; i < MAX_SIZE_3D_LUT; i++) {
>> +               /* Each entry has 0-9 (B), 10-19 (G) and
>> +               20-29 R values */
>> +               val = tbl[i].b & D3_LUT_ENTRY_MASK;
>> +               val |= (tbl[i].g & D3_LUT_ENTRY_MASK) <<
>> +                        D3_LUT_ENTRY_G_SHIFT;
>> +               val |= (tbl[i].r & D3_LUT_ENTRY_MASK) <<
>> +                        D3_LUT_ENTRY_R_SHIFT;
>> +               bnk_index = i % 4;
>> +               tbl_index = i >> 2;
>> +               tbl_index <<= 2;
>> +               if (bnk_index == 0)
>> +                       w_ip_table(val, tbl_index + D3L_TB0_START_ADDR);
>> +               else if (bnk_index == 1)
>> +                       w_ip_table(val, tbl_index + D3L_TB1_START_ADDR);
>> +               else if (bnk_index == 2)
>> +                       w_ip_table(val, tbl_index + D3L_TB2_START_ADDR);
>> +               else
>> +                       w_ip_table(val, tbl_index + D3L_TB3_START_ADDR);
>> +       }
>> +}
>> +
>> +/* Lumina adjustments */
>> +void ipipe_set_lum_adj_regs(struct prev_lum_adj *lum_adj)
>> +{
>> +       u32 val;
>> +
>> +       ipipe_clock_enable();
>> +       /* combine fields of YUV_ADJ to set brightness and contrast */
>> +       val = lum_adj->contrast << LUM_ADJ_CONTR_SHIFT |
>> +                       lum_adj->brightness << LUM_ADJ_BRIGHT_SHIFT;
>> +       regw_ip(val, YUV_ADJ);
>> +}
>> +
>> +#define IPIPE_S12Q8(decimal, integer) \
>> +       (((decimal & 0xff) | ((integer & 0xf) << 8)))
>> +/* RGB2YUV */
>> +void ipipe_set_rgb2ycbcr_regs(struct prev_rgb2yuv *yuv)
>> +{
>> +       u32 val;
>> +
>> +       /* S10Q8 */
>> +       ipipe_clock_enable();
>> +       val = IPIPE_S12Q8(yuv->coef_ry.decimal, yuv->coef_ry.integer);
>> +       regw_ip(val, YUV_MUL_RY);
>> +       val = IPIPE_S12Q8(yuv->coef_gy.decimal, yuv->coef_gy.integer);
>> +       regw_ip(val, YUV_MUL_GY);
>> +       val = IPIPE_S12Q8(yuv->coef_by.decimal, yuv->coef_by.integer);
>> +       regw_ip(val, YUV_MUL_BY);
>> +       val = IPIPE_S12Q8(yuv->coef_rcb.decimal, yuv->coef_rcb.integer);
>> +       regw_ip(val, YUV_MUL_RCB);
>> +       val = IPIPE_S12Q8(yuv->coef_gcb.decimal, yuv->coef_gcb.integer);
>> +       regw_ip(val, YUV_MUL_GCB);
>> +       val = IPIPE_S12Q8(yuv->coef_bcb.decimal, yuv->coef_bcb.integer);
>> +       regw_ip(val, YUV_MUL_BCB);
>> +       val = IPIPE_S12Q8(yuv->coef_rcr.decimal, yuv->coef_rcr.integer);
>> +       regw_ip(val, YUV_MUL_RCR);
>> +       val = IPIPE_S12Q8(yuv->coef_gcr.decimal, yuv->coef_gcr.integer);
>> +       regw_ip(val, YUV_MUL_GCR);
>> +       val = IPIPE_S12Q8(yuv->coef_bcr.decimal, yuv->coef_bcr.integer);
>> +       regw_ip(val, YUV_MUL_BCR);
>> +       regw_ip(yuv->out_ofst_y & RGB2YCBCR_OFST_MASK, YUV_OFT_Y);
>> +       regw_ip(yuv->out_ofst_cb & RGB2YCBCR_OFST_MASK, YUV_OFT_CB);
>> +       regw_ip(yuv->out_ofst_cr & RGB2YCBCR_OFST_MASK, YUV_OFT_CR);
>> +}
>> +
>> +/* YUV 422 conversion */
>> +void ipipe_set_yuv422_conv_regs(struct prev_yuv422_conv *conv)
>> +{
>> +       u32 val;
>> +
>> +       ipipe_clock_enable();
>> +       /* Combine all the fields to make YUV_PHS register of IPIPE */
>> +       val = (conv->chrom_pos << 0) | (conv->en_chrom_lpf << 1);
>> +       regw_ip(val, YUV_PHS);
>> +}
>> +
>> +/* GBCE */
>> +void ipipe_set_gbce_regs(struct prev_gbce *gbce)
>> +{
>> +       unsigned int tbl_index;
>> +       unsigned int count;
>> +       u32 mask = GBCE_Y_VAL_MASK;
>> +       u32 val;
>> +
>> +       if (gbce->type == IPIPE_GBCE_GAIN_TBL)
>> +               mask = GBCE_GAIN_VAL_MASK;
>> +
>> +       ipipe_clock_enable();
>> +       regw_ip(gbce->en & 1, GBCE_EN);
>> +
>> +       if (!gbce->en)
>> +               return;
>> +
>> +       regw_ip(gbce->type, GBCE_TYP);
>> +
>> +       if (!gbce->table)
>> +               return;
>> +
>> +       /* set to 0 */
>> +       val = 0;
>> +
>> +       for (count = 0; count < MAX_SIZE_GBCE_LUT; count++) {
>> +               tbl_index = count >> 1;
>> +               tbl_index <<= 2;
>> +               /* Each table has 2 LUT entries, first in LS
>> +                 * and second in MS positions
>> +                 */
>> +               if (count % 2) {
>> +                       val |=
>> +                               (gbce->table[count] & mask) <<
>> +                               GBCE_ENTRY_SHIFT;
>> +                       w_ip_table(val, tbl_index + GBCE_TB_START_ADDR);
>
>
> You can clean this up by looping half the times, and replace the inside of
> the loop with this (or something close anyway):
>
> w_ip_table(((gbce->table[count + 1] & mask) << GBCE_ENTRY_SHIFT) |
>                 gbce->table[count] & mask), (count << 2) +
>                                         GBCE_TB_START_ADDR));
>
>
Ok.

>
>> +               } else {
>> +                       val = gbce->table[count] & mask;
>> +               }
>> +       }
>> +}
>> +
>> +/* Edge Enhancement */
>> +void ipipe_set_ee_regs(struct prev_yee *ee)
>> +{
>> +       unsigned int tbl_index;
>> +       unsigned int count;
>> +       u32 val;
>> +
>> +       ipipe_clock_enable();
>> +       regw_ip(ee->en, YEE_EN);
>> +
>> +       if (!ee->en)
>> +               return;
>> +
>> +       val = ee->en_halo_red & 1;
>> +       val |= ee->merge_meth << YEE_HALO_RED_EN_SHIFT;
>> +       regw_ip(val, YEE_TYP);
>> +       regw_ip(ee->hpf_shft, YEE_SHF);
>> +       regw_ip(ee->hpf_coef_00 & YEE_COEF_MASK, YEE_MUL_00);
>> +       regw_ip(ee->hpf_coef_01 & YEE_COEF_MASK, YEE_MUL_01);
>> +       regw_ip(ee->hpf_coef_02 & YEE_COEF_MASK, YEE_MUL_02);
>> +       regw_ip(ee->hpf_coef_10 & YEE_COEF_MASK, YEE_MUL_10);
>> +       regw_ip(ee->hpf_coef_11 & YEE_COEF_MASK, YEE_MUL_11);
>> +       regw_ip(ee->hpf_coef_12 & YEE_COEF_MASK, YEE_MUL_12);
>> +       regw_ip(ee->hpf_coef_20 & YEE_COEF_MASK, YEE_MUL_20);
>> +       regw_ip(ee->hpf_coef_21 & YEE_COEF_MASK, YEE_MUL_21);
>> +       regw_ip(ee->hpf_coef_22 & YEE_COEF_MASK, YEE_MUL_22);
>> +       regw_ip(ee->yee_thr & YEE_THR_MASK, YEE_THR);
>> +       regw_ip(ee->es_gain & YEE_ES_GAIN_MASK, YEE_E_GAN);
>> +       regw_ip(ee->es_thr1 & YEE_ES_THR1_MASK, YEE_E_THR1);
>> +       regw_ip(ee->es_thr2 & YEE_THR_MASK, YEE_E_THR2);
>> +       regw_ip(ee->es_gain_grad & YEE_THR_MASK, YEE_G_GAN);
>> +       regw_ip(ee->es_ofst_grad & YEE_THR_MASK, YEE_G_OFT);
>> +
>> +       if (ee->table == NULL)
>> +               return;
>> +
>> +       for (count = 0; count < MAX_SIZE_YEE_LUT; count++) {
>> +               tbl_index = count >> 1;
>> +               tbl_index <<= 2;
>> +               /* Each table has 2 LUT entries, first in LS
>> +                 * and second in MS positions
>> +                 */
>> +               if (count % 2) {
>> +                       val |= (ee->table[count] & YEE_ENTRY_MASK) <<
>> +                               YEE_ENTRY_SHIFT;
>> +                       w_ip_table(val, tbl_index + YEE_TB_START_ADDR);
>> +               } else {
>> +                       val = ee->table[count] & YEE_ENTRY_MASK;
>> +               }
>
>
> Same here.
>
Ok.

>
>> +       }
>> +}
>> +
>> +/* Chromatic Artifact Correction. CAR */
>> +static void ipipe_set_mf(void)
>> +{
>> +       /* typ to dynamic switch */
>> +       regw_ip(IPIPE_CAR_DYN_SWITCH, CAR_TYP);
>> +       /* Set SW0 to maximum */
>> +       regw_ip(CAR_MF_THR, CAR_SW);
>> +}
>> +
>> +static void ipipe_set_gain_ctrl(struct prev_car *car)
>> +{
>> +       regw_ip(IPIPE_CAR_CHR_GAIN_CTRL, CAR_TYP);
>> +       regw_ip(car->hpf, CAR_HPF_TYP);
>> +       regw_ip(car->hpf_shft & CAR_HPF_SHIFT_MASK, CAR_HPF_SHF);
>> +       regw_ip(car->hpf_thr, CAR_HPF_THR);
>> +       regw_ip(car->gain1.gain, CAR_GN1_GAN);
>> +       regw_ip(car->gain1.shft & CAR_GAIN1_SHFT_MASK, CAR_GN1_SHF);
>> +       regw_ip(car->gain1.gain_min & CAR_GAIN_MIN_MASK, CAR_GN1_MIN);
>> +       regw_ip(car->gain2.gain, CAR_GN2_GAN);
>> +       regw_ip(car->gain2.shft & CAR_GAIN2_SHFT_MASK, CAR_GN2_SHF);
>> +       regw_ip(car->gain2.gain_min & CAR_GAIN_MIN_MASK, CAR_GN2_MIN);
>> +}
>> +
>> +void ipipe_set_car_regs(struct prev_car *car)
>> +{
>> +       u32 val;
>> +
>> +       ipipe_clock_enable();
>> +       regw_ip(car->en, CAR_EN);
>> +
>> +       if (!car->en)
>> +               return;
>> +
>> +       switch (car->meth) {
>> +       case IPIPE_CAR_MED_FLTR:
>> +               ipipe_set_mf();
>> +               break;
>> +       case IPIPE_CAR_CHR_GAIN_CTRL:
>> +               ipipe_set_gain_ctrl(car);
>> +               break;
>> +       default:
>> +               /* Dynamic switch between MF and Gain Ctrl. */
>> +               ipipe_set_mf();
>> +               ipipe_set_gain_ctrl(car);
>> +               /* Set the threshold for switching between
>> +                 * the two Here we overwrite the MF SW0 value
>> +                 */
>> +               regw_ip(IPIPE_CAR_DYN_SWITCH, CAR_TYP);
>> +               val = car->sw1;
>> +               val <<= CAR_SW1_SHIFT;
>> +               val |= car->sw0;
>> +               regw_ip(val, CAR_SW);
>> +       }
>> +}
>> +
>> +/* Chromatic Gain Suppression */
>> +void ipipe_set_cgs_regs(struct prev_cgs *cgs)
>> +{
>> +       ipipe_clock_enable();
>> +       regw_ip(cgs->en, CGS_EN);
>> +
>> +       if (!cgs->en)
>> +               return;
>> +
>> +       /* Set the bright side parameters */
>> +       regw_ip(cgs->h_thr, CGS_GN1_H_THR);
>> +       regw_ip(cgs->h_slope, CGS_GN1_H_GAN);
>> +       regw_ip(cgs->h_shft & CAR_SHIFT_MASK, CGS_GN1_H_SHF);
>> +       regw_ip(cgs->h_min, CGS_GN1_H_MIN);
>> +}
>> +
>> +void rsz_src_enable(int enable)
>> +{
>> +       regw_rsz(enable, RSZ_SRC_EN);
>> +}
>> +
>> +int rsz_enable(int rsz_id, int enable)
>> +{
>> +       if (rsz_id == RSZ_A) {
>> +               regw_rsz(enable, RSZ_EN_A);
>> +               /* We always enable RSZ_A. RSZ_B is enable upon request
>> from
>> +                * application. So enable RSZ_SRC_EN along with RSZ_A
>> +                */
>> +               regw_rsz(enable, RSZ_SRC_EN);
>> +       } else if (rsz_id == RSZ_B) {
>> +               regw_rsz(enable, RSZ_EN_B);
>> +       } else {
>> +               return -EINVAL;
>
>
> This should be BUG() or WARN(). It's a driver bug if this happens.
>
Ok.

>
>> +       }
>> +
>> +       return 0;
>> +}
>> diff --git a/drivers/media/platform/davinci/dm365_ipipe_hw.h
>> b/drivers/media/platform/davinci/dm365_ipipe_hw.h
>> new file mode 100644
>> index 0000000..7e92633
>> --- /dev/null
>> +++ b/drivers/media/platform/davinci/dm365_ipipe_hw.h
>> @@ -0,0 +1,538 @@
>> +/*
>> + * Copyright (C) 2012 Texas Instruments 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 version 2.
>> + *
>> + * 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
>> + *
>> + * Contributors:
>> + *      Manjunath Hadli <manjunath.hadli@ti.com>
>> + *      Prabhakar Lad <prabhakar.lad@ti.com>
>> + */
>> +
>> +#ifndef _DM365_IPIPE_HW_H
>> +#define _DM365_IPIPE_HW_H
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/io.h>
>> +
>> +#define IPIPE_IOBASE_VADDR             IO_ADDRESS(0x01c70800)
>> +#define RSZ_IOBASE_VADDR               IO_ADDRESS(0x01c70400)
>> +#define IPIPE_INT_TABLE_IOBASE_VADDR   IO_ADDRESS(0x01c70000)
>
>
> The above three look like something that should come through platform data.
>
>
>> +#define SET_LOW_ADD     0x0000ffff
>> +#define SET_HIGH_ADD    0xffff0000
>
>
> Address is often shortened as "addr" but seldom "add". This is because the
> obvious confusing with adding. Up to you.
>
I'll make it ADDR.

>
>> +/* Below are the internal tables */
>> +#define DPC_TB0_START_ADDR     0x8000
>> +#define DPC_TB1_START_ADDR     0x8400
>> +
>> +#define GAMMA_R_START_ADDR     0xa800
>> +#define GAMMA_G_START_ADDR     0xb000
>> +#define GAMMA_B_START_ADDR     0xb800
>> +
>> +/* RAM table addresses for edge enhancement correction*/
>> +#define YEE_TB_START_ADDR      0x8800
>> +
>> +/* RAM table address for GBC LUT */
>> +#define GBCE_TB_START_ADDR     0x9000
>> +
>> +/* RAM table for 3D NF LUT */
>> +#define D3L_TB0_START_ADDR     0x9800
>> +#define D3L_TB1_START_ADDR     0x9c00
>> +#define D3L_TB2_START_ADDR     0xa000
>> +#define D3L_TB3_START_ADDR     0xa400
>> +
>> +/* IPIPE Register Offsets from the base address */
>> +#define IPIPE_SRC_EN           0x0000
>> +#define IPIPE_SRC_MODE         0x0004
>> +#define IPIPE_SRC_FMT          0x0008
>> +#define IPIPE_SRC_COL          0x000c
>> +#define IPIPE_SRC_VPS          0x0010
>> +#define IPIPE_SRC_VSZ          0x0014
>> +#define IPIPE_SRC_HPS          0x0018
>> +#define IPIPE_SRC_HSZ          0x001c
>> +
>> +#define IPIPE_SEL_SBU          0x0020
>> +
>> +#define IPIPE_DMA_STA          0x0024
>> +#define IPIPE_GCK_MMR          0x0028
>> +#define IPIPE_GCK_PIX          0x002c
>> +#define IPIPE_RESERVED0                0x0030
>> +
>> +/* Defect Correction */
>> +#define DPC_LUT_EN             0x0034
>> +#define DPC_LUT_SEL            0x0038
>> +#define DPC_LUT_ADR            0x003c
>> +#define DPC_LUT_SIZ            0x0040
>> +#define DPC_OTF_EN             0x0044
>> +#define DPC_OTF_TYP            0x0048
>> +#define DPC_OTF_2D_THR_R       0x004c
>> +#define DPC_OTF_2D_THR_GR      0x0050
>> +#define DPC_OTF_2D_THR_GB      0x0054
>> +#define DPC_OTF_2D_THR_B       0x0058
>> +#define DPC_OTF_2C_THR_R       0x005c
>> +#define DPC_OTF_2C_THR_GR      0x0060
>> +#define DPC_OTF_2C_THR_GB      0x0064
>> +#define DPC_OTF_2C_THR_B       0x0068
>> +#define DPC_OTF_3_SHF          0x006c
>> +#define DPC_OTF_3D_THR         0x0070
>> +#define DPC_OTF_3D_SLP         0x0074
>> +#define DPC_OTF_3D_MIN         0x0078
>> +#define DPC_OTF_3D_MAX         0x007c
>> +#define DPC_OTF_3C_THR         0x0080
>> +#define DPC_OTF_3C_SLP         0x0084
>> +#define DPC_OTF_3C_MIN         0x0088
>> +#define DPC_OTF_3C_MAX         0x008c
>> +
>> +/* Lense Shading Correction */
>> +#define LSC_VOFT               0x90
>> +#define LSC_VA2                        0x94
>> +#define LSC_VA1                        0x98
>> +#define LSC_VS                 0x9c
>> +#define LSC_HOFT               0xa0
>> +#define LSC_HA2                        0xa4
>> +#define LSC_HA1                        0xa8
>> +#define LSC_HS                 0xac
>> +#define LSC_GAIN_R             0xb0
>> +#define LSC_GAIN_GR            0xb4
>> +#define LSC_GAIN_GB            0xb8
>> +#define LSC_GAIN_B             0xbc
>> +#define LSC_OFT_R              0xc0
>> +#define LSC_OFT_GR             0xc4
>> +#define LSC_OFT_GB             0xc8
>> +#define LSC_OFT_B              0xcc
>> +#define LSC_SHF                        0xd0
>> +#define LSC_MAX                        0xd4
>> +
>> +/* Noise Filter 1. Ofsets from start address given */
>> +#define D2F_1ST                        0xd8
>> +#define D2F_EN                 0x0
>> +#define D2F_TYP                        0x4
>> +#define D2F_THR                        0x8
>> +#define D2F_STR                        0x28
>> +#define D2F_SPR                        0x48
>> +#define D2F_EDG_MIN            0x68
>> +#define D2F_EDG_MAX            0x6c
>> +
>> +/* Noise Filter 2 */
>> +#define D2F_2ND                        0x148
>> +
>> +/* GIC */
>> +#define GIC_EN                 0x1b8
>> +#define GIC_TYP                        0x1bc
>> +#define GIC_GAN                        0x1c0
>> +#define GIC_NFGAN              0x1c4
>> +#define GIC_THR                        0x1c8
>> +#define GIC_SLP                        0x1cc
>> +
>> +/* White Balance */
>> +#define WB2_OFT_R              0x1d0
>> +#define WB2_OFT_GR             0x1d4
>> +#define WB2_OFT_GB             0x1d8
>> +#define WB2_OFT_B              0x1dc
>> +#define WB2_WGN_R              0x1e0
>> +#define WB2_WGN_GR             0x1e4
>> +#define WB2_WGN_GB             0x1e8
>> +#define WB2_WGN_B              0x1ec
>> +
>> +/* CFA interpolation */
>> +#define CFA_MODE               0x1f0
>> +#define CFA_2DIR_HPF_THR       0x1f4
>> +#define CFA_2DIR_HPF_SLP       0x1f8
>> +#define CFA_2DIR_MIX_THR       0x1fc
>> +#define CFA_2DIR_MIX_SLP       0x200
>> +#define CFA_2DIR_DIR_THR       0x204
>> +#define CFA_2DIR_DIR_SLP       0x208
>> +#define CFA_2DIR_NDWT          0x20c
>> +#define CFA_MONO_HUE_FRA       0x210
>> +#define CFA_MONO_EDG_THR       0x214
>> +#define CFA_MONO_THR_MIN       0x218
>> +#define CFA_MONO_THR_SLP       0x21c
>> +#define CFA_MONO_SLP_MIN       0x220
>> +#define CFA_MONO_SLP_SLP       0x224
>> +#define CFA_MONO_LPWT          0x228
>> +
>> +/* RGB to RGB conversiona - 1st */
>> +#define RGB1_MUL_BASE          0x22c
>> +/* Offsets from base */
>> +#define RGB_MUL_RR             0x0
>> +#define RGB_MUL_GR             0x4
>> +#define RGB_MUL_BR             0x8
>> +#define RGB_MUL_RG             0xc
>> +#define RGB_MUL_GG             0x10
>> +#define RGB_MUL_BG             0x14
>> +#define RGB_MUL_RB             0x18
>> +#define RGB_MUL_GB             0x1c
>> +#define RGB_MUL_BB             0x20
>> +#define RGB_OFT_OR             0x24
>> +#define RGB_OFT_OG             0x28
>> +#define RGB_OFT_OB             0x2c
>> +
>> +/* Gamma */
>> +#define GMM_CFG                        0x25c
>> +
>> +/* RGB to RGB conversiona - 2nd */
>> +#define RGB2_MUL_BASE          0x260
>> +
>> +/* 3D LUT */
>> +#define D3LUT_EN               0x290
>> +
>> +/* RGB to YUV(YCbCr) conversion */
>> +#define YUV_ADJ                        0x294
>> +#define YUV_MUL_RY             0x298
>> +#define YUV_MUL_GY             0x29c
>> +#define YUV_MUL_BY             0x2a0
>> +#define YUV_MUL_RCB            0x2a4
>> +#define YUV_MUL_GCB            0x2a8
>> +#define YUV_MUL_BCB            0x2ac
>> +#define YUV_MUL_RCR            0x2b0
>> +#define YUV_MUL_GCR            0x2b4
>> +#define YUV_MUL_BCR            0x2b8
>> +#define YUV_OFT_Y              0x2bc
>> +#define YUV_OFT_CB             0x2c0
>> +#define YUV_OFT_CR             0x2c4
>> +#define YUV_PHS                        0x2c8
>> +
>> +/* Global Brightness and Contrast */
>> +#define GBCE_EN                        0x2cc
>> +#define GBCE_TYP               0x2d0
>> +
>> +/* Edge Enhancer */
>> +#define YEE_EN                 0x2d4
>> +#define YEE_TYP                        0x2d8
>> +#define YEE_SHF                        0x2dc
>> +#define YEE_MUL_00             0x2e0
>> +#define YEE_MUL_01             0x2e4
>> +#define YEE_MUL_02             0x2e8
>> +#define YEE_MUL_10             0x2ec
>> +#define YEE_MUL_11             0x2f0
>> +#define YEE_MUL_12             0x2f4
>> +#define YEE_MUL_20             0x2f8
>> +#define YEE_MUL_21             0x2fc
>> +#define YEE_MUL_22             0x300
>> +#define YEE_THR                        0x304
>> +#define YEE_E_GAN              0x308
>> +#define YEE_E_THR1             0x30c
>> +#define YEE_E_THR2             0x310
>> +#define YEE_G_GAN              0x314
>> +#define YEE_G_OFT              0x318
>> +
>> +/* Chroma Artifact Reduction */
>> +#define CAR_EN                 0x31c
>> +#define CAR_TYP                        0x320
>> +#define CAR_SW                 0x324
>> +#define CAR_HPF_TYP            0x328
>> +#define CAR_HPF_SHF            0x32c
>> +#define        CAR_HPF_THR             0x330
>> +#define CAR_GN1_GAN            0x334
>> +#define CAR_GN1_SHF            0x338
>> +#define CAR_GN1_MIN            0x33c
>> +#define CAR_GN2_GAN            0x340
>> +#define CAR_GN2_SHF            0x344
>> +#define CAR_GN2_MIN            0x348
>> +
>> +/* Chroma Gain Suppression */
>> +#define CGS_EN                 0x34c
>> +#define CGS_GN1_L_THR          0x350
>> +#define CGS_GN1_L_GAN          0x354
>> +#define CGS_GN1_L_SHF          0x358
>> +#define CGS_GN1_L_MIN          0x35c
>> +#define CGS_GN1_H_THR          0x360
>> +#define CGS_GN1_H_GAN          0x364
>> +#define CGS_GN1_H_SHF          0x368
>> +#define CGS_GN1_H_MIN          0x36c
>> +#define CGS_GN2_L_THR          0x370
>> +#define CGS_GN2_L_GAN          0x374
>> +#define CGS_GN2_L_SHF          0x378
>> +#define CGS_GN2_L_MIN          0x37c
>> +
>> +/* Resizer */
>> +#define RSZ_SRC_EN             0x0
>> +#define RSZ_SRC_MODE           0x4
>> +#define RSZ_SRC_FMT0           0x8
>> +#define RSZ_SRC_FMT1           0xc
>> +#define RSZ_SRC_VPS            0x10
>> +#define RSZ_SRC_VSZ            0x14
>> +#define RSZ_SRC_HPS            0x18
>> +#define RSZ_SRC_HSZ            0x1c
>> +#define RSZ_DMA_RZA            0x20
>> +#define RSZ_DMA_RZB            0x24
>> +#define RSZ_DMA_STA            0x28
>> +#define RSZ_GCK_MMR            0x2c
>> +#define RSZ_RESERVED0          0x30
>> +#define RSZ_GCK_SDR            0x34
>> +#define RSZ_IRQ_RZA            0x38
>> +#define RSZ_IRQ_RZB            0x3c
>> +#define RSZ_YUV_Y_MIN          0x40
>> +#define RSZ_YUV_Y_MAX          0x44
>> +#define RSZ_YUV_C_MIN          0x48
>> +#define RSZ_YUV_C_MAX          0x4c
>> +#define RSZ_YUV_PHS            0x50
>> +#define RSZ_SEQ                        0x54
>> +
>> +/* Resizer Rescale Parameters */
>> +#define RSZ_EN_A               0x58
>> +#define RSZ_EN_B               0xe8
>> +/* offset of the registers to be added with base register of
>> +   either RSZ0 or RSZ1
>> +*/
>> +#define RSZ_MODE               0x4
>> +#define RSZ_420                        0x8
>> +#define RSZ_I_VPS              0xc
>> +#define RSZ_I_HPS              0x10
>> +#define RSZ_O_VSZ              0x14
>> +#define RSZ_O_HSZ              0x18
>> +#define RSZ_V_PHS_Y            0x1c
>> +#define RSZ_V_PHS_C            0x20
>> +#define RSZ_V_DIF              0x24
>> +#define RSZ_V_TYP              0x28
>> +#define RSZ_V_LPF              0x2c
>> +#define RSZ_H_PHS              0x30
>> +#define RSZ_H_PHS_ADJ          0x34
>> +#define RSZ_H_DIF              0x38
>> +#define RSZ_H_TYP              0x3c
>> +#define RSZ_H_LPF              0x40
>> +#define RSZ_DWN_EN             0x44
>> +#define RSZ_DWN_AV             0x48
>> +
>> +/* Resizer RGB Conversion Parameters */
>> +#define RSZ_RGB_EN             0x4c
>> +#define RSZ_RGB_TYP            0x50
>> +#define RSZ_RGB_BLD            0x54
>> +
>> +/* Resizer External Memory Parameters */
>> +#define RSZ_SDR_Y_BAD_H                0x58
>> +#define RSZ_SDR_Y_BAD_L                0x5c
>> +#define RSZ_SDR_Y_SAD_H                0x60
>> +#define RSZ_SDR_Y_SAD_L                0x64
>> +#define RSZ_SDR_Y_OFT          0x68
>> +#define RSZ_SDR_Y_PTR_S                0x6c
>> +#define RSZ_SDR_Y_PTR_E                0x70
>> +#define RSZ_SDR_C_BAD_H                0x74
>> +#define RSZ_SDR_C_BAD_L                0x78
>> +#define RSZ_SDR_C_SAD_H                0x7c
>> +#define RSZ_SDR_C_SAD_L                0x80
>> +#define RSZ_SDR_C_OFT          0x84
>> +#define RSZ_SDR_C_PTR_S                0x88
>> +#define RSZ_SDR_C_PTR_E                0x8c
>> +
>> +/* Macro for resizer */
>> +#define IPIPE_RESIZER_A(i)     (RSZ_IOBASE_VADDR + RSZ_EN_A + i)
>> +#define IPIPE_RESIZER_B(i)     (RSZ_IOBASE_VADDR + RSZ_EN_B + i)
>> +
>> +#define RSZ_YUV_Y_MIN          0x40
>> +#define RSZ_YUV_Y_MAX          0x44
>> +#define RSZ_YUV_C_MIN          0x48
>> +#define RSZ_YUV_C_MAX          0x4c
>> +
>> +#define IPIPE_GCK_MMR_DEFAULT  1
>> +#define IPIPE_GCK_PIX_DEFAULT  0xe
>> +#define RSZ_GCK_MMR_DEFAULT    1
>> +#define RSZ_GCK_SDR_DEFAULT    1
>> +
>> +/* LUTDPC */
>> +#define LUTDPC_TBL_256_EN      0
>> +#define LUTDPC_INF_TBL_EN      1
>> +#define LUT_DPC_START_ADDR     0
>> +#define LUT_DPC_H_POS_MASK     0x1fff
>> +#define LUT_DPC_V_POS_MASK     0x1fff
>> +#define LUT_DPC_V_POS_SHIFT    13
>> +#define LUT_DPC_CORR_METH_SHIFT        26
>> +#define LUT_DPC_MAX_SIZE       256
>> +#define LUT_DPC_SIZE_MASK      0x3ff
>> +
>> +/* OTFDPC */
>> +#define OTFDPC_DPC2_THR_MASK   0xfff
>> +#define OTF_DET_METHOD_SHIFT   1
>> +#define OTF_DPC3_0_SHF_MASK    3
>> +#define OTF_DPC3_0_THR_SHIFT   6
>> +#define OTF_DPC3_0_THR_MASK    0x3f
>> +#define OTF_DPC3_0_SLP_MASK    0x3f
>> +#define OTF_DPC3_0_DET_MASK    0xfff
>> +#define OTF_DPC3_0_CORR_MASK   0xfff
>> +
>> +/* NF (D2F) */
>> +#define D2F_SPR_VAL_MASK               0x1f
>> +#define D2F_SPR_VAL_SHIFT              0
>> +#define D2F_SHFT_VAL_MASK              3
>> +#define D2F_SHFT_VAL_SHIFT             5
>> +#define D2F_SAMPLE_METH_SHIFT          7
>> +#define D2F_APPLY_LSC_GAIN_SHIFT       8
>> +#define D2F_USE_SPR_REG_VAL            0
>> +#define D2F_STR_VAL_MASK               0x1f
>> +#define D2F_THR_VAL_MASK               0x3ff
>> +#define D2F_EDGE_DET_THR_MASK          0x7ff
>> +
>> +/* Green Imbalance Correction */
>> +#define GIC_TYP_SHIFT                  0
>> +#define GIC_THR_SEL_SHIFT              1
>> +#define        GIC_APPLY_LSC_GAIN_SHIFT        2
>> +#define GIC_GAIN_MASK                  0xff
>> +#define GIC_THR_MASK                   0xfff
>> +#define GIC_SLOPE_MASK                 0xfff
>> +#define GIC_NFGAN_INT_MASK             7
>> +#define GIC_NFGAN_DECI_MASK            0x1f
>> +
>> +/* WB */
>> +#define WB_OFFSET_MASK                 0xfff
>> +#define WB_GAIN_INT_MASK               0xf
>> +#define WB_GAIN_DECI_MASK              0x1ff
>> +
>> +/* CFA */
>> +#define CFA_HPF_THR_2DIR_MASK          0x1fff
>> +#define CFA_HPF_SLOPE_2DIR_MASK                0x3ff
>> +#define CFA_HPF_MIX_THR_2DIR_MASK      0x1fff
>> +#define CFA_HPF_MIX_SLP_2DIR_MASK      0x3ff
>> +#define CFA_DIR_THR_2DIR_MASK          0x3ff
>> +#define CFA_DIR_SLP_2DIR_MASK          0x7f
>> +#define CFA_ND_WT_2DIR_MASK            0x3f
>> +#define CFA_DAA_HUE_FRA_MASK           0x3f
>> +#define CFA_DAA_EDG_THR_MASK           0xff
>> +#define CFA_DAA_THR_MIN_MASK           0x3ff
>> +#define CFA_DAA_THR_SLP_MASK           0x3ff
>> +#define CFA_DAA_SLP_MIN_MASK           0x3ff
>> +#define CFA_DAA_SLP_SLP_MASK           0x3ff
>> +#define CFA_DAA_LP_WT_MASK             0x3f
>> +
>> +/* RGB2RGB */
>> +#define RGB2RGB_1_OFST_MASK            0x1fff
>> +#define RGB2RGB_1_GAIN_INT_MASK                0xf
>> +#define RGB2RGB_GAIN_DECI_MASK         0xff
>> +#define RGB2RGB_2_OFST_MASK            0x7ff
>> +#define RGB2RGB_2_GAIN_INT_MASK                0x7
>> +
>> +/* Gamma */
>> +#define GAMMA_BYPR_SHIFT               0
>> +#define GAMMA_BYPG_SHIFT               1
>> +#define GAMMA_BYPB_SHIFT               2
>> +#define GAMMA_TBL_SEL_SHIFT            4
>> +#define GAMMA_TBL_SIZE_SHIFT           5
>> +#define GAMMA_MASK                     0x3ff
>> +#define GAMMA_SHIFT                    10
>> +
>> +/* 3D LUT */
>> +#define D3_LUT_ENTRY_MASK              0x3ff
>> +#define D3_LUT_ENTRY_R_SHIFT           20
>> +#define D3_LUT_ENTRY_G_SHIFT           10
>> +#define D3_LUT_ENTRY_B_SHIFT           0
>> +
>> +/* Lumina adj */
>> +#define        LUM_ADJ_CONTR_SHIFT             0
>> +#define        LUM_ADJ_BRIGHT_SHIFT            8
>> +
>> +/* RGB2YCbCr */
>> +#define RGB2YCBCR_OFST_MASK            0x7ff
>> +#define RGB2YCBCR_COEF_INT_MASK                0xf
>> +#define RGB2YCBCR_COEF_DECI_MASK       0xff
>> +
>> +/* GBCE */
>> +#define GBCE_Y_VAL_MASK                        0xff
>> +#define GBCE_GAIN_VAL_MASK             0x3ff
>> +#define GBCE_ENTRY_SHIFT               10
>> +
>> +/* Edge Enhancements */
>> +#define YEE_HALO_RED_EN_SHIFT          1
>> +#define YEE_HPF_SHIFT_MASK             0xf
>> +#define YEE_COEF_MASK                  0x3ff
>> +#define YEE_THR_MASK                   0x3f
>> +#define YEE_ES_GAIN_MASK               0xfff
>> +#define YEE_ES_THR1_MASK               0xfff
>> +#define YEE_ENTRY_SHIFT                        9
>> +#define YEE_ENTRY_MASK                 0x1ff
>> +
>> +/* CAR */
>> +#define CAR_MF_THR                     0xff
>> +#define CAR_SW1_SHIFT                  8
>> +#define CAR_GAIN1_SHFT_MASK            7
>> +#define CAR_GAIN_MIN_MASK              0x1ff
>> +#define CAR_GAIN2_SHFT_MASK            0xf
>> +#define CAR_HPF_SHIFT_MASK             3
>> +
>> +/* CGS */
>> +#define CAR_SHIFT_MASK                 3
>> +
>> +/* Resizer */
>> +#define RSZ_BYPASS_SHIFT               1
>> +#define RSZ_SRC_IMG_FMT_SHIFT          1
>> +#define RSZ_SRC_Y_C_SEL_SHIFT          2
>> +#define IPIPE_RSZ_VPS_MASK             0xffff
>> +#define IPIPE_RSZ_HPS_MASK             0xffff
>> +#define IPIPE_RSZ_VSZ_MASK             0x1fff
>> +#define IPIPE_RSZ_HSZ_MASK             0x1fff
>> +#define RSZ_HPS_MASK                   0x1fff
>> +#define RSZ_VPS_MASK                   0x1fff
>> +#define RSZ_O_HSZ_MASK                 0x1fff
>> +#define RSZ_O_VSZ_MASK                 0x1fff
>> +#define RSZ_V_PHS_MASK                 0x3fff
>> +#define RSZ_V_DIF_MASK                 0x3fff
>> +
>> +#define RSZA_H_FLIP_SHIFT              0
>> +#define RSZA_V_FLIP_SHIFT              1
>> +#define RSZB_H_FLIP_SHIFT              2
>> +#define RSZB_V_FLIP_SHIFT              3
>> +#define RSZ_A                          0
>> +#define RSZ_B                          1
>> +#define RSZ_CEN_SHIFT                  1
>> +#define RSZ_YEN_SHIFT                  0
>> +#define RSZ_TYP_Y_SHIFT                        0
>> +#define RSZ_TYP_C_SHIFT                        1
>> +#define RSZ_LPF_INT_MASK               0x3f
>> +#define RSZ_LPF_INT_MASK               0x3f
>> +#define RSZ_LPF_INT_C_SHIFT            6
>> +#define RSZ_H_PHS_MASK                 0x3fff
>> +#define RSZ_H_DIF_MASK                 0x3fff
>> +#define RSZ_DIFF_DOWN_THR              256
>> +#define RSZ_DWN_SCALE_AV_SZ_V_SHIFT    3
>> +#define RSZ_DWN_SCALE_AV_SZ_MASK       7
>> +#define RSZ_RGB_MSK1_SHIFT             2
>> +#define RSZ_RGB_MSK0_SHIFT             1
>> +#define RSZ_RGB_TYP_SHIFT              0
>> +#define RSZ_RGB_ALPHA_MASK             0xff
>> +
>> +static inline u32 regr_ip(u32 offset)
>> +{
>> +       return readl(IPIPE_IOBASE_VADDR + offset);
>> +}
>> +
>> +static inline u32 regw_ip(u32 val, u32 offset)
>> +{
>> +       writel(val, IPIPE_IOBASE_VADDR + offset);
>> +
>> +       return val;
>
>
> Is it useful to return the written value? It's the same as the first
> argument in any case. All I can think of is a funny way of assigning that
> value somewhere, but that might not look as good as just doing the
> assignment without this function.
>
>
I'll make it void.

Regards,
--Prabhakar Lad

>> +}
>> +
>> +static inline u32 r_ip_table(u32 offset)
>> +{
>> +       return readl(IPIPE_INT_TABLE_IOBASE_VADDR + offset);
>> +}
>> +
>> +static inline u32 w_ip_table(u32 val, u32 offset)
>> +{
>> +       writel(val, IPIPE_INT_TABLE_IOBASE_VADDR + offset);
>> +
>> +       return val;
>> +}
>> +
>> +static inline u32 regr_rsz(u32 offset)
>> +{
>> +       return readl(RSZ_IOBASE_VADDR + offset);
>> +}
>> +
>> +static inline u32 regw_rsz(u32 val, u32 offset)
>> +{
>> +       writel(val, RSZ_IOBASE_VADDR + offset);
>> +
>> +       return val;
>> +}
>> +
>> +#endif  /* End of #ifdef _DM365_IPIPE_HW_H */
>>
>
> Kind regards,
>
> --
> Sakari Ailus
> sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2012-09-24  4:59 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-14 12:46 [PATCH 00/14] Media Controller capture driver for DM365 Prabhakar Lad
2012-09-14 12:46 ` [PATCH 01/14] davinci: vpfe: add dm3xx IPIPEIF hardware support module Prabhakar Lad
2012-09-19 22:01   ` Laurent Pinchart
2012-09-22  5:08     ` Prabhakar Lad
2012-09-14 12:46 ` [PATCH 02/14] davinci: vpfe: add IPIPE hardware layer support Prabhakar Lad
2012-09-23 14:36   ` Sakari Ailus
2012-09-24  4:59     ` Prabhakar Lad
2012-09-14 12:46 ` [PATCH 03/14] davinci: vpfe: add IPIPE support for media controller driver Prabhakar Lad
2012-09-14 12:46 ` [PATCH 04/14] davinci: vpfe: add support for CCDC hardware for dm365 Prabhakar Lad
2012-09-14 12:46 ` [PATCH 05/14] davinci: vpfe: add ccdc driver with media controller interface Prabhakar Lad
2012-09-14 12:46 ` [PATCH 06/14] davinci: vpfe: add v4l2 video driver support Prabhakar Lad
2012-09-14 13:30   ` Hans Verkuil
2012-09-22  5:03     ` Prabhakar Lad
2012-09-14 12:46 ` [PATCH 07/14] davinci: vpfe: v4l2 capture driver with media interface Prabhakar Lad
2012-09-14 12:46 ` [PATCH 08/14] davinci: vpfe: previewer driver based on v4l2 media controller framework Prabhakar Lad
2012-09-14 12:46 ` [PATCH 09/14] davinci: vpfe: resizer driver based on media framework Prabhakar Lad
2012-09-14 12:46 ` [PATCH 10/14] dm365: vpss: setup ISP registers Prabhakar Lad
2012-09-14 12:46 ` [PATCH 11/14] dm365: vpss: set vpss clk ctrl Prabhakar Lad
2012-09-14 12:46 ` [PATCH 12/14] dm365: vpss: add vpss helper functions to be used in the main driver for setting hardware parameters Prabhakar Lad
2012-09-14 12:46 ` [PATCH 13/14] davinci: vpfe: build infrastructure for dm365 Prabhakar Lad
2012-09-14 12:46 ` [PATCH 14/14] [media] davinci: vpfe: Add documentation Prabhakar Lad
2012-09-23 15:16 ` [PATCH 00/14] Media Controller capture driver for DM365 Sakari Ailus
2012-09-24  4:49   ` Prabhakar Lad

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).